1.单机容器网络的实现
-
同节点两个容器的互访
为了说明容器间的访问,在consul-0所在宿主机上调度了一个web-1的应用。#进入consul-0容器 kubectl exec consul-0 -it /bin/sh #在容器里执行 / # ifconfig eth0 Link encap:Ethernet HWaddr 6E:55:56:21:F3:9F inet addr:10.244.3.40 Bcast:10.244.3.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1 RX packets:13178957 errors:0 dropped:0 overruns:0 frame:0 TX packets:8061195 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:1677907317 (1.5 GiB) TX bytes:1085173944 (1.0 GiB) #看路由情况 / # route Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface default 10.244.3.1 0.0.0.0 UG 0 0 0 eth0 10.244.0.0 10.244.3.1 255.255.0.0 UG 0 0 0 eth0 10.244.3.0 * 255.255.255.0 U 0 0 0 eth0
可以看到consul-0容器里面有eth0的网卡,怎么通过该网卡传输数据到指定web-0容器呢。这里涉及到Veth Pair的虚拟设备。Veth Pair的特点是它会以两张网卡的方式成对存在,并且从其中一张网卡发送数据包可以直接出现在对应的另一张网卡上,即使这两张网卡在不同的NetworkNamespace(对应容器namespace隔离技术中对应的网络隔离)上。
```
#宿主机上
[root@k8s-node3 ~]# ifconfig
cni0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1450
inet 10.244.3.1 netmask 255.255.255.0 broadcast 10.244.3.255
inet6 fe80::242d:afff:fe7e:516 prefixlen 64 scopeid 0x20<link>
ether 26:2d:af:7e:05:16 txqueuelen 1000 (Ethernet)
RX packets 13784494 bytes 1697239447 (1.5 GiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 22202070 bytes 2850632066 (2.6 GiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
veth2e303920: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1450
inet6 fe80::8c1d:cdff:fe31:6e6c prefixlen 64 scopeid 0x20<link>
ether 8e:1d:cd:31:6e:6c txqueuelen 0 (Ethernet)
RX packets 1 bytes 42 (42.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 280 bytes 16957 (16.5 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
veth6a98119e: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1450
inet6 fe80::f45b:81ff:fee2:f031 prefixlen 64 scopeid 0x20<link>
ether f6:5b:81:e2:f0:31 txqueuelen 0 (Ethernet)
RX packets 13346497 bytes 1814710689 (1.6 GiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 21741625 bytes 2790447367 (2.5 GiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@k8s-node3 ~]# brctl show
bridge name bridge id STP enabled interfaces
cni0 8000.262daf7e0516 no veth2e303920
veth6a98119e
docker0 8000.0242aa302d4e no
```
可以看到veth2e303920,veth6a98119e两张虚拟网卡被“插”到cni上,这里可以看到并没有走docker0,这是因为k8s的网络接管了容器原有的网络。这里怎么判断consul-0对应的veth pair是哪张虚拟网卡呢?
```
#宿主机上
[root@k8s-node3 ~]# ip link
21: veth2e303920@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master cni0 state UP mode DEFAULT group default
link/ether 8e:1d:cd:31:6e:6c brd ff:ff:ff:ff:ff:ff link-netnsid 3
44: veth6a98119e@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master cni0 state UP mode DEFAULT group default
link/ether f6:5b:81:e2:f0:31 brd ff:ff:ff:ff:ff:ff link-netnsid 0
#consul-0容器上
/ # cat /sys/class/net/eth0/iflink
44
```
说明veth6a98119e对应consul-0的在veth pair的虚拟网卡,veth2e303920对应web-1,就不额外说明了。
```
#查看pod的ip信息
[root@k8s-master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
consul-0 1/1 Running 0 6d23h 10.244.3.40 k8s-node3 <none> <none>
web-1 1/1 Running 0 10d 10.244.3.17 k8s-node3 <none> <none>
```
consul-0去访问web-1时通过ip地址10.244.3.17,前面route的时候看到10.244.3.0对应的Gateway是*,意味着是网络直连走二层网络,前面讲了veth2e303920,veth6a98119e插在cni0网络上,所以需要通过cni0找到10.244.3.17的mac地址,而veth2e303920对应的nginx-0的地址为10.244.3.17,cni0发广播到nginx-0的网络协议栈,就会把10.244.3.17的MAC地址回复给consul-0。所以consul-0可以访问到nginx-0.
宿主机不同容器网络的访问
结合下图整体说明同宿主机不同容器网络的访问情况。
- ARP广播
1. consul-0访问10.244.3.17,在路由上可以看到gateway为*,所以会走二层网络直达。
2. consul-0访问10.244.3.17,在路由上可以看到Use Iface为eth0,所以流量会通过eth0
3. 而eth0跟veth6a98119e是veth Pair,所以过eth0的流量会在veth6a98119e出现,此时veth6a98119e相当于一张虚拟网卡被插在cni网桥上。
4. consul-0访问10.244.3.17,第一次访问的时候不知道10.244.3.17对应的MAC地址,所以cni0会发ARP广播给整个二层网络。ARP广播通过veth2e303920到达web-1的eth0,web-1会把自身的MAC地址回复到consul-0容器。
- 发数据包
1. 同ARP广播流程,consul-0发数据包通过eth0到veth6a98119e,根据cni0缓存的CAM查询到端口为veth2e303920,数据包流量就进入到了web-1.
**宿主机访问容器**
```
[root@k8s-node3 ~]# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default gateway 0.0.0.0 UG 100 0 0 ens192
10.244.3.0 0.0.0.0 255.255.255.0 U 0 0 0 cni0
```
宿主机访问10.244.3.40,通过cni网关过veth pair到达consul-0的eth0。
**容器访问宿主机**
容器consul-0访问宿主机,数据包通过cni0网桥出现在宿主机上。