K8S pod 网络

K8S 的网络如下,POD 的网络是 Overlay 网络,意思是在现有网络上构建一个网络。就像图里的,只有 K8S 节点才能访问 10.244.0.0/16 这个网络,其他机器访问就会走自己默认路由最后路由出去而不会进到 POD 网络。

而 cni0 是 K8S 的 CNI plugin 接口规范,容器运行时并不是只有 docker ,还有很多其他的容器运行时实现,要求 pod 的容器 veth 都挂在 cbr0 下而不限制在 docker0 下,也就是 cni0 网桥。

K8S 的 POD 就是 >=1 个的容器,先创建 pause 这个 sandbox 容器,然后其他的容器 --net container:<pause_id> 附加上去。

Service 工作原理

K8S Service 就是在节点上访问 ServiceIP:ServicePort DNAT 成应用真实副本 POD_IP:POD_PORT 就像下面

而 K8S service 相关工作进程和大体工作流程如下

  • kubelet:增删改 POD ,并且对 POD 做探针请求,http、tcp、exec ,如果探针失败认为 POD 不健康,上报 kube-apiserver
  • kube-proxy 监听到 POD 就绪、删除、不健康后,会更新到本节点上的 iptables/ipvs 规则

查看当前节点 kube-proxy 模式可以通过下面命令查看,iptables 和 ipvs 模式各有优缺点和 bug,按需选择。

$ curl localhost:10249/proxyMode
iptables

Service 虽然工作在内核态的四层(TCP/UDP/STCP)负载均衡,但是还是需要 IP 地址(因为是四层拦截,IP 不会被路由,所以 Service IP 也被称为虚拟 IP,VIP),官方一些教程默认的 CIDR 是 10.96.0.0/12,自行更改的话注意子网计算,例如 10.95.0.0/12 实际上是在 10.80.0.0/12 里,kube-apiserver 启动时候会创建 Service CIDR 第一个主机位的 IP 的 Service:

$ kubectl describe svc kubernetes
Name:              kubernetes
Namespace:         default
Labels:            component=apiserver
                   provider=kubernetes
Annotations:       <none>
Selector:          <none>
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.96.0.1
IPs:               10.96.0.1
Port:              https  443/TCP
TargetPort:        6443/TCP
Endpoints:         192.168.2.111:6443,192.168.2.112:6443,192.168.2.113:6443
Session Affinity:  None
Events:            <none>

Service 后端是 Endpoints,而 Endpoint 的 IP 一般是 POD_IP 或者类似 kubernetes 这样的机器 IP ,以及如果你想创建类似把外部 IP 映射到内部的 service 域名,可以创建不指定 selector 的同名 service 和 endpoint。另外不一定要走 Service,很多服务有注册发现机制,把 Pod_IP:Port 注册上去,其他业务直接使用它来连接。

注意事项

  • POD 访问自己的 service 会不通(特别是在一些其他人或者云上的 K8S 实例上),需要配置 cni0 为混杂模式或者 kubelet 配置 hairpinMode
  • SVC 负载还得看应用层,比如 GRPC (基于 HTTP/2,只会一次 TCP 握手)会因为长连接而在 SVC 下不会均衡在每个 POD 上
  • 每个节点最好安装 conntrack-tools 让有 conntrack 二进制命令,kube-proxy 会使用它做一些操作

iptables Service 模式

iptables 模式下规则为以下几类

  • KUBE-SERVICES(nat.PREROUTING/nat.OUTPUT):在 PREROUTING 和 OUTPUT 链的最开始,它的规则分为两类:
    • -d SVCIP ... --dport Port -j KUBE-SVC-xxx 将 SVC_IP:PORT 发放对应的
    • -m addrtype --dst-type LOCAL 将本地网卡的数据包分派到 KUBE-NODEPORTS 链
  • KUBE-NODEPORTS:根据 dst-port 匹配 NodePort 端口
    • 数据包进入相应的 KUBE-SVC-xxx 链(externalTrafficPolicy=Cluster)
    • 数据包进入相应的 KUBE-XLB-xxx 链(externalTrafficPolicy=Local)
  • KUBE-SVC-xxx: 对应 service,数据包将随机进入 KUBE-SEP-xxx 链
  • KUBE-XLB-xxx: 对应 service,数据包可能进入 KUBE-SEP-xxx 链或者被丢弃
  • KUBE-SEP-xxx: 对应 endpoint 中的 IP 地址,数据包将 DNAT 到 Pod IP
  • KUBE-FIREWALL(filter.INPUT/filter.OUTPUT):丢弃 0x8000 的包,主要用在 externalTrafficPolicy=Local 的场景
  • KUBE-MARK-MASQ:标记数据包为 0x4000(需要SNAT)
  • KUBE-MARK-DROP:标记数据包为 0x8000(DROP包)
  • KUBE-POSTROUTING(nat.POSTROUTING):MASQUERADE 0x4000 的包

service 一般不会出问题,所以会查 iptables 规则和看就行了,上面的 SERVICE 和 MARK 、KUBE-POSTROUTING 几个实际在 ipvs 里也使用了。

  • 无标签
写评论...