kubernetes网络之浅谈单机容器网络

容器网络环境隔离怎么理解?

容器的网络环境是隔离的,这个隔离就体现在不共用内核网络协议栈,即不共用网络协议栈要用到的数据和设备了:

  • 传输层:端口号
  • 网络层:路由表、iptables规则
  • 数据链路层:网卡设备、arp缓存表

如果在容器中执行iptablesifconfigarproute命令看到的肯定是不同的iptables规则、网络设备、arp缓存表和路由表。

网桥和veth pair

同一个宿主机的容器之间通信是通过二层网络进行通信的。物理机如果想通过二层网络通信,那么必须要有两样东西,一个是网线,一个是交换机。

在Linux系统中,扮演虚拟交换机角色的,叫做网桥;扮演网线角色的,叫做veth pair。

以Docker为例,在bridge模式下:

  • Docker Daemon第一次启动时会创建docker0网桥;
  • 在创建容器时,会创建一个veth pair,即veth设备对。

veth pair有两个端点:

  • 一端在宿主机中,可以看成是宿主机的一块虚拟网卡,但被关联到docker0网桥上;
  • 另一端,则借助net namespace技术,变成了容器中的eth0网卡。

veth pair之所以可以被看成“网线”,是因为它的特殊之处在于,只要有一端收到了数据包,同样的数据包也会在另一端出现。不受namespace的约束。

网桥:Linux的网桥提供了在同一个机器上各种网络设备之间互相转发数据的设备。普通的交换机对于接收到的报文,要么转发,要么丢弃,网桥除了具备普通交换机的功能以外,它还可以调用内核协议栈,处理发送给本机的报文

同宿主机中的容器通信过程

同一台宿主机中的两个容器(容器A -> 容器B)建立通信的过程如下(容器B的ip地址为172.17.0.3):

  1. 容器A中的内核网络协议栈对网络层进行处理时,去查路由表:

    1$ route
    2Kernel IP routing table
    3Destination     Gateway        Genmask       Flags  Metric Ref Use Iface
    4default         172.17.0.1     0.0.0.0        UG     0     0   0   eth0
    5172.17.0.0      0.0.0.0        255.255.0.0    U      0     0   0   eth0
    

    发现路由表中容器B的网络地址和第二条规则匹配。这条路由规则的网关(Gateway)是 0.0.0.0,这就意味着这是一条直连规则,即:凡是匹配到这条规则的 IP 包,应该经过 eth0 网卡,通过二层网络直接发往目的主机。

  2. 容器A于是查询本地的arp缓存表,如果没有找到目的MAC地址,则发一条arp广播,通过容器的eth0网卡发送出去。

  3. veth pair的另一端收到这个arp消息,把它转发给docker0网桥。

    这个另一端是宿主机的一块虚拟网卡,本来是应该可以调用网络协议栈来处理收到的数据包的,但是它被和docker0网桥绑定了,所以它的功能被降级为交换机的一个端口,只能无脑把数据包发给网桥去处理。

  4. docker0网桥扮演二层交换机的角色,把arp请求广播出去,收到容器B返回的MAC地址后,再通过原链路把MAC地址返回给容器A。

  5. 容器A使用目的MAC地址和源MAC地址封装链路层头部,将消息通过eth0网卡发送出去。

  6. docker0网桥收到数据包,直接根据目的MAC地址将其转发给容器B。

整个过程可以用下面这张图概括:

Pod中的容器网络

创建一个Pod前,首先要创建infra容器,这个infra容器就通过veth设备连接到网桥,接着创建其他容器,其他容器加入infra容器的net namespace,这样,就能做到和infra容器之间以localhost的方式通信,因为同一个namespace中的进程,共享内核数据和网络设备