Kubernetes 集群如何工作:控制平面与节点
让集群运转的各个组件,以及从 kubectl apply 到运行中的容器之间发生了什么。
Kubernetes 集群是一组相互协作的进程。了解每个进程做什么,会让其他一切,从调度到排障,都更容易推理。本指南先点出各个组件的名称,然后跟随一个请求一路走到运行中的容器。
控制平面与工作节点
控制平面负责对集群做出决策。工作节点运行你的工作负载。在 minikube 这样的本地集群中,一个节点同时扮演两种角色。生产集群通常有多个控制平面节点以保证可用性:如果你失去了唯一的一个,你就无法再更改集群中的任何东西,尽管已在运行的工作负载通常会继续运行一段时间。控制平面节点通常带有污点(taint),这样你的应用 Pod 就不会被调度到它们上面。
控制平面组件
- kube-apiserver 是前门。每个客户端(
kubectl、仪表板、脚本以及其他组件)都通过 HTTP API 与它通信。它负责认证和授权请求、验证对象,并且是唯一读写 etcd 的组件。 - etcd 是一个一致性的键值存储,保存集群的所有状态:存在哪些节点、应该运行哪些 Pod、它们的当前状态。把它视作集群的记忆。请备份它,因为失去它意味着失去对一切的跟踪。
- kube-scheduler 为每个尚未分配节点的 Pod 选择一个节点,依据的是资源请求、约束和可用容量。
- kube-controller-manager 运行各个控制器,即比较期望状态与实际状态并对差异采取行动的控制循环。Deployment、ReplicaSet 和 Node 控制器都在这里。
- cloud-controller-manager(仅在云服务商上)与服务商集成,处理负载均衡器和节点生命周期之类的事情。
节点组件
- kubelet 是每个节点上的代理。它监视分配到其节点的 Pod,确保它们的容器正在运行且健康,并把状态汇报回去。
- 容器运行时(container runtime) 实际运行容器。它通常是 containerd 或 CRI-O,通过容器运行时接口连接。Kubernetes 不再直接与 Docker Engine 通信(dockershim 已在 1.24 中被移除),但用 Docker 构建的镜像仍能运行,因为镜像遵循开放的 OCI 标准。
- kube-proxy 在每个节点上维护网络规则,使 Service 地址能够到达正确的 Pod。
- 网络插件(CNI) 为 Pod 提供 IP 地址以及跨节点的连通性。
跟随一个请求从 kubectl apply 到运行中的容器
假设你应用了一个 Deployment 清单。接下来会发生:
kubectl读取你的 kubeconfig,并通过 HTTPS 将清单发送给 API 服务器。- API 服务器对你进行认证和授权,验证对象,将其存入 etcd,并作出响应。
- Deployment 控制器注意到新的 Deployment 并创建一个 ReplicaSet,ReplicaSet 控制器随后创建 Pod 对象。此时 Pod 已经存在,但尚未分配到节点。
- 调度器注意到没有节点的 Pod,为每个 Pod 选择一个节点,并通过 API 服务器记录这一决定。
- 被选中节点上的 kubelet 看到分配给它的 Pod,并告诉容器运行时拉取镜像并启动容器。
- kubelet 将进展汇报回 API 服务器,后者将其存入 etcd。这正是
kubectl get pods读取的内容。
注意这些组件从不直接相互调用。每个组件都监视 API 服务器上它所关心的对象并做出反应。这种松耦合正是你可以重启大多数组件而不丢失任何东西的原因:它们所需要的状态都在 etcd 中。
你可以在 Kubernetes 记录的事件中看到这个序列:
kubectl create deployment demo --image=nginx:1.25
kubectl get events --sort-by=.metadata.creationTimestamp
查找 Scheduled、Pulling、Pulled、Created 和 Started。这些是调度器和 kubelet 在各自履行职责。
查看你自己集群中的组件
kubectl get nodes -o wide
kubectl get pods -n kube-system
在 minikube 和 kubeadm 构建的集群上,你会看到控制平面组件作为 Pod 运行在 kube-system 命名空间中,旁边还有 kube-proxy 和网络插件。在托管服务(EKS、GKE、AKS)上,服务商为你运行控制平面,你只会看到你的工作节点。
这种设计在实践中意味着什么
- API 服务器是咽喉要道。 一切都经过它,所以保护它并为它合理定容很重要。
- etcd 的健康就是集群的健康。 备份它,并在生产环境中冗余运行它。
- 失败是预料之中的。 宕机的节点、崩溃的组件或被删除的 Pod,只是期望状态与实际状态之间的一个差异,某个控制器最终会修复它。