1. 常见的容器之间通信方式
1.1. 同一个宿主机内部
- 通过虚拟交换机来实现容器间通信
- 如果容器在不同的虚拟交换机上,则可以通过交换机直连或者路由转发的方式通信
1.2. 跨宿主机的容器通信
- 通过桥接宿主机网卡的方式通信
- NAT转发(docker默认的方式)
- 叠加式网络(Overlay network)
2. Docker网络模型
- 封闭式容器(none)
仅有一个lo口的容器,一般用于内部的数据处理等任务,而不需要与外界进行通信的容器。
- 桥接式容器(Bridge,default)
每个容器在创建之初就分配了私有地址和lo口,其中私有地址接在docker的虚拟桥上,可以通过NAT方式与外界通信,这是默认的网络模型。
- 联盟式容器(Joined)
多个容器共用同一个Net名称空间,而其它名称空间是私有的,这些容器内部可以通过lo口直接通信,而不需要走docker桥。
- 开放式容器(Open)
开放式容器是联盟式容器的一种特例,此容器共享的是宿主机的网卡
3. 案例
3.1 Docker 容器网络信息查看
[root@centos-82 ~]# ip link show
## veth3c68900@if4 一半在docker0上,一半在容器中。master接口是 docker0
......
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
link/ether 02:42:86:d7:21:83 brd ff:ff:ff:ff:ff:ff
5: veth3c68900@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
link/ether 26:62:60:c8:23:f6 brd ff:ff:ff:ff:ff:ff link-netnsid 0
[root@centos-82 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
19eb0f999458 bridge bridge local ## 默认方式,桥接
b12765b5a394 host host local ## 共享宿主机网络
67019894af82 none null local ## 封闭式容器,仅lo口
[root@centos-82 ~]# docker network inspect bridge
"Name": "bridge",
......
"Driver": "default",
......
"Subnet": "172.17.0.0/16", ## 子网地址池
"Gateway": "172.17.0.1" ## 网关
......
"Containers": { ## 包含的容器信息
"2efec0177ae1ed1d6f3705f6357f7c99157f2a74daa2082108c87a69a6b45e8c": {
"Name": "web01",
"EndpointID": "ca991021b1d70462551127cc34753ba1f745ab9c592ac3be56903693759c9132",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
......
"com.docker.network.bridge.name": "docker0", ## 网络名称
"com.docker.network.driver.mtu": "1500" ## MTU
......
3.2. 模拟网络名称空间
[root@centos-82 ~]# ip netns add ns1 ## 创建网络名称空间
[root@centos-82 ~]# ip netns add ns2
[root@centos-82 ~]# ip netns list ## 查看当前网络名称空间
ns2
ns1
[root@centos-82 ~]# ip netns exec ns1 ip a ## 在指定的网络名称空间中执行命令
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
[root@centos-82 ~]# ip link add name veth1.1 type veth peer name veth1.2 ## 创建一对虚拟网卡
[root@centos-82 ~]# ip link show ## veth1.1和veth1.2是一对网卡
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 00:0c:29:88:a8:40 brd ff:ff:ff:ff:ff:ff
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether 02:42:5d:21:bc:03 brd ff:ff:ff:ff:ff:ff
4: veth1.2@veth1.1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether a6:b3:2f:16:12:46 brd ff:ff:ff:ff:ff:ff
5: veth1.1@veth1.2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether de:90:83:56:79:1a brd ff:ff:ff:ff:ff:ff
[root@centos-82 ~]# ip link set dev veth1.2 netns ns1 ## 将其中一个网卡一半接入网络名称空间
[root@centos-82 ~]# ip netns exec ns1 ip a ## 接入的网卡处于未激活状态
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
4: veth1.2@if5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether a6:b3:2f:16:12:46 brd ff:ff:ff:ff:ff:ff link-netnsid 0
[root@centos-82 ~]# ip netns exec ns1 ip link set dev veth1.2 name eth0 ## 对网卡设备改名
[root@centos-82 ~]# ip netns exec ns1 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
4: eth0@if5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether a6:b3:2f:16:12:46 brd ff:ff:ff:ff:ff:ff link-netnsid 0
[root@centos-82 ~]# ip netns exec ns1 ifconfig -a
eth0: flags=4098<BROADCAST,MULTICAST> mtu 1500
ether a6:b3:2f:16:12:46 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=8<LOOPBACK> mtu 65536
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@centos-82 ~]# ifconfig veth1.1 10.154.2.2 ## 激活宿主机的网卡
[root@centos-82 ~]# ip netns exec ns1 ifconfig eth0 10.154.2.3 ## 激活名称空间中的网卡
[root@centos-82 ~]# ip netns exec ns1 ifconfig -a
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.154.2.3 netmask 255.0.0.0 broadcast 10.255.255.255
inet6 fe80::a4b3:2fff:fe16:1246 prefixlen 64 scopeid 0x20<link>
ether a6:b3:2f:16:12:46 txqueuelen 1000 (Ethernet)
RX packets 6 bytes 508 (508.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 6 bytes 508 (508.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=8<LOOPBACK> mtu 65536
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@centos-82 ~]# ping -c 2 -w 1 10.154.2.3 ## 宿主机与网络名称空间中的网卡通信
PING 10.154.2.3 (10.154.2.3) 56(84) bytes of data.
64 bytes from 10.154.2.3: icmp_seq=1 ttl=64 time=0.046 ms
64 bytes from 10.154.2.3: icmp_seq=2 ttl=64 time=0.045 ms
[root@centos-82 ~]# ip link set dev veth1.1 netns ns2 ## 将宿主机中的另一半虚拟网卡移动到另一个网络名称空间中
[root@centos-82 ~]# ip netns exec ns2 ifconfig -a
lo: flags=8<LOOPBACK> mtu 65536
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
veth1.1: flags=4098<BROADCAST,MULTICAST> mtu 1500
ether de:90:83:56:79:1a txqueuelen 1000 (Ethernet)
RX packets 12 bytes 928 (928.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 12 bytes 928 (928.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@centos-82 ~]# ip netns exec ns2 ip link set dev veth1.1 name eth0
[root@centos-82 ~]# ip netns exec ns2 ifconfig eth0 10.154.2.9 ## 激活网卡
[root@centos-82 ~]# ip netns exec ns2 ifconfig -a
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.154.2.9 netmask 255.0.0.0 broadcast 10.255.255.255
inet6 fe80::dc90:83ff:fe56:791a prefixlen 64 scopeid 0x20<link>
ether de:90:83:56:79:1a txqueuelen 1000 (Ethernet)
RX packets 12 bytes 928 (928.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 18 bytes 1436 (1.4 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=8<LOOPBACK> mtu 65536
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@centos-82 ~]# ip netns exec ns2 ping -c 1 -w 1 10.154.2.3 ## 两个名称空间实现通信
PING 10.154.2.3 (10.154.2.3) 56(84) bytes of data.
64 bytes from 10.154.2.3: icmp_seq=1 ttl=64 time=0.045 ms
3.3. 容器的网络配置
3.3.1. 容器创建时指定
[root@centos-82 ~]# docker run —name bx1 -it —rm busybox:latest ## 默认的主机名是ID
/ # hostname
d7e05d8b2fe6
[root@centos-82 ~]# docker run —name bx1 —hostname container-test-bx1 -it —rm busybox:latest ## 手动指定主机名
/ # hostname
container-test-bx1
/ # cat /etc/hosts ## 默认hosts文件配置
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 container-test-bx1
/ # cat /etc/resolv.conf ## 默认使用了宿主机的DNS服务器
# Generated by NetworkManager
nameserver 223.5.5.5
nameserver 114.114.114.114
[root@centos-82 ~]# docker run —name bx1 —hostname container-test-bx1 —dns 172.17.0.1 —dns 8.8.8.8 —add-host bbs.heyang.com:192.168.1.80 -it —rm busybox:latest
/ # cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
192.168.1.80 www.heyang.com
192.168.1.80 bbs.heyang.com
172.17.0.2 container-test-bx1
/ # cat /etc/resolv.conf
nameserver 172.17.0.1
nameserver 8.8.8.8
3.3.2. 修改初始化配置
- Docker 网络配置参数
[root@centos-82 ~]# ip a show docker0{ "bip": "192.168.1.5/24", # docker0桥的IP,定义这个IP后,其它非DNS的字段会自动计算 "fixed-cidr": "10.20.0.0/16", # IPv4 地址池 "fixed-cidr-v6": "2001:db8::/64", # IPv6 地址池 "mtu": 1500, # MTU 数据包分片大小 "default-gateway": "10.20.1.1", # 默认IPv4网关 "default-gateway-v6": "2001:db8:abcd::89", # 默认IPv6网关 "dns": ["10.20.1.1","20.20.1.3"] # 默认DNS地址 }
[root@centos-82 ~]# vim /etc/docker/daemon.json3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 ......
[root@centos-82 ~]# systemctl restart docker{ "registry-mirrors":["https://registry.docker-cn.com"], "bip":"10.154.50.1/24", "dns":["114.114.114.114","192.168.1.99"] }
[root@centos-82 ~]# ip a show docker0
[root@centos-82 ~]# docker container run —name bx1 —rm -it busybox:latest3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default inet 10.154.50.1/24 brd 10.154.50.255 scope global docker0 ......
/ # ifconfig eth0 Link encap:Ethernet HWaddr 02:42:0A:9A:32:02 inet addr:10.154.50.2 Bcast:10.154.50.255 Mask:255.255.255.0 ...... / # cat /etc/resolv.conf nameserver 114.114.114.114 nameserver 192.168.1.99
3.3.3. 添加新的网络设备
[root@centos-82 ~]# docker network ls
[root@centos-82 ~]# docker network create -d bridge —subnet “10.175.0.0/16” —gateway “10.175.0.1” mybr0NETWORK ID NAME DRIVER SCOPE f6fc3bdd3b71 bridge bridge local b12765b5a394 host host local 67019894af82 none null local
[root@centos-82 ~]# docker network ls3ad60ea3b43e8f1a432212f51958216cabcbab7b34679dab9af6e1139c96a0f6
[root@centos-82 ~]# ip addr showNETWORK ID NAME DRIVER SCOPE f6fc3bdd3b71 bridge bridge local b12765b5a394 host host local 3ad60ea3b43e mybr0 bridge local 67019894af82 none null local
[root@centos-82 ~]# docker container run —name bx1 —network mybr0 -it —rm busybox:latest...... 4: br-3ad60ea3b43e: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default link/ether 02:42:cd:97:32:bd brd ff:ff:ff:ff:ff:ff inet 10.175.0.1/16 brd 10.175.255.255 scope global br-3ad60ea3b43e valid_lft forever preferred_lft forever
/ # ip a ...... 5: eth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:0a:af:00:02 brd ff:ff:ff:ff:ff:ff inet 10.175.0.2/16 brd 10.175.255.255 scope global eth0 valid_lft forever preferred_lft forever
3.4. Docker 网络模型
3.4.1. None模型(仅lo)
[root@centos-82 ~]# docker container run —name bx1 —network none -it —rm busybox:latest ## none模式/ # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever
3.4.2. Bridge模型(docker0)
3.4.2.1. 指定Bridge模式
[root@centos-82 ~]# docker container run —name bx1 -it —rm busybox:latest ## 默认bridge模式
/ # ip a
.......
6: eth0@if7: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
[root@centos-82 ~]# docker container run —name bx1 —network bridge -it —rm busybox:latest
/ # ip a
......
8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
3.4.2.2. NAT 转发
- 宿主机所有地址中的随机端口
[root@centos-82 ~]# docker container run —name web -p 80 —rm nginx:latest
[root@centos-82 ~]# docker container port web ## 查看容器的端口映射
80/tcp -> 0.0.0.0:32768
[root@centos-82 ~]# netstat -lntp | grep docker ##监听在随机端口 32768
tcp6 0 0 :::32768 :::* LISTEN 3441/docker-proxy
[root@centos-82 ~]# docker container inspect web | grep -w IPAddress ## 当前IP
"IPAddress": "172.17.0.2",
[root@centos-82 ~]# iptables -t nat -nvL | grep 172.17.0.2 ## 自动创建DNAT规则
0 0 MASQUERADE tcp -- * * 172.17.0.2 172.17.0.2 tcp dpt:80
1 60 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:32768 to:172.17.0.2:80
[root@centos-82 ~]# curl -s -I 172.17.0.2 | grep ^HTTP ## 宿主机访问
HTTP/1.1 200 OK
[root@centos-50 ~]# curl -s -I 192.168.1.82:32768 | grep HTTP ## 外部网络访问
HTTP/1.1 200 OK
- 宿主机指定IP的随机端口
[root@centos-82 ~]# docker container run —name web -p 192.168.1.82::80 —rm nginx:latest
[root@centos-82 ~]# docker container port web
80/tcp -> 192.168.1.82:32768
- 宿主机指定IP的指定端口
[root@centos-82 ~]# docker container run —name web -p 192.168.1.82:80:80 —rm nginx:latest
[root@centos-82 ~]# docker container port web
80/tcp -> 192.168.1.82:80
[root@centos-50 ~]# curl -s -I 192.168.1.82 | grep HTTP ## 外界可以直接访问
HTTP/1.1 200 OK
- 宿主机所有地址中的指定端口
[root@centos-82 ~]# docker container run —name web -p 80:80 —rm nginx:latest
[root@centos-82 ~]# docker container port web
80/tcp -> 0.0.0.0:80
[root@centos-82 ~]# curl -s -I 127.0.0.1 | grep ^HTTP
HTTP/1.1 200 OK
[root@centos-50 ~]# curl -s -I 192.168.1.82 | grep HTTP
HTTP/1.1 200 OK
- 宿主机多个端口映射到容器
[root@centos-82 ~]# docker container run —name web -p 80:80 -p 8080:80 —rm nginx:latest
[root@centos-82 ~]# docker container port web
80/tcp -> 0.0.0.0:8080
80/tcp -> 0.0.0.0:80
3.4.3. Join 模型(联盟式)
[root@centos-82 ~]# docker run —name bx1 -it —rm busybox:latest
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
32: eth0@if33: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
/ # mkdir -p /data/web
/ # echo 'bx1' > /data/web/index.html
/ # httpd -h /data/web/
[root@centos-82 ~]# docker container run —name bx2 -it —rm —network container:bx1 busybox:latest
/ # ip a ## 共享IP地址,但是其它名称空间隔离
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
32: eth0@if33: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
/ # wget -O - -q 127.0.0.1 ## 可以通过lo访问bx1中的web服务
bx1
/ # ls /data/web ## Mount名称空间隔离
ls: /data/web: No such file or directory
3.4.4. Open 模型(共享宿主机网络)
[root@centos-82 ~]# docker run —name bx1 -it —network host —rm busybox:latest
/ # ip a ## 显示的是宿主机的网络
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
link/ether 00:0c:29:88:a8:40 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.82/24 brd 192.168.1.255 scope global ens32
valid_lft forever preferred_lft forever
inet6 fe80::76f9:ec2b:13f3:2b18/64 scope link
valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue
link/ether 02:42:5d:21:bc:03 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:5dff:fe21:bc03/64 scope link
valid_lft forever preferred_lft forever
/ # mkdir /tmp/test/
/ # echo 'bx1' > /tmp/test/index.html
/ # httpd -h /tmp/test
[root@centos-82 ~]# netstat -lntp ## 在本机上可以直接看到httpd进程
tcp6 0 0 :::80 :::* LISTEN 5796/httpd
[root@centos-82 ~]# ps uax|grep http
root 5796 0.0 0.0 1272 40 ? Ss 23:01 0:00 httpd -h /tmp/test
[root@centos-82 ~]# ls /tmp/test ## Mounts仍然是隔离的
ls: cannot access /tmp/test: No such file or directory
[root@centos-82 ~]# curl 127.0.0.1 ## 可以直接访问
bx1