为什么需要网络管理

容器的网络默认会与宿主机器以及其他的容器相互隔离,但是还需要考虑到下面的这些问题:

  1. 多个容器之间是如何进行通信的
  2. 容器和宿主机是如何进行通信的
  3. 容器和外界是如何进行通信的
  4. 容器要运行一些网络的服务,如果要让外部也能访问,那么该如何实现
  5. 容器不想让它的网络和宿主机,以及其他的容器隔离该如何实现
  6. 容器不需要网络该如何实现
  7. 容器需要定制化网络该如何实现

Docker网络架构简介

Docker容器网络是为了应用程序而创造的虚拟环境的一部分,它能让应用从宿主机器上操作系统的网络环境中独立出来,形成容器自有的网络设备,ip协议栈,端口套接字,等等模块,Docker为了实现出容器网络,因此主要采取的架构有三部分组成:CNM,Libnetwork和驱动组成,下面就一一对这些进行概述

CNM

Docker在最初的设计过程中,采用的设计规范就是这种模式,这种模式的全称是container network Model,在具体的Docker网络中的基础组成元素是,Sandbox,Endpoint,Network

在这里插入图片描述
下面对于上述的这些内容进行解释:

Sandbox:提供了容器的虚拟网络栈,就是所谓的端口,套接字,ip路由表,防火墙,dns等内容,主要是用来隔离容器网络和宿主机网络,也形成了完全独立的容器网络环境

Network:这是Docker内部的一个虚拟的子网,使得网络内的参与者可以进行通信

Endpoint:这是虚拟网络的接口,就想普通网络的接口一样,Endpoint的主要职责是负责创建链接,Endpoint类似于常见的网络适配器,这就意味着一个Endpoint只需要能接入到某一个网络,当容器需要接入多个网络,就需要多个Endpoint

如上所示,容器b中有两个Endpoint,那么它就可以接入到网络a和网络b,那么容器a和容器b是可以相互进行通信的,因为这两个都使用了网络a,但是a和c是不可以通信的,因为没有接入一个网络中

LibNetwork

这个模块是CNM的一个具体的标准实现,Libnetwork是一个开源库,在这个开源库中是使用Go语言进行编写的,也是Docker中使用的标准库,Docker网络架构的核心代码都在这里,这个库中实现了CNM中定义的三个组件,此外还实现了本地服务发现,基于容器的负载均衡,还有网络控制层和管理层等功能

驱动

驱动主要是负责进行实现数据层相关的内容,例如说对于网络的连通性和隔离性就是通过驱动来完成的,驱动主要是实现了特定网络类型的方式拓展了Docker的网络栈,例如有桥接网络和覆盖网络

Docker内部还内置了很多的驱动,驱动主要是负责进行它上面网络资源的创建和管理

Docker网络管理命令

命令清单:

  1. docker network create:创建网络
  2. docker network connect:连接网络
  3. docker network disconnect:断开网络
  4. docker network ls:列出网络
  5. docker network prune:删除不使用的网络
  6. docker network inspect:查看网络详情
  7. docker network rm:删除1个或者多个网络

网络命令基本操作

创建网络并制定ip地址段

root@VM-24-7-ubuntu:~# docker network create --subnet=172.18.0.0/16 mynetwork
a2d04989a501be9e76052a27bd3b65bcfbe6df05eab8cd4c951bc1e54f0198ef

查看创建的网络

root@VM-24-7-ubuntu:~# docker network ls
NETWORK ID     NAME        DRIVER    SCOPE
c649cc05be2c   bridge      bridge    local
d86cdfa38d43   host        host      local
a2d04989a501   mynetwork   bridge    local
ab94c63a107d   none        null      local

创建一个容器并加入网络

root@VM-24-7-ubuntu:~# docker run -itd --name mynginx --network mynetwork nginx
e0f24948938c88e563fc68405ef1caca2246280f84f6a8033314d18884316a74

查看容器网络信息

"Networks": {
                "mynetwork": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "MacAddress": "02:42:ac:12:00:02",
                    "NetworkID": "a2d04989a501be9e76052a27bd3b65bcfbe6df05eab8cd4c951bc1e54f0198ef",
                    "EndpointID": "43ad4323fe156a4670fcbad65d538d8d56bacbf6f1b4bfbff6f16a2a7043efed",
                    "Gateway": "172.18.0.1",
                    "IPAddress": "172.18.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "DriverOpts": null,
                    "DNSNames": [
                        "mynginx",
                        "e0f24948938c"
                    ]
                }

网络详解

再回到前面列举出的网络,下面一一解释在docker中存在的网络信息:

NETWORK ID     NAME        DRIVER    SCOPE
c649cc05be2c   bridge      bridge    local
d86cdfa38d43   host        host      local
a2d04989a501   mynetwork   bridge    local
ab94c63a107d   none        null      local

docker Bridge网络

在Docker Bridge网络中采用内置的Bridge驱动,这个驱动的底层使用的是Linux内核中的一个Linux Bridge技术,对于网路来说,Bridge网络是在网络段之间进行转发流量的链路蹭设备,而网桥是可以在主机内核中运行的硬件设备或者软件设备

对于Docker来说,桥接网络使用的软件网桥Docker0,它允许连接到同一个网桥网络的容器进行通信,同时提供与未连接到该网桥网络容器的隔离

Docker container的Bridge桥接模式可以参考下面的图片:

在这里插入图片描述
正常来说,当在创建的容器中如果没有使用–network参数制定要加入的Docker网络的时候,默认使用的就是Docker默认的单机桥接网络,就是这个Bridge的网络

而默认的Bridge网络也会背映射到内核中为Docker0的网络上

Docker默认的Bridge网络和Linux内核中的Docker0网桥也是一一对应的关系,Bridge是Docker对于网络的命名,而Docker0是内核中网桥的名字

在这里插入图片描述

容器之间的网络通信

多台主机之间是如何通过网络进行通信的?

如果是两台主机可以直接连接网线的两段进行通信,那么多个主机之间的通信?需要用到的是路由器交换机进行通信

那么对于Docker容器来说,其实也是这个基本原理,容器之间的通信也和上面主机通信的方式如出一辙,之前提到了安装Docker的时候默认会使用docker0这个网桥软件设备,这个docker0设备可以类比成上图的交换机和路由器设备,当创建好容器之后,如果不手动指定网络模式,默认会使用Bridge网络,容器也会连接到docker0这个网桥设备,然后通过这个网桥来进行容器之间的通信

做个实验

现在用Busybox创建两个容器

root@VM-24-7-ubuntu:~# docker container run -itd --name c1 busybox
Unable to find image 'busybox:latest' locally
latest: Pulling from library/busybox
ec562eabd705: Pull complete 
Digest: sha256:9ae97d36d26566ff84e8893c64a6dc4fe8ca6d1144bf5b87b2b85a32def253c7
Status: Downloaded newer image for busybox:latest
0debb05244d3b60d555c68da54693b3f5610c8046a6024104e20d39f87625a8e
root@VM-24-7-ubuntu:~# docker container run -itd --name c2 busybox
ea71679200c98e065d43e300eeb4faace2ba204ea76892a8bf7cc69668f9c84b
root@VM-24-7-ubuntu:~# docker container ls
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS     NAMES
ea71679200c9   busybox   "sh"                     6 seconds ago    Up 6 seconds              c2
0debb05244d3   busybox   "sh"                     14 seconds ago   Up 14 seconds             c1

查看两个容器的通信现象

先查看一下网路信息:

root@VM-24-7-ubuntu:~# docker container exec -it c1 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:13 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:1086 (1.0 KiB)  TX bytes:0 (0.0 B)

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:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

root@VM-24-7-ubuntu:~# docker container exec -it c2 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:11 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:866 (866.0 B)  TX bytes:0 (0.0 B)

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:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

然后在c1容器中去ping一下c2容器的ip地址:

此时会发现是可以正常通信的:

root@VM-24-7-ubuntu:~# docker container exec -it c1 ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.321 ms
64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.063 ms
64 bytes from 172.17.0.3: seq=2 ttl=64 time=0.070 ms
64 bytes from 172.17.0.3: seq=3 ttl=64 time=0.097 ms
64 bytes from 172.17.0.3: seq=4 ttl=64 time=0.063 ms
^C
--- 172.17.0.3 ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max = 0.063/0.122/0.321 ms

然后查看Bridge网络的信息

        "Containers": {
            "0debb05244d3b60d555c68da54693b3f5610c8046a6024104e20d39f87625a8e": {
                "Name": "c1",
                "EndpointID": "0c44305f7aff7af74f90e6d60a30089317cdb22256d0fef1409d141c2580f626",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "ea71679200c98e065d43e300eeb4faace2ba204ea76892a8bf7cc69668f9c84b": {
                "Name": "c2",
                "EndpointID": "5d92cf8664f80abbebbb508b8f3f5749f7f4d087cab080ef084d1c1c505e4d22",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            }
        },

可以看出,这个网络中现在接入了两个容器,c1和c2,而此时,这两个容器就是通过docker0这个网桥来进行通信的,当我们停止或者删除一个容器的时候,就会和这个docker0断开:

暂停一个容器

在这里插入图片描述
创建自定义Bridge

在默认情况下,创建的容器都会连接在docker0这个Bridge上,我们也可以自己定义一些Bridge,让运行的容器借助这个Bridge来进行通信

DNS解析

Docker自定义桥接网络是支持通过Docker的DNS服务来进行域名解析的,也就是说可以直接用容器名来进行通信,因为DNS可以解析容器名到ip地址的映射,但是默认的Bridge网络是不支持DNS的

下面创建四个容器

两个使用默认的Bridge,两个使用自定义Bridge

root@VM-24-7-ubuntu:~# docker container run -itd --name c1 busybox
321e39278a0f8a5182fea4ab1cf1eba6a58fd57907e8fe02331402212703c182
root@VM-24-7-ubuntu:~# docker container run -itd --name c2 busybox
cd8d20f25c867e58d59b47facdf8ada0ad74c97c96c533c34c1ee0b507746fe9
root@VM-24-7-ubuntu:~# docker network create new-bridge
da9aba174a732e9ff7eb267427d6aa7a20686bd11ce361c72c4344b0a689d573
root@VM-24-7-ubuntu:~# docker container run -itd --name c3 --network new-bridge busybox
48fab956ab181239c3525afa307b90aca56277418eb7def2f8c8fc7986336aa2
root@VM-24-7-ubuntu:~# docker container run -itd --name c4 --network new-bridge busybox
ac589f4b66f5aa2ee3eaff299e764484b1fd34fb051a430d84cd0f7e296f2101

查看现在的容器列表

CONTAINER ID   IMAGE     COMMAND   CREATED              STATUS              PORTS     NAMES
ac589f4b66f5   busybox   "sh"      30 seconds ago       Up 29 seconds                 c4
48fab956ab18   busybox   "sh"      35 seconds ago       Up 33 seconds                 c3
cd8d20f25c86   busybox   "sh"      About a minute ago   Up About a minute             c2
321e39278a0f   busybox   "sh"      About a minute ago   Up About a minute             c1

看c1和c2是否可以使用DNS解析服务

尝试用c1去ping一下c2的ip地址

root@VM-24-7-ubuntu:~# docker container exec -it c1 ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.347 ms
64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.082 ms
^C
--- 172.17.0.3 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.082/0.214/0.347 ms

看出结论是可以的

尝试用c1去ping一下c2:

root@VM-24-7-ubuntu:~# docker container exec -it c1 ping c2
ping: bad address 'c2'

从而确定,默认的Bridge是不支持进行DNS解析的

验证c3和c4是否可以进行DNS解析

root@VM-24-7-ubuntu:~# docker container exec -it c3 ping 172.18.0.3
PING 172.18.0.3 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=1.732 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.084 ms
^C
--- 172.18.0.3 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.084/0.908/1.732 ms
root@VM-24-7-ubuntu:~# docker container exec -it c3 ping c4
PING c4 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.070 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.091 ms
^C
--- c4 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.070/0.080/0.091 ms

这两个都ping成功了,说明自定义的Bridge是支持DNS解析的

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐