docker 网络

作者: 赵阳_c149 | 来源:发表于2019-10-24 14:09 被阅读0次

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
  1. 从容器到外界: 容器的eth0->veth1(虚拟网桥bridge0的容器端接口veth6eb0c0d)->docker0(SNAT源地址转换)->宿主机eth0->外界

  2. 从外界到容器:外界 ->宿主机(DNAT目标地址转换)->docker0->eth0veth1(虚拟网桥bridge0的容器端接口veth6eb0c0d)->容器的eth0

宿主机主要网络配置

  1. 虚拟网桥:docker0
  2. 自定义网桥:br-fe392ff4421e
  3. 宿主机对外接口:eth0
  4. 虚拟网桥在宿主机端的接口: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

相关文章

网友评论

    本文标题:docker 网络

    本文链接:https://www.haomeiwen.com/subject/bkwrvctx.html