除了自动创建的网络,还可以根据业务需要创建自定义网络。Docker提供三种自定义网络驱动: bridge
、 overlay
和 macvlan
, overlay
和 macvlan
用于创建跨主机的网络。
注:建议使用自定义的网络来控制哪些容器可以相互通信,可以自动DNS解析容器名称到IP地址
自定义创建bridge网络
测试通过 bridge 驱动创建类似于默认的 bridge 网络(自定义网桥中会自己分配ip地址和网关地址)
- 创建自定义网桥 ```shell [root@centos-01 ~]# docker network create —driver bridge my-net c62a2e3d6ad5dece71a470cde488ad9c41c24fac9380689f43905ffbd70d4389
[root@centos-01 ~]# brctl show
bridge name bridge id STP enabled interfaces
br-c62a2e3d6ad5 8000.0242ae4b8680 no
docker0 8000.0242cbf135ea no
[root@centos-01 ~]# docker network ls NETWORK ID NAME DRIVER SCOPE f6524186651f bridge bridge local ed7ffc7437dd host host local c62a2e3d6ad5 my-net bridge local fa66bc1a17f4 none null local
看到新增网桥`br-c62a2e3d6ad5`, `c62a2e3d6ad5` 是新建网桥 `my-net` 的短id,`docker network inspect` 看下 `my-net` 的配置信息
```bash
[root@centos-01 ~]# docker network inspect my-net
[
{
"Name": "my-net",
"Id": "c62a2e3d6ad5dece71a470cde488ad9c41c24fac9380689f43905ffbd70d4389",
"Created": "2021-06-18T11:16:55.17530733+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.19.0.0/16",
"Gateway": "172.19.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
这里 172.19.0.0/16
是 Docker
自动分配的IP网段,网关为 172.19.0.1
,在 my-net
对应的网桥br-c62a2e3d6ad5
上
注:如果想要指定IP网段。只需在创建网段时指定
--subnet
和-gateway
参数即可,命令如下:
docker network create --driver bridge --subnet 172.22.16.0/24 --gateway 172.22.16.1 my-net
容器要使用新的网络,需要在启动时通过 --network
指定
[root@centos-01 ~]# docker run -d --network=my-net --name nginx nginx
2104ba150f62d9ea552d09b05ccb0b376db10ce054b50908d16361a639826b84
查看容器配置
容器分配到的IP为 172.19.0.2
到目前为止,这里的IP是docker自动从 subnet
中分配的,如果想要指定一个静态IP可以通过 --ip
指定
这里有个问题需要注意:
[root@centos-01 ~]# docker run -d --network=my-net --ip 172.19.0.110 --name nginx nginx
5506e7ca82c8252727d8e7e4ae2c25ae1e3e5276fcf031112a17702ac4194e77
docker: Error response from daemon: user specified IP address is supported only when connecting to networks with user configured subnets.
Docker中只有使用 --subnet
创建的网络才能指定静态IP。上面也有提到这点,因此在使用 docker-compose
或者 docker run
命令创建容器时,如果需要指定可以使用 :
–subnet
指定IP
段–gateway
指定网关-
同网桥下的容器通信
nginx1:
[root@centos-01 ~]# docker run -d --name nginx1 --network=my-net nginx
96a448f4c29fef3038abdd91410d7f9264ef3620cb1a80974bcb63694e61953c
[root@centos-01 ~]# docker exec -it nginx1 /bin/bash
root@96a448f4c29f:/# ping 172.19.0.3
PING 172.19.0.3 (172.19.0.3) 56(84) bytes of data.
64 bytes from 172.19.0.3: icmp_seq=1 ttl=64 time=0.175 ms
64 bytes from 172.19.0.3: icmp_seq=2 ttl=64 time=0.052 ms
64 bytes from 172.19.0.3: icmp_seq=3 ttl=64 time=0.044 ms
nginx2:
[root@centos-01 ~]# docker run -d --name nginx2 --network=my-net nginx
8d47f51c8138e0ef935f3e8a7447c16a655ce21f18e87a0af0bc6e5ea2daaa21
[root@centos-01 ~]# docker exec -it nginx2 /bin/bash
root@8d47f51c8138:/# ping 172.19.0.2
PING 172.19.0.2 (172.19.0.2) 56(84) bytes of data.
64 bytes from 172.19.0.2: icmp_seq=1 ttl=64 time=0.043 ms
64 bytes from 172.19.0.2: icmp_seq=2 ttl=64 time=0.064 ms
64 bytes from 172.19.0.2: icmp_seq=3 ttl=64 time=0.049 ms
容器跨网桥通信
这里有个问题是
my-net
与默认的bridge
网络是否可以通信,正常来说两个网络属于不同的网桥应该不能通信,测试一下: ```bash [root@centos-01 ~]# docker ps -a 1CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8d47f51c8138 nginx “/docker-entrypoint.…” 32 minutes ago Up 32 minutes 80/tcp nginx2 96a448f4c29f nginx “/docker-entrypoint.…” 32 minutes ago Up 32 minutes 80/tcp nginx1
[root@centos-01 ~]# docker run -d —name nginx3 nginx 220cc3010771f7a3b0c778d4d5668baa860e969e8d5a6cde830290b31dad89fd
[root@centos-01 ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 220cc3010771 nginx “/docker-entrypoint.…” 3 seconds ago Up 2 seconds 80/tcp nginx3 8d47f51c8138 nginx “/docker-entrypoint.…” 32 minutes ago Up 32 minutes 80/tcp nginx2 96a448f4c29f nginx “/docker-entrypoint.…” 32 minutes ago Up 32 minutes 80/tcp nginx1
[root@centos-01 ~]# brctl show bridge name bridge id STP enabled interfaces br-c62a2e3d6ad5 8000.0242ae4b8680 no veth0a1e1ba veth1069d0c docker0 8000.0242cbf135ea no veth3147348
[root@centos-01 ~]# docker inspect nginx3
![image.png](https://cdn.nlark.com/yuque/0/2021/png/21738459/1623995046046-c86a1d3d-6278-4e94-84c5-0aff61970c17.png#align=left&display=inline&height=402&id=mcBIW&margin=%5Bobject%20Object%5D&name=image.png&originHeight=402&originWidth=1155&size=42319&status=done&style=shadow&width=1155)<br />新建容器 `nginx3` 但不指定网桥所以会使用默认的 `bridge` 网络,结果显示 `br-c62a2e3d6ad5` 上绑定了两个虚拟网卡 `veth0a1e1ba` 和 `veth1069d0c` 对应 `nginx1` 和 `nginx2` , `docker0` 上绑定了 `veth3147348` ,对应 `ngnix3` ,分配的IP地址是 `172.17.0.2` 也可以看出来不在一个网段。
```bash
[root@centos-01 ~]# docker exec -it nginx1 /bin/bash
root@96a448f4c29f:/# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
结果可知:不同网段的确是 **ping**
不通的
思考:“不同的网络如果加上路由是否可以通信”,如果host上对每个网络都有一条路由,同时操作系统上打开了 ip forwarding
,host就成了一个路由器,挂接在不同网桥上的网络就能够相互通信。试试看
查看路由表
[root@centos-01 ~]# ip r
default via 192.168.126.67 dev ens33 proto static metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
172.19.0.0/16 dev br-c62a2e3d6ad5 proto kernel scope link src 172.19.0.1
192.168.126.0/24 dev ens33 proto kernel scope link src 192.168.126.143 metric 100
172.17.0.0/16
和172..16.0/24两个网络的路由都定义好了。再看看 ip forwarding
:
[root@centos-01 ~]# sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
这里看到路由转发也是开启的,条件都满足的情况下为什么还不行呢,再看看 iptables
这里看到原因是因为: **iptables**
**DROP**
掉了网桥 **dockero**
与 **br-c62a2e3d6ad5**
之间双向的流量。从规则命名 **DOCKER-ISOLATION**
可知 **docker**
在设计上就是要隔离不同的 **netwrok**
,这里可以通过使用 **docker network connect**
命令添加一块网卡来实现不同网桥容器通信
[root@centos-01 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
220cc3010771 nginx "/docker-entrypoint.…" 34 hours ago Up 34 hours 80/tcp nginx3
8d47f51c8138 nginx "/docker-entrypoint.…" 34 hours ago Up 34 hours 80/tcp nginx2
96a448f4c29f nginx "/docker-entrypoint.…" 34 hours ago Up 34 hours 80/tcp nginx1
[root@centos-01 ~]# docker network connect my-net 220cc3010771 #将nginx3连接到my-net中
[root@centos-01 ~]# docker exec -it nginx1 /bin/bash
root@96a448f4c29f:/# ping 172.19.0.4
PING 172.19.0.4 (172.19.0.4) 56(84) bytes of data.
64 bytes from 172.19.0.4: icmp_seq=1 ttl=64 time=0.130 ms
64 bytes from 172.19.0.4: icmp_seq=2 ttl=64 time=0.046 ms
64 bytes from 172.19.0.4: icmp_seq=3 ttl=64 time=0.060 ms
外部访问容器
容器访问外网是通过 iptables
的 SNAT
实现的,docker容器在启动的时候,如果不指定端口映射参数,容器外部无法通过网络访问容器内的网络应用和服务。需要设置端口映射,也可以使用 Dockerfile
文件中的 EXPOSE
指令来配置。
端口映射使用 **-p**
、 **-P**
来实现
-p
容器内部端口绑定到指定的主机端口-P
容器内部端口随机映射到主机的高端口IP:HOSTPORT:CONTAINERPORT
指定ip:指定宿主机port:指定容器port
: 适用于映射到指定地址的指定端口
[root@wangpengliang ~]# docker run -it -d -p 127.0.0.1:5000:5000 --name redis redis #将容器的5000端口映射到指定地址127.0.0.1的5000端口上
c2179a906b05e210c42eb6561cf76285f3391e703d5db249a154e06d4d025f28
[root@wangpengliang ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4927cb5dfe67 redis "docker-entrypoint.s…" 49 seconds ago Up 48 seconds 127.0.0.1:5000->5000/tcp, 6379/tcp redis
IP::CONTAINERPORT
指定ip、未指定宿主机port(随机)、指定容器port
:适用于映射到指定地址的任意端口
[root@wangpengliang ~]# docker run -it -d -p 127.0.0.1::5000 --name redis redis #将容器的5000端口映射到指定地址127.0.0.1的任意端口上
c19e6b8f249db67b2f50455d35159f718a1d68e6efd02c106f0148bae14ba496
[root@wangpengliang ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c19e6b8f249d redis "docker-entrypoint.s…" 2 seconds ago Up 2 seconds 6379/tcp, 127.0.0.1:49153->5000/tcp redis
HOSTPORT:CONTAINERPORT
未指定ip、指定宿主机port、指定容器port
:适用于将容器指定端口指定映射到宿主机的一个端口上(映射所有接口地址)
[root@wangpengliang ~]# docker run -it -d -p 80:8000 --name redis redis #将容器的8000端口映射到宿主机的80端口上
3ad63ffd90665413e644cd16f2eb7d404fcb14bb509eee05f67e0db8f1c067a4
[root@wangpengliang ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3ad63ffd9066 redis "docker-entrypoint.s…" 5 seconds ago Up 4 seconds 6379/tcp, 0.0.0.0:80->8000/tcp, :::80->8000/tcp redis
绑定 UDP 端口
默认情况下
-p
和-P
绑定的都是tcp
协议端口,如果要绑定udp
协议端口,只能使用-p
参数,且在最后添加/udp
字符串
[root@wangpengliang ~]# docker run -d -p 127.0.0.1:5553:5000/udp jcdemo/flaskapp
6aa30aa070a6e77f0d3f8653df69c654edf6e8bb68cea475aefbc68f6f7f9572
绑定多个端口
多次使用
-p
参数可以映射多个端口
[root@wangpengliang ~]# docker run -d -p 5552:5000 -p 5551:5001 jcdemo/flaskapp
fa116ae4f5c19d82d9d4f40560c3219c85540a21d88f7fa999b60382ab57524a
查看映射端口配置
docker port container_ID #容器ID
#结果输出
80/tcp -> 0.0.0.0:800
跨主机网络解决方案
TODO