四、Docker 网络原理、分类及容器互联配置
本文是《Docker必知必会系列》第四篇,原文发布于个人博客:悟尘记。
Docker 网络配置¶
Docker 网络基本原理¶
要实现网络通信,机器需要至少一个网络接口(物理接口或虚拟接口)来收发数据包。如果不同子网之间要进行通信,需要路由机制。
Docker 中的网络接口默认都是虚拟接口,虚拟接口的优势之一是转发效率较高。 Linux 通过在内核中进行数据复制来实现虚拟接口之间的数据转发,发送接口的发送缓存中的数据包被直接复制到接收接口的接收缓存中。
当 Docker 启动时,会自动在主机上创建一个 docker0
虚拟网桥( Linux 的一个 bridge),它会在挂载到它的网口之间进行转发。同时,Docker 随机分配一个本地未占用的私有网段中的一个地址给 docker0
接口,此后启动的容器内的网口也会自动分配一个同一网段(172.17.0.0/16
)的地址。
当创建一个 Docker 容器的时候,同时会创建了一对 veth pair
接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包)。这对接口一端在容器内,即 eth0
;另一端在本地并被挂载到 docker0
网桥,名称以 veth
开头(例如 vethAQI2QT
)。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。
关于 Docker 网络的更多内容,可以访问:https://docs.docker.com/network/>
Docker 网络类型¶
Docker 创建一个容器的时候,会执行如下操作:
- 创建一对虚拟接口,分别放到本地主机和新容器中;
- 本地主机一端桥接到默认的 docker0 或指定网桥上,并具有一个唯一的名字,如 veth65f9;
- 容器一端放到新容器中,并修改名字作为 eth0,这个接口只在容器的命名空间可见;
- 从网桥可用地址段中获取一个空闲地址分配给容器的 eth0,并配置默认路由到桥接网卡 veth65f9。
完成这些之后,容器就可以使用 eth0 虚拟网卡来连接其他容器和其他网络。
可以在 docker run
的时候通过 --net
参数来指定容器的网络配置,有 4 个可选值:
--net=bridge
这个是默认值,连接到默认的网桥。--net=host
告诉 Docker 不要将容器网络放到隔离的命名空间中,即不要容器化容器内的网络。此时容器使用本地主机的网络,它拥有完全的本地主机接口访问权限。容器进程可以跟主机其它 root 进程一样可以打开低范围的端口,可以访问本地网络服务比如 D-bus,还可以让容器做一些影响整个主机系统的事情,比如重启主机。因此使用这个选项的时候要非常小心。如果进一步的使用--privileged=true
,容器会被允许直接配置主机的网络堆栈。--net=container:NAME_or_ID
让 Docker 将新建容器的进程放到一个已存在容器的网络栈中,新容器进程有自己的文件系统、进程列表和资源限制,但会和已存在的容器共享 IP 地址和端口等网络资源,两者进程可以直接通过lo
环回接口通信。--net=none
让 Docker 将新容器放到隔离的网络栈中,但是不进行网络配置。之后,用户可以自己进行配置。
外部访问容器¶
默认情况下,容器可以主动访问到外部网络的连接,但是外部网络无法访问到容器。想要允许外部访问容器,可以在 docker run
时候通过 -p
或 -P
参数来启用(可以多次使用 -p
标记来绑定多个端口)。
使用 docker ps
可以看到,本地主机的 80 被映射到了容器的 80
端口。此时访问本机的 80
端口即可访问容器内 nginx
应用提供的界面。
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bc533791f3f5 nginx "nginx -g '…" 5 days ago Up 4 days 0.0.0.0:80->80/tcp nginx
容器间互联¶
先创建一个新的 Docker 网络:
docker network create -d bridge lixl-net
-d
参数指定 Docker 网络类型,有bridge
,overlay
。其中overlay
网络类型用于 Swarm mode。
运行一个容器并连接到新建的 lixl-net
网络
docker run -it --rm --name busybox1 --network lixl-net busybox sh
打开新的终端,再运行一个容器并加入到 lixl-net
网络
docker run -it --rm --name busybox2 --network lixl-net busybox sh
再打开一个新的终端查看容器信息
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b47060aca56b busybox "sh" 1 minutes ago Up 1 minutes busybox2
8720575823ec busybox "sh" 1 minutes ago Up 1 minutes busybox1
下面通过 ping
来证明 busybox1
容器和 busybox2
容器建立了互联关系。
在 busybox1
容器输入以下命令
/ # ping busybox2
PING busybox2 (172.19.0.3): 56 data bytes
64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.072 ms
64 bytes from 172.19.0.3: seq=1 ttl=64 time=0.118 ms
用 ping 来测试连接 busybox2
容器,它会解析成 172.19.0.3
。
同理在 busybox2
容器执行 ping busybox1
,也会成功连接到。
/ # ping busybox1
PING busybox1 (172.19.0.2): 56 data bytes
64 bytes from 172.19.0.2: seq=0 ttl=64 time=0.064 ms
64 bytes from 172.19.0.2: seq=1 ttl=64 time=0.143 ms
这样,busybox1
容器和 busybox2
容器建立了互联关系。
如果有多个容器之间需要互相连接,推荐使用 Docker Compose。