在 kubernetes 网络原理(0) - 网络知识预备 和 kubernetes 网络原理(1) - 环境预备 & 初窥网络 中我们将基础的知识已经知悉,我们就来看看我们的网络通讯。
我们已知道 Kubernetes
的逻辑架构如下:
¶Container <-> Container
在Kubernetes
中我们知道一个 Pod
由多个 Container
构成,而在 Pod
内的Container
和Container
的通讯是通过 localhost
这个虚拟独立出来的 namespace
。
我们来做个实验确认下。
我们使用如下的 yaml
部署一个 Pod
1 | apiVersion: v1 |
我们使用如下脚本进入系统内部
1 | kubectl exec c2c-network-demo -c curl-client -it bash |
我们先看看我们的网卡信息
1 | root@c2c-network-demo:/# ip a |
我们发现了我们有 3
张网卡,分别是 lo
,tunl0
,eth0
,我们监听下我们的 lo
1 | root@c2c-network-demo:/# tcpdump -i lo |
1 | 08:08:42.491989 IP localhost.51366 > localhost.8080: Flags [S], seq 350716622, win 43690, options [mss 65495,sackOK,TS val 196496407 ecr 0,nop,wscale 7], length 0 |
切换监听另外一个 eth0
1 | root@c2c-network-demo:/# tcpdump -i eth0 |
我们发现并没有任何的输出,(虽然如同一个废话)
¶Pod <-> Pod
¶嗅探蛛丝马迹
因为在一个 Pod 内的通讯是简单的,我们来看看我们我们下面需要去进阶的一个网络,Pod
和 Pod
之间的通讯。
现在我们就想知道 Pod
和 Pod
之间他们是怎么通讯的。
在容器内进行 ip a
的时候,我们发现除了 lo
的回环地址之外,就还有一个我们所熟悉的 eth0
网卡,而这个网卡的IP
也显得颇为特别。192.168.1.10/32
,我们在定位下这个 POD 所在的机器
1 | $ kubectl get pods -o wide |
还记得 k8s-worker-1
这个机器的 Tun0
的 IP
是 192.168.1.1
,Wow,我们发现 Pod
的 IP 和Tun0
的 IP
在同一个网段中。我们在 c2c-network-demo
检查下网络状态。
1 | root@c2c-network-demo:/# route -n |
我们可以发现我们网络包的网关是一个 169.254.1.1
的私有地址,实际上应该也不对应任何的设备,从路由表中可以得到的信息是,我们所有的数据包都会从 eth0
的网卡发出去。
我们新起一个 pod
尝试访问下我们的 echo-server
1 | apiVersion: v1 |
我们在新启动的 test-tools
中检查下网络状态
1 | root@test-tools:/# ip a |
不出意外的话,我们可以看的出来 192.168.1.12/32
和上述的 192.168.1.10/32
看起来就像是在同一个网段内,子网掩码是32
又在无处的命中我们的内心,他们的确是隔离的网络,我们来看看这两个网络怎么相通吧。
-
Ping 一下,是成功的网络是相通
1
2
3
4root@test-tools:/# ping 192.168.1.10
PING 192.168.1.10 (192.168.1.10): 56 data bytes
64 bytes from 192.168.1.10: icmp_seq=0 ttl=63 time=0.270 ms
64 bytes from 192.168.1.10: icmp_seq=1 ttl=63 time=0.083 ms -
抓个包看看(上文已经知道出口是 eth0)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17# 请求一个HTTP
root@test-tools:/# curl 192.168.1.10:8080
<p>Hi from c2c-network-demo</p>
# 同时抓包网卡,没有获得什么有用的信息,网络是直接相通的
root@test-tools:/# tcpdump -i eth0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
03:21:20.695727 IP test-tools.33968 > 192.168.1.10.http-alt: Flags [S], seq 1375634196, win 28000, options [mss 1400,sackOK,TS val 235385958 ecr 0,nop,wscale 7], length 0
03:21:20.695831 IP 192.168.1.10.http-alt > test-tools.33968: Flags [S.], seq 2004093135, ack 1375634197, win 27760, options [mss 1400,sackOK,TS val 235385958 ecr 235385958,nop,wscale 7], length 0
03:21:20.695847 IP test-tools.33968 > 192.168.1.10.http-alt: Flags [.], ack 1, win 219, options [nop,nop,TS val 235385958 ecr 235385958], length 0
03:21:20.695904 IP test-tools.33968 > 192.168.1.10.http-alt: Flags [P.], seq 1:82, ack 1, win 219, options [nop,nop,TS val 235385958 ecr 235385958], length 81: HTTP: GET / HTTP/1.1
03:21:20.695916 IP 192.168.1.10.http-alt > test-tools.33968: Flags [.], ack 82, win 217, options [nop,nop,TS val 235385958 ecr 235385958], length 0
03:21:20.696182 IP test-tools.55118 > kube-dns.kube-system.svc.cluster.local.domain: 42450+ PTR? 10.1.168.192.in-addr.arpa. (43)
03:21:20.696341 IP 192.168.1.10.http-alt > test-tools.33968: Flags [P.], seq 1:18, ack 82, win 217, options [nop,nop,TS val 235385958 ecr 235385958], length 17: HTTP: HTTP/1.0 200 OK
03:21:20.714519 IP test-tools.35007 > kube-dns.kube-system.svc.cluster.local.domain: 29106+ PTR? 10.0.96.10.in-addr.arpa. (41)
03:21:20.715149 IP kube-dns.kube-system.svc.cluster.local.domain > test-tools.35007: 29106* 1/0/0 PTR kube-dns.kube-system.svc.cluster.local. (116)既然中间没有什么 TCP 的中继,那显然是通过路由表实现这样的功能,我们再来看看路由是怎么跳的。
没有发现什么内容,显然如果就这么放弃显然也为之过早,我们回到宿主机上检查下。
1 | ➜ ~ ip a |
再次执行 ip link type veth
1 | 5: cali0005aea454a@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1440 qdisc noqueue state UP mode DEFAULT group default |
我们发现了我们其实多了一些 veth
,让我们嗅到了一些蛛丝马迹的感觉,我们知道veth
设备总是成对出现的。那我们eth0
的关联的又是哪一个虚拟网卡呢?我们借助ifindex
这个全局唯一的信息来查看。
在容器内执行如下操作:
1 | root@test-tools:/# cat /sys/class/net/eth0/iflink |
我们再回到宿主机上:
1 | ➜ ~ grep -l 13 /sys/class/net/cali*/ifindex |
我们发现了容器内的 eth0
绑定到了 calid9d486e54a8
这个虚网卡上了。
现在我们知道所有的网卡设备的网络请求都通过 容器的eth0
<-> 宿主机 calid9d486e54a8
上。
¶Pod 的通讯
我们现在对 calid9d486e54a8
抓个包,可以轻易获得数据流量,也验证了我们上述的证明事情。
1 | ➜ ~ tcpdump -i calid9d486e54a8 |
那这个数据到了 calid9d486e54a8
之后又是怎么扭转的呢?既然IP
没有任何改变,应该是通过路由表实现的。
我们查询下路由表
1 | ➜ ~ route -n |
因为我们的 dest ip
是 192.168.1.12
,显而易见的我们命中了
1 | 192.168.1.12 0.0.0.0 255.255.255.255 UH 0 0 0 calied9d42cb137 |
我们现在的网络显然就是这样的:
轻而易举的可以补全这个图: