K8S 的网络特征:
- 每个POD 一个IP (IP peer POD)
- 所有POD 通过IP 直接访问其他POD 而不管POD 是否在同一台物理机上
- POD 内的所有容器共享一个LINUX NET NAMESPACE (网络堆栈), POD 内的容器, 都可以使用localhost 来访问pod 内的其他容器.
K8S 对集群网络的要求:
- 所有容器都可以在不用NAT 的方式下访问其他容器
- 所有节点都可以在不用NAT的方式下同所有容器通信,反之亦然
- 容器的地址和别人看到的地址是同一个地址
kubernetes 网络实现
POD 间通信网络模型
NODE 间通信网络模型
ip1 ip2 都存在 etcd中
K8S 不同node 中pod 相互通信需要满足的条件如下
- 整个K8S集群中的POD IP 分配不能有冲突
- 找到一种办法,将 POD 的 IP 和所在的 NDOE 的 IP 关联起来, 通过这个关联让 POD 相互访问
条件1 要求NODE 中的docker0 的网桥地址不能冲突
条件2 要求 POD 中的数据在出发时,需要有一个机制能够知道对方 POD 的 IP 地址在哪个NODE上
满足条件的扁平化网络拓扑如下
默认docker0 的网络为 172.17.0.0/16 的网段. 每个容器都在这个子网内获得 IP 并且将 docker0 作为网关
docker 宿主机不需要知道任何关于docker 0 的信息, 因为docker 宿主机对任何容器发出的数据,在物理卡上都做了 IP 伪装(masquerade 隐含nat),也就是说其他任何node看到的数据包来源都是宿主机的物理网卡IP
这个模型的缺点是, 需要使用nat技术
K8S 模型中,每个 NODE 上的 docker0 都是可以被路由到的, 也就是说, 在部署一个 POD 时, 在同一个集群内, 各个主机都可以访问其他主机上的 POD IP, 并不需要在主机上做端口映射.
我们可以把NODE 看作交换机网络模型看起来就是下面这个样子
在node中,我们目前采用直接路由的方式来实现.在每个node上配置讲台路由
例如在192.168.1.10 上配置
route add -net 10.1.20.0 netmask 255.255.255.0 gw 192.168.1.20
route add -net 10.1.30.0 netmask 255.255.255.0 gw 192.168.1.30
复制代码
当我们启动一个POD ,要求POD 下的所有容器都使用同一个网络命名空间,以及同一个IP,所以必须要使用容器网络的 container 模式. 如果将所有 pod 中的容器做成一个链的结构, 中间任何一个容器出问题, 都会引起连锁反映, 所以在每个 POD 中都引入一个 google_containers/pause 其他容器都链接到这个容器, 由 google_containers/pause 来负责端口规划和映射
POD 内部的网络模型为
pause 容器用于接管pod的endpoint.
通过docker inpsect <id> | grep NetworkMod
查看pause 容器的网络模式,可以看到使用的是bridge 而 业务容器 docker inpsect < 业务容器id> | grep NetworkMod
使用的是 container:<长ID>
Service 的网络信息
当在K8S中创建一个service(非 NODEPORT) 之后, K8S 会为每个 service 分配一个cluster IP
roger@microk8s:~$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default-http-backend ClusterIP 10.152.183.69 <none> 80/TCP 11d
http-svc ClusterIP 10.152.183.164 <none> 80/TCP 11d
复制代码
IP 地址段为 apiserver 启动时, --server-cluster-ip-range 所指定的 IP 段,这个 IP 段不能和 docker0 的 IP 段冲突, 这个网段不会在 物理网络和 docker0 之间路由. 这个portal network 的意义是让容器流量都指向默认的网关,也就docker0
查看iptables-save 数据
:KUBE-POSTROUTING - [0:0]
...
-A KUBE-PORTALS-CONTAINER -d 10.152.183.69/32 -p tcp -m comment --comment "default/default-http-backend:" -m tcp --dport 80 -j REDIRECT --to-ports 37853
-A KUBE-PORTALS-CONTAINER -d 10.152.183.164/32 -p tcp -m comment --comment "default/http-svc:http" -m tcp --dport 80 -j REDIRECT --to-ports 35667
-A KUBE-PORTALS-CONTAINER -d 10.152.183.1/32 -p tcp -m comment --comment "default/kubernetes:https" -m tcp --dport 443 -j REDIRECT --to-ports 40441
...
-A KUBE-PORTALS-HOST -d 10.152.183.69/32 -p tcp -m comment --comment "default/default-http-backend:" -m tcp --dport 80 -j DNAT --to-destination 192.168.10.5:37853
-A KUBE-PORTALS-HOST -d 10.152.183.164/32 -p tcp -m comment --comment "default/http-svc:http" -m tcp --dport 80 -j DNAT --to-destination 192.168.10.5:35667
-A KUBE-PORTALS-HOST -d 10.152.183.1/32 -p tcp -m comment --comment "default/kubernetes:https" -m tcp --dport 443 -j DNAT --to-destination 192.168.10.5:40441
可以发现, 到三个服务的流量都被重定向到一个随机端口, 37853, 35667, 40441 . 这几个端口都是由kube-proxy 创建的, kube-proxy 服务会为每个创建的service 都关联一个随机端口,并监听那个特定的端口, 为服务创建相关联的负载均衡.
注意, node3 的kubeproxy 并未参与此次交互. node1 的kube-proxy 起到了负载均衡的作用