docker容器功能强大,部分原因是容器可以通过网络连接到其他容器和非容器的实体。在网络通讯的过程中,对于docker容器上的部署的应用来说,部署在docker环境中还是部署在非docker环境中,是没有任何区别的。
docker容器的网络通常有以下几种模式
1. bridge
bridge:-net=bridge
, 默认网络,Docker启动或创建一个docker0网桥,默认创建的容器也是添加到这个网桥中。
ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:92ff:fe3a:7063 prefixlen 64 scopeid 0x20<link>
ether 02:42:92:3a:70:63 txqueuelen 0 (Ethernet)
RX packets 42 bytes 7456 (7.2 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1989 bytes 209250 (204.3 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
可以看到docker0是docker容器的默认网关,网关ip为172.17.0.1。
创建一个容器
docker run -it busybox
进入容器后查看容器的网络配置:
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:7 errors:0 dropped:1 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:755 (755.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
可以看到,默认情况下,docker为容器创建了一个网卡接口eth0。容器通过这个接口和宿主机进行网络通讯。
2. Host
-net=host
容器不会获得一个独立的network namespace,而是与宿主机共用一个。这就意味着容器不会有自己的网卡信息,而是使用宿主机的。容器除了网络,其他都是隔离的。
尝试以host的模式创建容器,然后进入容器,查看网络配置:
docker run -it --net=host busybox
docker0 Link encap:Ethernet HWaddr 02:42:92:3A:70:63
inet addr:172.17.0.1 Bcast:172.17.255.255 Mask:255.255.0.0
inet6 addr: fe80::42:92ff:fe3a:7063/64 Scope:Link
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:42 errors:0 dropped:0 overruns:0 frame:0
TX packets:1991 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:7456 (7.2 KiB) TX bytes:209502 (204.5 KiB)
eth0 Link encap:Ethernet HWaddr 00:21:F6:15:86:04
inet addr:10.245.253.136 Bcast:10.245.255.255 Mask:255.255.248.0
inet6 addr: 2606:b400:2010:6863:221:f6ff:fe15:8604/64 Scope:Global
inet6 addr: fe80::221:f6ff:fe15:8604/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:255654103 errors:0 dropped:0 overruns:0 frame:0
TX packets:6224902 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:24689037382 (22.9 GiB) TX bytes:925742378 (882.8 MiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:114432 errors:0 dropped:0 overruns:0 frame:0
TX packets:114432 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:26104761 (24.8 MiB) TX bytes:26104761 (24.8 MiB)
此时显示的网络配置和宿主机一样。
3.None
-net=none
获取独立的network namespace,但不为容器进行任何网络配置,需要我们手动配置。
尝试以None的模式创建容器,然后进入容器,查看网络配置:
docker run -it --net=none busybox
/ # ifconfig
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
此时,ip和namespace都需要自定义配置。
4. Container
-net=container:Name/ID
与指定的容器使用同一个network namespace,具有同样的网络配置信息,两个容器除了网络,其他都是隔离的。
尝试以默认的模式创建容器:
docker run -d --name nginx01 --net nginx
因为该容器并没有暴露端口,在容器外无法访问。
现在创建另外一个容器,并暴露端口:
docker run -itd --name bs -p 99:80 busybox
重新创建nginx容器,并设置网络为container模式:
docker run -d --name nginx01 --net container:bs nginx
现在,nginx01容器是可以在容器外面访问的:
curl 172.17.0.2:80
进入容器bs:
docker exec -it bs sh
查看监听短端口,发现80端口已经在容器bs上被监听了。
netstat -antp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
tcp 0 0 :::16385 :::* LISTEN -
5. 自定义
与默认的bridge原理一样,但自定义网络具备内部DNS发现,可以通过容器名或者主机名容器之间网络通信。
创建两个容器:
docker run -itd --name bs1 busybox
docker run -itd --name bs2 busybox
分别进入并查看网络配置:
docker exec -it bs1 sh
ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:03
inet addr:172.17.0.3 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:14 errors:0 dropped:2 overruns:0 frame:0
TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1910 (1.8 KiB) TX bytes:434 (434.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
docker exec -it bs2 sh
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:04
inet addr:172.17.0.4 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:16 errors:0 dropped:6 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:2298 (2.2 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
在两个容器中,互相无法ping通:
ping bs1
ping: bad address 'bs1'
ping bs2
ping: bad address 'bs2'
创建网络:
docker network create bs-test
用新创建的网络重新创建容器
docker run -it --name bs3 --net=bs-test busybox
docker run -it --name bs4 --net=bs-test busybox
进入容器之后,可以看到ping ps3 和ping ps4成功了。
6. overlay
一个可以跨宿主机的bridge network。常用于docker swarm集群。用户可以选择对容器之间的网络通讯进行加密。Docker swarm和K8S都是容器编排工具。K8S 支持复杂度更高的需求,主要用于生产环境。而docker swarm主要提供一个易于入手的解决方案,部署简单而快速。因此在现实的工作中,容器编排主要通过K8S实现。随着k8s的普及,已经很少有人用了【1】,所以就不再详细介绍。
docker网络通讯原理
由于docker网络通讯的原理较为复杂,本文仅以最基本的bridge0为例简单介绍。更多说明请参照官方文档【2】。
这是Docker网络的默认选项,docker启动后创建一个docker0网桥,所有默认创建的容器将自动加入这个网络命名空间。Bridge顾名思义,就是网桥,工作于数据链路层,是一个虚拟的二层交换机。在网桥内,有一个表,存储着MAC地址和IP地址间的映射。同时,网桥还可以对传输数据进行校验。区别router,router主要用于不同网路之间的通讯,如以太网和ATM网,以IP为操作对象;区别集线器,集线器主要用于信号加强,以广播的形式传递数据。关于docker是如何操作iptable的规则以实现网络隔离的细节,可以参考官方文档【3】【4】
宿主机和容器之间的网络通信是通过一对网络接口实现的。
- 在宿主机上就是veth
-
在容器内部就是eth0
docker_nw.png
具体来说,宿主机和容器之间的网络通讯形式又有两种:
network.png
-
从容器到外界: 容器的eth0->veth1(虚拟网桥bridge0的容器端接口veth6eb0c0d)->docker0(SNAT源地址转换)->宿主机eth0->外界
-
从外界到容器:外界 ->宿主机(DNAT目标地址转换)->docker0->eth0veth1(虚拟网桥bridge0的容器端接口veth6eb0c0d)->容器的eth0
宿主机主要网络配置
- 虚拟网桥:docker0
- 自定义网桥:br-fe392ff4421e
- 宿主机对外接口:eth0
- 虚拟网桥在宿主机端的接口:veth6eb0c0d
ifconfig
br-fe392ff4421e: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.18.0.1 netmask 255.255.0.0 broadcast 172.18.255.255
inet6 fe80::42:4cff:fe16:b709 prefixlen 64 scopeid 0x20<link>
ether 02:42:4c:16:b7:09 txqueuelen 0 (Ethernet)
RX packets 71 bytes 10542 (10.2 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2978 bytes 313242 (305.9 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:92ff:fe3a:7063 prefixlen 64 scopeid 0x20<link>
ether 02:42:92:3a:70:63 txqueuelen 0 (Ethernet)
RX packets 71 bytes 10542 (10.2 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2978 bytes 313242 (305.9 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.245.253.136 netmask 255.255.248.0 broadcast 10.245.255.255
inet6 2606:b400:2010:6863:221:f6ff:fe15:8604 prefixlen 64 scopeid 0x0<global>
inet6 fe80::221:f6ff:fe15:8604 prefixlen 64 scopeid 0x20<link>
ether 00:21:f6:15:86:04 txqueuelen 1000 (Ethernet)
RX packets 260560943 bytes 25092797886 (23.3 GiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 6330084 bytes 941913458 (898.2 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 0 (Local Loopback)
RX packets 116380 bytes 26552635 (25.3 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 116380 bytes 26552635 (25.3 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
veth6eb0c0d: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::506c:dcff:fe3a:d609 prefixlen 64 scopeid 0x20<link>
ether 52:6c:dc:3a:d6:09 txqueuelen 0 (Ethernet)
RX packets 6 bytes 434 (434.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 68 bytes 14075 (13.7 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
【1】Docker swarm vs kubernetes
【2】docker network
【3】iptables
【4】networking
网友评论