Pod 作为 K8s 中一等公民,其承载了最核心的 Container(s) 的运行。同时,Pod 也是 K8s 中资源调度的最小单位,因此熟悉其初始化过程(包括网络、存储、运行时等)将会使我们更加深入理解 K8s 的容器编排原理,以期更好的服务各类业务。
1. 概述
Pod 作为 K8s 中一等公民,其承载了最核心的 Container(s) 的运行。同时,Pod 也是 K8s 中资源调度的最小单位,因此熟悉其初始化过程(包括网络、存储、运行时等)将会使我们更加深入理解 K8s 的容器编排原理,以期更好的服务各类业务。
Pod 初始化核心流程如下:
-
kube-apiserver 收到客户端请求(Controller 或 kubectl 客户端)后,创建对应的 Pod;
-
kube-scheduler 按照配置的调度策略进行 Pod 调度,选择最为合适的 Node 作为目标节点;
-
kubelet(运行于每个 Node 上的 K8s agent)Watch 监听到调度到所在节点的 Pod(s),开始真正创建 Pod;
-
由 CRI 首先创建出 PodSandbox,初始化对应的网络 net namespace,调用 CNI 获取 Pod IP;
-
接着 CRI 开始创建 Pod 中第一个 pause container,绑定到上一步创建的 net namespace 和 Pod IP;
-
接着由 CRI 依次创建和启动 Pod 中声明的 initContainers 和 containers 容器;
-
当所有的 containers 运行起来后,探针探测容器运行符合预期后,Pod 状态最终更新为 Running;
本文将从 K8s 中多种 IP CIDR、Pod 生命周期、kubelet 核心逻辑、CNI IPAM 分配 Pod IP、双协议栈(IPv4/IPv6)、IP 固定与回收等流程,说明 Pod IP 的分配机制。
本文基于 K8s v1.27,CRI 已移除 Dockershim。
2. K8s 中多种 IP
2.1 Pod IP CIDR
在 K8s 中最常见的 IP 类型就是 Pod IP,在初始化 K8s 集群的时候,通过 --cluster-cidr
参数控制 Pod IP CIDR 网段,所有 Pod 动态分配的 IP 都会落在此 CIDR 网段内。
具体参数控制如下: 通过 kube-controller-manager 组件的 --cluster-cidr
参数进行配置,根据集群规模一般会选择 16 位的网段来配置集群支持的 Pod IP CIDR 网段,如 10.0.0.0/16,理论上最大支持 2 ^ (32 - 16) = 65536 个 Pod IP 的分配。
【集群规模】可按需配置 Pod IP CIDR,K8s 官方支持的一个大集群(large cluster),最大支持约 5k Nodes、15w Pods。
2.2 Node CIDR
在通过 kube-controller-manager 组件的 --cluster-cidr
控制了 Pod IP 的 CIDR 网段后,首先会在集群中每个 Node 分配一个 subnet CIDR,他们都属于 --cluster-cidr
网段。
具体参数控制如下: 通过 kube-controller-manager 组件的 --allocate-node-cidrs=true
、--node-cidr-mask-size=24
参数控制每个 Node 节点的 subnet CIDR 子网段,这样落在每个 Node 上的 Pod 最大的可分配 IP 数量为 2 ^ (32 - 24) = 256 个,各云厂商会根据自己的网络策略,一般会预留一部分,最终可分配的 IP 一般为最大个数的一半 (128 个)。
【双协议栈】若开启了 dual-stack IP,则可通过
--node-cidr-mask-size-ipv4=24
、--node-cidr-mask-size-ipv6=64
分别控制 IPv4 和 IPv6 的 Node CIDR 子网大小。
在 K8s 标准集群中,通过 kubelet 组件的 --max-pods=110
控制了默认一个 Node 最大的 Pod 数量为 110 个。
2.3 Service IP CIDR
除了上面提到的 Pod IP CIDR 和 Node CIDR 外,K8s 中还有一类 Service IP CIDR,控制 Service 资源的 ClusterIP
网段范围。
具体参数控制如下: 通过 kube-apiserver 和 kube-controller-manager 组件的 --service-cluster-ip-range=10.96.0.0/12
控制 Service ClusterIP
的网段范围。
根据 Service Type 不同,除了 Headless Service
显式将 .spec.clusterIP=None
设置后,生成的 Service 将不会分配 ClusterIP,其他类型的 Service 则都会动态分配 ClusterIP。示例如下:
kubectl get svc -n demo
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
demo-clusterip ClusterIP 10.96.0.46 <none> 80/TCP 6d11h
demo-nodeport NodePort 10.96.0.25 <none> 80:31666/TCP 6d11h
demo-loadbalancer ClusterIP 10.96.0.250 11.234.50.12 80/TCP 153d
demo-headless ClusterIP None <none> 8080/TCP,80