S_lion's Studio

docker网络

字数统计: 1.3k阅读时长: 4 min
2022/03/21 Share
自己动手实现network namespace中演示了network namespace的实现方式,network namespace可以为命名空间内的所有进程提供了全新隔离的网络协议栈。而所谓“网络栈”,就包括了:网卡(Network Interface)、回环设备(Loopback Device)、路由表(Routing Table)和 iptables 规则。对于一个进程来说,这些要素,构成了它发起和响应网络请求的基本环境。

作为一个容器,它可以声明直接使用宿主机的网络栈(–net=host),即:不开启 Network Namespace,比如:

1
$ docker run –d –net=host --name nginx-host nginx

直接使用主机网络模式虽然可以为容器提供良好的网络性能,但会引入共享网络资源的问题,比如端口冲突。所以,在大多数情况下,我们都希望容器进程能使用自己 Network Namespace 里的网络栈,即:拥有属于自己的 IP 地址和端口。

如何让隔离的容器进程跟其他 Network Namespace 里的容器进程进行交互呢?Linux 中可以通过虚拟网桥实现,docker中也是通过“网桥”实现的。

Docker Bridge

当 Docker 启动时,会自动在主机上创建一个 docker0 虚拟网桥,实际上是 Linux 的一个 bridge,可以理解为一个软件交换机。它会在挂载到它的网口之间进行转发。

创建一个 Docker 容器的时候,同时会创建了一对 veth pair 接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包)。这对接口一端在容器内,即 eth0 ;另一端在本地并被挂载到docker0 网桥,名称以 veth 开头(例如vethAQI)。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。Docker 就创建了在主机和所有容器之间一个虚拟共享网络。

brctl show查看当前的网桥:

上面显示中的接口是由对应的桥提供网络流转的,在宿主机上也可以看出只有bridge拥有ip地址,而挂在bridge上的vethxxx则没有ip。

网络流转拓扑

容器与宿主机通信

在桥接模式下,Docker Daemon 将 veth0 附加到 docker0 网桥上,保证宿主机的报文有能力发往 veth0。再将 veth1 添加到 Docker 容器所属的网络命名空间,保证宿主机的网络报文若发往 veth0 可以立即被 veth1 收到。

容器与外界通信

容器如果需要联网,则需要采用 NAT 方式。准确的说,是 NATP (网络地址端口转换) 方式。NATP 包含两种转换方式:SNAT 和 DNAT 。

外部访问容器

目的 NAT (Destination NAT,DNAT): 修改数据包的目的地址。

当宿主机以外的世界需要访问容器时,数据包的流向如下图所示:

由于容器的 IP 与端口对外都是不可见的,所以数据包的目的地址为宿主机的 ip 和端口,为 192.168.1.10:24 。

数据包经过路由器发给宿主机 eth0,再经 eth0 转发给 docker0 网桥。由于存在 DNAT 规则,会将数据包的目的地址转换为容器的 ip 和端口,为 172.17.0.n:24 。

宿主机上的 docker0 网桥识别到容器 ip 和端口,于是将数据包发送附加到 docker0 网桥上的 veth0 接口,veth0 接口再将数据包发送给容器内部的 veth1 接口,容器接收数据包并作出响应。

容器访问外部

目的 NAT (Destination NAT,DNAT): 修改数据包的目的地址。

当容器需要访问宿主机以外的世界时,数据包的流向为下图所示:

此时数据包的源地址为容器的 ip 和端口,为 172.17.0.n:24,容器内部的 veth1 接口将数据包发往 veth0 接口,到达 docker0 网桥。

宿主机上的 docker0 网桥发现数据包的目的地址为外界的 IP 和端口,便会将数据包转发给 eth0 ,并从 eth0 发出去。由于存在 SNAT 规则,会将数据包的源地址转换为宿主机的 ip 和端口,为 192.168.1.10:24 。

由于路由器可以识别到宿主机的 ip 地址,所以再将数据包转发给外界,外界接受数据包并作出响应。这时候,在外界看来,这个数据包就是从 192.168.1.10:24 上发出来的,Docker 容器对外是不可见的。

docker0 之所以能将对外报文转发到eth0,是因为在一个主机内,通过路由表规则进行转发,在主机内docker0可以reach到eth0所对应的IP。

当进行端口映射的时候我们可以查看到宿主机中多了一个进程,这就是前面所说的docker-proxy,每增加一个端口映射,宿主机就会多出一个docker-proxy进程,当其他的人访问这个主机的时候,docker-proxy就会自动找到对应容器的端口。

参考链接

http://blog.daocloud.io/4896.html

CATALOG
  1. 1. Docker Bridge
  2. 2. 网络流转拓扑
    1. 2.1. 容器与宿主机通信
    2. 2.2. 容器与外界通信
      1. 2.2.1. 外部访问容器
      2. 2.2.2. 容器访问外部
  3. 3. 参考链接