
诸如 containerd 这样的容器运行时在 Linux 上通过网络命名空间 (Network Namespace) 实现容器之间的网络隔离.
为了让容器和容器之间, 容器和宿主机之间可以互相通信, 我们需要借助 veth 和 network brdige. veth 的全称是 Virtual Ethernet Device, 即虚拟网卡, 用于在容器网络和宿主机网络之间架起桥梁. bridge 则是链接着所有容器的交换机, 简化路由逻辑.
当 containerd 创建新的容器时, 其新建一个 veth, 连接容器和宿主机的网络空间. 类似命令 ip link add <p1-name> netns <p1-ns> type veth peer <p2-name> netns <p2-ns>.
我们在一个测试集群中寻找一个容器, 并确定其 veth 对应的 if.
~ k get -n dev -l app=signin pods NAME READY STATUS RESTARTS AGE signin-test-a-8bcd5db69-9z2c5 2/2 Running 0 6d3h ~ k exec -n dev -ti signin-test-a-8bcd5db69-9z2c5 -- ip link show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: eth0@if220: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP link/ether c2:ce:72:1b:97:6e brd ff:ff:ff:ff:ff:ff ~ k exec -n dev -ti signin-test-a-8bcd5db69-9z2c5 -- cat /sys/class/net/eth0/iflink 220 随后, 我们可以在宿主机的网络空间中找到对应的设备.
~ grep -l 220 /sys/class/net/veth*/ifindex /sys/class/net/veth12acb4c1/ifindex ~ ip link show dev veth12acb4c1 220: veth12acb4c1@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master cni0 state UP mode DEFAULT group default link/ether be:78:61:7f:a4:25 brd ff:ff:ff:ff:ff:ff link-netnsid 50 我们可以发现该设备链接到了名为 cni0 的 bridge 上.
~ ls -alht /sys/class/net/veth12acb4c1/ | grep master lrwxrwxrwx. 1 root root 0 12 月 5 21:49 master -> ../cni0 或者更准确的说, 这台宿主机上和容器绑定的设备都链接到了 cni0.
~ ls -alht /sys/class/net/cni0/ | grep veth | head lrwxrwxrwx. 1 root root 0 12 月 5 23:44 lower_veth0c9a5076 -> ../veth0c9a5076 lrwxrwxrwx. 1 root root 0 12 月 5 23:44 lower_veth75d5e70a -> ../veth75d5e70a lrwxrwxrwx. 1 root root 0 12 月 5 23:44 lower_veth12acb4c1 -> ../veth12acb4c1 lrwxrwxrwx. 1 root root 0 12 月 5 23:44 lower_veth25c523a3 -> ../veth25c523a3 lrwxrwxrwx. 1 root root 0 12 月 5 23:44 lower_veth54236aab -> ../veth54236aab lrwxrwxrwx. 1 root root 0 12 月 5 23:44 lower_veth69d77b1d -> ../veth69d77b1d lrwxrwxrwx. 1 root root 0 12 月 5 23:44 lower_vethd81e7b63 -> ../vethd81e7b63 lrwxrwxrwx. 1 root root 0 12 月 5 23:44 lower_veth2ea2cc31 -> ../veth2ea2cc31 lrwxrwxrwx. 1 root root 0 12 月 5 23:44 lower_veth534bb0ad -> ../veth534bb0ad lrwxrwxrwx. 1 root root 0 12 月 5 23:44 lower_vethabcf68fe -> ../vethabcf68fe 此时容器内看路由表, 可以发现:
# k exec -n dev -ti signin-test-a-8bcd5db69-9z2c5 -- ip route default via 172.22.0.1 dev eth0 172.22.0.0/24 dev eth0 scope link src 172.22.0.253 172.22.0.0/16 via 172.22.0.1 dev eth0 # k get -n dev pods signin-test-a-8bcd5db69-9z2c5 -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES signin-test-a-8bcd5db69-9z2c5 2/2 Running 0 6d4h 172.22.0.253 10.30.180.56 <none> <none> 上文中 172.22.0.0./24 是当前宿主机的 podCIDR, 172.22.0.0/16 是整个集群的 CIDR, 172.22.0.1 是宿主机上 cni0 对应的地址.
# ip addr show dev cni0 7: cni0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether aa:8d:2f:44:14:b0 brd ff:ff:ff:ff:ff:ff inet 172.22.0.1/24 brd 172.22.0.255 scope global cni0 valid_lft forever preferred_lft forever inet6 fe80::a88d:2fff:fe44:14b0/64 scope link valid_lft forever preferred_lft forever 在宿主机上看路由表, 可以发现:
ip route | grep -v -E "172.1(7|8)" default via 10.30.180.254 dev eth0 proto static metric 100 10.30.180.0/24 dev eth0 proto kernel scope link src 10.30.180.56 metric 100 172.22.0.0/24 dev cni0 proto kernel scope link src 172.22.0.1 172.22.1.0/24 via 10.30.180.55 dev eth0