Kubernetes的云厂商集成模型,从内置驱动到外置Cloud Controller Manager
cloud-provider 指的是 Kubernetes 与云平台之间的那一层适配:节点要有区域/机型信息、LoadBalancer 类型的 Service 要真的开出一个云负载均衡、跨节点 Pod 流量要走云路由。这些能力曾经内置在 Kubernetes 核心里(in-tree),现在则全部外置为 Cloud Controller Manager(CCM)。
这是一次跨度数年的大迁移,代号 KEP-2395,官方称之为「Kubernetes 历史上最大规模的迁移」——删掉了约 150 万行代码,核心组件二进制体积缩小约 40%。理解这段历史,才能读懂今天各种「节点一直不 Ready」「LoadBalancer 一直 Pending」的报错。
1.26 内置 OpenStack 驱动移除
1.27 内置 AWS 驱动移除
1.29 DisableCloudProviders 与 DisableKubeletCloudCredentialProviders
两个特性门控默认值改为 true —— 内置驱动【默认全部失效】
需要显式把它们设回 false 才能继续用旧的内置驱动(临时兜底)
1.31 内置云驱动从核心组件中【永久禁用并移除】
此后只有 external 一种模式
1.33 DisableCloudProviders / DisableKubeletCloudCredentialProviders
两个已 GA 的特性门控被删除
kube-apiserver 的 --cloud-provider 参数被移除,传入会直接启动失败
配套撤离的还有三个子系统:
Cloud Controller Manager KEP-2392 替代 kube-controller-manager 与 kubelet 里的云逻辑
API Server Network Proxy KEP-1281 替代 apiserver 到节点的 SSH 隧道
kubelet 凭据提供者插件 KEP-2133 替代 kubelet 内置的 ECR/GCR/ACR 镜像拉取凭据获取
CSI 迁移 KEP-625 替代内置的云盘卷插件
今天的现实是:--cloud-provider 只接受空字符串或 external。 传 aws、gce、azure 这类值在 kubelet 与 kube-controller-manager 上都是非法的。
CCM 是与 kube-controller-manager 平行的独立二进制,由云厂商各自维护和发布。它可以包含四种控制器:
cloud-node 节点控制器
为新节点填上云侧信息(区域、机型、内网/外网 IP)
校验节点在云上是否还存在,不存在就删除 Node 对象
初始化完成后【移除初始化污点】
cloud-node-lifecycle 节点生命周期控制器
按云侧状态决定是否驱逐 / 删除节点
service Service 控制器
为 type=LoadBalancer 的 Service 创建云负载均衡
同步 status.loadBalancer.ingress
route 路由控制器
配置跨节点 Pod 流量的云路由
或分配 Pod 网段
CCM 自身的运行要求:
- 与云 API 的认证(AK/SK、IAM 角色、托管身份……)
- 与 kube-apiserver 的 RBAC 授权
- 高可用:默认开启 leader election,多副本只有一个在工作
- 通常以 Deployment 形式跑在 kube-system 里
所需的 RBAC 权限大致是:
Node 资源的完全读写(节点控制器)
Node 的只读(路由控制器)
Service 的 list/get/watch + services/status 的 patch/update
Events 的 create/patch/update
ServiceAccount 的 create
这是 CCM 缺席时最典型的症状来源。任何设置了 --cloud-provider=external 的组件,在节点初始化时都会加上这个污点:
node.cloudprovider.kubernetes.io/uninitialized:NoSchedule
含义是「这个节点还需要外部控制器做第二次初始化」,在此期间不会被调度任何工作负载。移除它的正是 CCM 的节点控制器。
# 查看节点上的污点
kubectl describe node <node-name> | grep -A5 Taints
kubectl get node <node-name> -o jsonpath='{.spec.taints}'
# 典型症状:新节点永远 Pending 不了 Pod,describe 里看到上面这个污点
CCM 自己也必须容忍这个污点,否则它无法在自己初始化的节点上运行:
tolerations:
- key: node.cloudprovider.kubernetes.io/uninitialized
value: "true"
effect: NoSchedule
kubelet 与 kube-controller-manager 侧:
--cloud-provider=external 只有这个值有意义(空字符串表示不用云集成)
--cloud-config=<path> 云厂商配置文件路径(部分 CCM 仍需要)
kube-apiserver 侧已无此参数:1.31 起不再生效,1.33 起彻底移除,继续传会直接让 apiserver 启动失败。
以 kubeadm 集群为例,给 kubelet 追加参数走 systemd drop-in:
sudo vi /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
Environment="KUBELET_EXTRA_ARGS=--cloud-provider=external"
sudo systemctl daemon-reload
sudo systemctl restart kubelet
cloud.conf(以 OpenStack 为例)形如:
[Global]
auth-url = https://keystone.example.com:5000/v3
username = kubernetes
password = <password>
tenant-name = my-project
region = RegionOne
[LoadBalancer]
subnet-id = <subnet-uuid>
AWS 的 CCM 则习惯用 --cloud-config 指向一个只含 [global] 段的配置,认证走节点 IAM 角色或 IRSA。
kubernetes/cloud-provider-aws 是 AWS 的官方外置实现,主要产出 aws-cloud-controller-manager:
- 负责 ELB/NLB 的创建与回收
- 负责节点初始化与 region/zone 标签
- 通常以 DaemonSet 或 Deployment 部署在 kube-system
- 需要节点角色具备 ELB、EC2 描述等权限
- 在 EKS 上该组件由托管控制平面提供,自建集群才需要自己部署
配置与部署方式见其仓库的 Helm chart,常用参数:
--cloud-provider=aws
--cloud-config=/etc/kubernetes/cloud-config
--use-service-account-credentials=true
--leader-elect=true
# 1. 节点是否被初始化
kubectl get node <node-name> -o jsonpath='{.spec.taints}'
# 还带着 node.cloudprovider.kubernetes.io/uninitialized → CCM 没工作
# 2. CCM 是否在跑
kubectl get pods -n kube-system | grep cloud-controller-manager
kubectl logs -n kube-system <ccm-pod> -f
# 3. Service 是否拿到 LB
kubectl get svc <name> -o yaml | grep -A10 "status:"
kubectl describe svc <name> | grep -A10 Events
# 4. 节点上的云标签是否写上了
kubectl get node <node-name> --show-labels | tr ',' '\n' | grep -i "topology\|instance-type\|zone"
--cloud-provider=aws、kube-controller-manager 写 --cloud-provider=azure 的做法,在 1.29+ 会直接报错退出。只有 external 是合法值,而且必须真的部署了对应的 CCM。--cloud-provider 参数已被移除。1.33 起传入该参数会让 kube-apiserver 直接启动失败(unknown flag)。从旧版本升级时,要先清理启动脚本、systemd 单元与静态 Pod 清单里的这个参数。DisableCloudProviders 与 DisableKubeletCloudCredentialProviders 在 1.33 被移除,旧清单里写 --feature-gates=DisableCloudProviders=false 会直接报「无法识别的特性门控」。--image-credential-provider-config 与 --image-credential-provider-bin-dir)获取。老参数如 --azure-container-registry-config 已废弃。--cloud-provider=external,最后逐节点重启。顺序反过来会出现节点暂时无法初始化。cloud-provider: external 必须配到所有节点。包括控制平面节点。漏配的节点不会走云初始化,cluster-autoscaler 之类的组件会因节点缺少云侧标识而无法正确匹配实例,表现为伸缩行为异常。external 不是「更高级的内置驱动」。它意味着「我不用内置逻辑了,请外部组件接手」。设了这个值却没部署 CCM,比不设更糟 —— 节点会带着污点永远起不来。kubelet — 需要 --cloud-provider=external 交由 CCM 初始化kube-apiserver — 其 cloud-provider 参数已于 1.33 移除csi — 取代内置云盘插件的存储接口crictl — 排查 CCM 容器kubeadm — 自建集群的引导与参数下发