0%

单机容器网络

前言

  • 最近在搭建 k8s 过程中,网络方案使用了 flannel 网络,遇到了 master 节点无法 ping 通 pod ip 的问题。为了解这个问题,先系统性学习一下容器网络相关的知识,会分成两个阶段,第一阶段是单机容器网络,第二阶段是跨主机容器网络。本篇主要先介绍单机容器网络。

实验环境

  • virtualbox 搭建4台 VM(ubuntu-18.04.5-live-server-amd64.iso),每台 VM 配置双网卡
    • 网卡1 NAT 桥接(使用 nat 会出现 k8s master 无法 ping 通 pod 等问题),用于连接外网,混杂模式选全部允许
    • 网卡2 Host-Only,用于提供宿主机到虚拟机的连接以及虚拟机直接的访问,混杂模式选全部允许。参考virtualbox 虚拟机组网一顿操作后配置结果如下
ip hostname
192.168.99.13 linyouquan-master
192.168.99.14 linyouquan-worker1
192.168.99.15 linyouquan-worker2
192.168.99.16 linyouquan-test

docker 网络

原生网络

docker 安装时会自动在 host 上创建三个网络

linyouquan@linyouquan-master:~$ docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
98835cd9ea52   bridge    bridge    local
9be4ce0db265   host      host      local
dee007fac16c   none      null      local

none 网络

linyouquan@linyouquan-master:~$ docker run -it --network=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:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # ping www.baidu.com
ping: bad address 'www.baidu.com'
/ # ping 192.168.99.13
PING 192.168.99.13 (192.168.99.13): 56 data bytes
ping: sendto: Network is unreachable

host 网络

连接到 host 网络的容器共享 docker host 的网络栈,容器的网络配置和 host 完全一样

docker run -it --network=host busybox

bridge 网络

Docker 安装时会创建一个命名为如果不指定--network,创建的容器会默认挂到 docker0 上。

linyouquan@linyouquan-master:~$ 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:8 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:696 (696.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:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ #
linyouquan@linyouquan-master:~$ brctl show
bridge name	bridge id		STP enabled	interfaces
cni0		8000.2adc05803c00	no		veth757262fe
							vethc8bd6ed9
docker0		8000.0242391693b6	no		veth146cb3d
ip address
docker network inspect bridge

自定义网络

docker 提供了三种 user-defined 网络(bridge/overlay/macvlan),本篇文章只先讲 bridg 网络。

docker network create --driver bridge --subnet 172.22.16.0/24 --gateway 172.22.16.1 my_net
docker run  -it --network=my_net --ip 172.22.16.18 busybox /bin/sh
docker run  -it --network=my_net --ip 172.22.16.19 busybox /bin/sh

同一网络中的容器是可以通信的,不同网络中的容器不能相互通信

如何让第一个 busybox 容器能访问第二第三个 busybox 呢?答案是给第一个 busybox 增加 my_net 网卡

docker network connect my_net dc5464853a0f

容器间通信

ip 通信

  • 直接 ping ip

docker dns server

从 Docker 1.10 版本开始,docker daemon 实现了一个内嵌的 DNS server,使容器可以直接通过“容器名”通信。方法很简单,只要在启动时用 --name 为容器命名就可以了。使用 docker DNS 有个限制:只能在 user-defined 网络中使用。也就是说,默认的 bridge 网络是无法使用 DNS 的。

joined 容器

joined 容器非常特别,它可以使两个或多个容器共享一个网络栈,共享网卡和配置信息,joined 容器之间可以通过 127.0.0.1 直接通信。

docker run -d -it --name=web1 httpd
docker run -it --network=container:web1 busybox
/ # wget localhost
Connecting to localhost (127.0.0.1:80)
saving to 'index.html'
index.html           100% |**************************************************************************************************************************************************************************************************************|    45  0:00:00 ETA
'index.html' saved
/ # cat index.html
<html><body><h1>It works!</h1></body></html>
/ #

joined 容器非常适合以下场景:

  • 不同容器中的程序希望通过 loopback 高效快速地通信,比如 web server 与 app server。
  • 希望监控其他容器的网络流量,比如运行在独立容器中的网络监控程序。

容器与外部世界连接

容器访问外部世界

容器默认就能访问外网。在上面的例子中,busybox 位于 docker0 这个私有 bridge 网络中(172.17.0.0/16),当 busybox 从容器向外 ping 时,docker host 上的网桥 docker0 收到来自 172.17.0.0/16 网段的外出包,把它交给 MASQUERADE 处理。而 MASQUERADE 的处理方式是将包的源地址替换成 host 的地址发送出去,即做了一次网络地址转换(NAT)。

外部世界访问容器

docker 可将容器对外提供服务的端口映射到 host 的某个端口,外网通过该端口访问容器。每一个映射的端口,host 都会启动一个 docker-proxy 进程来处理访问容器的流量。

docker run -d -p 80 httpd
linyouquan@linyouquan-master:~$ docker ps | grep -v k8s
CONTAINER ID   IMAGE                                               COMMAND                  CREATED          STATUS          PORTS                                     NAMES
5f285be7fb67   httpd                                               "httpd-foreground"       55 minutes ago   Up 55 minutes   0.0.0.0:49153->80/tcp, :::49153->80/tcp   upbeat_lewin
linyouquan@linyouquan-master:~$ ps aux | grep -i proxy
root      5271  0.0  0.1 1152912 3788 ?        Sl   18:18   0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 49153 -container-ip 172.17.0.2 -container-port 80
root      5277  0.0  0.1 1152912 4016 ?        Sl   18:18   0:00 /usr/bin/docker-proxy -proto tcp -host-ip :: -host-port 49153 -container-ip 172.17.0.2 -container-port 80
linyouq+ 14629  0.0  0.0  13144  1048 pts/0    S+   18:43   0:00 grep --color=auto -i proxy

参考