K8s 架构大拆解:控制面与数据面到底在聊什么?
Kubernetes(K8s)已经成为云原生时代的操作系统。当我们部署一个Pod时,背后是一系列精密组件在协同工作。你是否曾好奇,kubectl apply -f pod.yaml 这个简单的命令背后,控制面的kube-apiserver和数据面的kubelet究竟进行了怎样一番“对话”?本文将深入K8s腹地,拆解控制面与数据面的通信机制,揭示集群内部协调工作的核心协议。
一、 核心架构总览:谁在控制,谁在执行?
首先,我们必须清晰区分K8s的两大平面:
- 控制面 (Control Plane): 集群的“大脑”和“指挥中心”。负责接收用户指令,维护集群的期望状态(如:应该有3个Nginx副本),并做出调度决策。核心组件包括:
- kube-apiserver: 集群的唯一入口,所有内部、外部通信的中枢。
- etcd: 集群的“记忆中枢”,持久化存储所有集群数据(如Pod、Service、ConfigMap等对象)。
- kube-scheduler: 调度器,决定Pod应该运行在哪个节点上。
- kube-controller-manager: 运行各种控制器(如Deployment控制器、Node控制器),驱动集群当前状态向期望状态收敛。
- 数据面 (Data Plane): 集群的“四肢”和“执行单元”。负责在具体的节点(Node)上运行容器,处理实际的数据流量。核心组件包括:
- kubelet: 节点上的“代理”,负责与
kube-apiserver通信,管理本节点Pod的生命周期(创建、销毁、监控)。 - kube-proxy: 节点上的网络代理,负责实现Service的负载均衡和网络规则。
- 容器运行时 (如 containerd/docker): 真正负责运行容器的引擎。
- kubelet: 节点上的“代理”,负责与
核心通信模式: 几乎所有通信都遵循 “控制器模式” 和 “声明式API”。用户或控制器向kube-apiserver声明一个期望状态,kube-apiserver将其存入etcd。随后,各个控制器和kubelet持续观察(Watch) 相关资源的变化,并采取行动,使现实世界(容器状态)与声明的期望状态保持一致。
二、 核心对话场景一:Pod的创建之旅
让我们跟随一个nginx Pod的创建请求,看看控制面和数据面如何“聊天”。
1. 用户发起请求
kubectl apply -f nginx-pod.yaml
kubectl将YAML内容转换为JSON,通过HTTPS REST API发送给kube-apiserver。
2. kube-apiserver 的验证与存储
kube-apiserver是守门人,它执行:
- 认证 (Authentication): 确认你是合法用户(Token、证书等)。
- 鉴权 (Authorization): 确认你有权限创建Pod(RBAC)。
- 准入控制 (Admission Control): 对请求进行修改或验证(如注入Sidecar、检查资源配额)。
- 通过所有检查后,它将Pod对象的期望状态写入
etcd。
此时,Pod在etcd中的记录状态为 Pending。
3. kube-scheduler 的介入(调度)
scheduler作为一个控制器,通过kube-apiserver的 Watch机制,发现有一个nodeName为空的Pod被创建。
- 它执行调度算法(过滤、打分),选择一个最优节点(如
node-01)。 - 对话内容:
scheduler向kube-apiserver发送一个 PATCH请求,更新Pod对象的nodeName字段为node-01。 kube-apiserver将这次更新再次写入etcd。
4. kubelet 的认领与执行(关键对话)
运行在node-01上的kubelet同样通过Watch机制,发现有一个Pod被调度到了自己管理的节点上。
- 对话发起方:
kubelet。 - 对话内容:
kubelet调用kube-apiserver的API,获取该Pod的详细定义(Spec)。 - 执行动作:
kubelet根据Pod Spec,开始在本节点工作:- 如果不存在,拉取镜像(可能从私有仓库,涉及
imagePullSecrets)。 - 通过CRI(容器运行时接口)调用
containerd或docker创建容器。 - 通过CNI(容器网络接口)调用网络插件(如Calico、Flannel)为Pod配置网络。
- 挂载存储卷(通过CSI)。
- 如果不存在,拉取镜像(可能从私有仓库,涉及
- 状态汇报: 容器启动后,
kubelet持续监控容器健康状态,并周期性地通过kube-apiserver的API 更新Pod的状态(Status)(如Running、Ready),kube-apiserver将其写入etcd。
至此,一个Pod从“期望”变成了“现实”。整个过程的核心是kube-apiserver作为消息总线,etcd作为状态存储,各组件通过Watch和Update进行异步协作。
三、 核心对话场景二:Service与网络流量转发
Pod创建好了,如何被访问?这就涉及到kube-proxy与kube-apiserver的对话。
1. Service的创建
用户创建一个ClusterIP类型的Service,kube-apiserver将其存入etcd。
2. kube-proxy 的监听与规则下发
每个节点上的kube-proxy组件Watch Service和Endpoint(由kube-controller-manager根据Pod创建)的变化。
- 对话内容:
kube-proxy从kube-apiserver获取全量的Service和Endpoint列表。 - 执行动作: 根据配置的模式(iptables或ipvs),在本节点配置相应的网络转发规则。
- iptables模式示例: 当访问
10.96.0.10:80(Service IP) 时,iptables规则会将其DNAT(目的地址转换)到某个具体的Pod IP(如172.16.1.2:80)。
- iptables模式示例: 当访问
# 在节点上查看kube-proxy为某个Service生成的iptables规则示例
sudo iptables -t nat -L KUBE-SERVICES | grep -A 2 “my-nginx-svc”
# 输出可能类似于:
# KUBE-SVC-XXXXXX tcp -- anywhere 10.96.0.10 /* default/my-nginx-svc:http cluster IP */ tcp dpt:http
# KUBE-SEP-YYYYYY all -- anywhere anywhere /* default/my-nginx-svc:http */ statistic mode random probability 0.33333333349
# KUBE-SEP-ZZZZZZ all -- anywhere anywhere /* default/my-nginx-svc:http */ statistic mode random probability 0.50000000000
关键点: kube-proxy与kube-apiserver的对话是拉取式的,它获取规则后,在本地节点独立配置,不参与具体的数据包转发。数据包转发由Linux内核的netfilter(iptables)或IPVS模块完成。
四、 通信协议与安全机制
它们到底用什么“语言”聊天?
- 主要协议: HTTPS/gRPC
- 外部通信 (kubectl -> apiserver): 使用基于TLS的 HTTPS REST API。这是最通用的接口。
- 内部组件通信: 为了高性能,大量使用 gRPC over HTTPS。例如
kubelet与kube-apiserver的Watch连接、etcd集群内部通信等。gRPC基于HTTP/2,支持流式传输,非常适合Watch这种长连接、持续推送的场景。
- 认证与授权
- ServiceAccount: Pod内部进程访问
kube-apiserver的凭证。每个Namespace有一个默认的defaultServiceAccount。kubelet使用其所在节点的凭证。 ```yamlPod spec中指定ServiceAccount
apiVersion: v1 kind: Pod metadata: name: my-pod spec: serviceAccountName: my-sa # 指定使用的ServiceAccount containers:
- name: app image: my-app ```
- RBAC: 定义
Role和RoleBinding,精细控制哪个ServiceAccount或User能对哪种资源(Resource)进行何种操作(Verb)。
- ServiceAccount: Pod内部进程访问
- 关键配置文件: kubeconfig
kubectl和许多组件通过kubeconfig文件定位kube-apiserver并提供认证信息。 ```yaml~/.kube/config 简化示例
apiVersion: v1 clusters:
- cluster: certificate-authority-data:
# 验证apiserver证书 server: https://api-server:6443 # apiserver地址 name: my-cluster contexts: - context: cluster: my-cluster user: admin-user name: my-context current-context: my-context users:
- name: admin-user user: client-certificate-data: <客户端证书> # 客户端身份 client-key-data: <客户端私钥> ```客户端私钥>客户端证书>
- cluster: certificate-authority-data:
五、 总结与最佳实践
K8s控制面与数据面的“聊天”本质是:以kube-apiserver为中心,以etcd为状态真相源,通过声明式API和Watch机制驱动的异步协调系统。
核心要点:
- 唯一真相源:
etcd存储期望状态,任何组件都不应绕过kube-apiserver直接修改它。 - 水平解耦: 组件各司其职,通过API交互,便于独立升级和扩展。
- 自我修复: 控制器不断比较期望状态与实际状态,并驱动系统向期望状态收敛。
运维启示:
- 保护
kube-apiserver和etcd: 它们是集群的命脉,需确保其高可用、高性能和安全。 - 监控关键组件的通信健康: 关注
kubelet的NodeReady状态、etcd的写入延迟、kube-apiserver的请求错误率。 - 理解网络模式: 根据集群规模选择
kube-proxy的iptables或ipvs模式,并确保CNI插件稳定。
通过理解这场持续的“对话”,我们不仅能更深入地运维K8s集群,也能更好地设计基于K8s的云原生应用,明白应用部署、服务发现和故障恢复背后的深层逻辑。