Kubernetes-02 架构深度解析
Kubernetes 架构深度解析
系列第二篇。理解 K8s 的内部架构,是排查问题、优化性能、设计系统的基础。本篇将带你深入 K8s 的每个核心组件。
目录
1. 整体架构概览
K8s 集群分为两类节点:
┌─────────────────────────────────────────────────────────────────┐
│ Kubernetes 集群 │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Control Plane(控制平面) │ │
│ │ │ │
│ │ ┌────────────┐ ┌──────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │kube- │ │ │ │ kube- │ │ kube- │ │ │
│ │ │apiserver │ │ etcd │ │scheduler │ │controller│ │ │
│ │ │ │ │ │ │ │ │-manager │ │ │
│ │ └────────────┘ └──────┘ └──────────┘ └──────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────┼───────────────┐ │
│ ▼ ▼ ▼ │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ Node 1 │ │ Node 2 │ │ Node 3 │ │
│ │ │ │ │ │ │ │
│ │ ┌─────────┐ │ │ ┌─────────┐ │ │ ┌─────────┐ │ │
│ │ │ kubelet │ │ │ │ kubelet │ │ │ │ kubelet │ │ │
│ │ └─────────┘ │ │ └─────────┘ │ │ └─────────┘ │ │
│ │ ┌─────────┐ │ │ ┌─────────┐ │ │ ┌─────────┐ │ │
│ │ │kube- │ │ │ │kube- │ │ │ │kube- │ │ │
│ │ │proxy │ │ │ │proxy │ │ │ │proxy │ │ │
│ │ └─────────┘ │ │ └─────────┘ │ │ └─────────┘ │ │
│ │ ┌─────────┐ │ │ ┌─────────┐ │ │ ┌─────────┐ │ │
│ │ │Pod A │ │ │ │Pod C │ │ │ │Pod E │ │ │
│ │ │Pod B │ │ │ │Pod D │ │ │ │Pod F │ │ │
│ │ └─────────┘ │ │ └─────────┘ │ │ └─────────┘ │ │
│ └───────────────┘ └───────────────┘ └───────────────┘ │
└─────────────────────────────────────────────────────────────────┘
核心设计思想:
- Control Plane = 大脑,负责决策(调度到哪、启几个副本、做什么)
- Node = 手脚,负责执行(真正跑容器的地方)
- 所有组件通过 kube-apiserver 通信(没有组件直接互相调用)
2. Control Plane(控制平面)
2.1 kube-apiserver
地位:K8s 的核心枢纽,一切的入口。
kube-apiserver 是 K8s 唯一对外暴露的组件,提供 RESTful API。所有对 K8s 资源的操作(增删改查)都要经过它。
核心职责:
- 认证(Authentication):确认"你是谁"(证书/Token/OIDC 等)
- 鉴权(Authorization):确认"你能干什么"(RBAC)
- 准入控制(Admission Control):校验/修改请求(如自动注入 sidecar)
- 数据持久化:把资源写入 etcd
请求流程:
kubectl / client-go / curl
↓
kube-apiserver
├── 1. 认证(Authentication)
│ └── 证书验证 / Bearer Token / OIDC
├── 2. 鉴权(Authorization)
│ └── RBAC(Role-Based Access Control)
├── 3. 准入控制(Admission Control)
│ ├── Mutating Admission Webhook(修改资源)
│ └── Validating Admission Webhook(校验资源)
└── 4. 存储 → etcd
水平扩展: apiserver 是无状态的,可以部署多个实例,通过负载均衡对外提供服务。
实践:直接调用 API
# 启动一个代理,把 API Server 暴露到本地
kubectl proxy --port=8001 &
# 直接调用 REST API
curl http://localhost:8001/api/v1/namespaces/default/pods
# 查看所有 API 版本
curl http://localhost:8001/apis
API 版本说明:
/api/v1 → 核心 API(Pod、Service、ConfigMap、Secret 等)
/apis/apps/v1 → apps 组(Deployment、StatefulSet、DaemonSet)
/apis/batch/v1 → batch 组(Job、CronJob)
/apis/networking.k8s.io/v1 → 网络(Ingress、NetworkPolicy)
2.2 etcd
地位:K8s 的数据库,存储集群所有状态。
etcd 是一个分布式键值存储系统,使用 Raft 共识算法保证强一致性。
存储什么:
- 所有 K8s 对象(Pod、Deployment、Service 等的 YAML)
- 集群状态(节点信息、资源配额)
- 配置数据(ConfigMap、Secret)
只有 kube-apiserver 直接读写 etcd,其他组件通过 apiserver 间接操作。
数据格式:
key: /registry/pods/default/nginx-demo
value: {序列化后的 Pod 对象}
用 etcdctl 查看(了解即可):
# 查看所有 Pod 的 key
etcdctl get /registry/pods --prefix --keys-only
# 查看某个 Pod 的数据
etcdctl get /registry/pods/default/nginx-demo
Watch 机制: K8s 各组件通过对 etcd 的 Watch 来感知状态变化。
kube-scheduler watch Pod → 发现新创建的 Pod(没有 NodeName)→ 开始调度
kubelet watch Pod → 发现自己 Node 上有新 Pod → 创建容器
生产建议:
- etcd 单独部署,不与其他组件混用
- 至少 3 节点(Raft 需要超过半数存活)
- 定期备份(
etcdctl snapshot save) - SSD 存储,etcd 对 IO 延迟非常敏感
2.3 kube-scheduler
地位:决定 Pod 跑在哪个 Node 上。
当一个 Pod 被创建时,它最初没有 nodeName(没有被分配到任何节点)。Scheduler 监听这类"待调度的 Pod",通过一套算法选出最合适的 Node。
调度流程:
待调度 Pod
↓
1. Filtering(过滤):找出所有"可以"跑这个 Pod 的节点
├── 节点资源是否充足(CPU/内存)
├── 节点是否有 Pod 需要的标签(NodeSelector)
├── 节点的污点(Taints)和 Pod 的容忍(Tolerations)是否匹配
├── Pod 的亲和性/反亲和性规则
└── ...
↓
2. Scoring(评分):对过滤后的节点打分,选出最优节点
├── 资源均衡(选资源利用率低的节点)
├── 镜像亲和(节点上已有镜像,省去拉取时间)
├── 拓扑分布(打散到不同可用区)
└── ...
↓
3. Binding(绑定):更新 Pod 的 nodeName 字段,写入 etcd
亲和性示例:
spec:
affinity:
# Pod 亲和性:和含有 app=cache 标签的 Pod 调度到同一 Node
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- cache
topologyKey: kubernetes.io/hostname
# Node 亲和性:只调度到 region=us-east 的节点
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: region
operator: In
values:
- us-east
污点和容忍(Taints & Tolerations):
# 给节点打污点(不允许普通 Pod 调度上去)
kubectl taint nodes node1 dedicated=gpu:NoSchedule
# Pod 的容忍(允许调度到有该污点的节点)
spec:
tolerations:
- key: "dedicated"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"
2.4 kube-controller-manager
地位:K8s 的自动化管家,持续让实际状态趋近期望状态。
kube-controller-manager 是多个 Controller 的集合,运行在同一个进程中。每个 Controller 负责一类资源。
核心控制器:
| 控制器 | 职责 |
|---|---|
| Node Controller | 监控节点状态,节点不健康时驱逐 Pod |
| Deployment Controller | 管理 Deployment → ReplicaSet → Pod 的创建/更新/删除 |
| ReplicaSet Controller | 保证 Pod 副本数量符合 spec.replicas |
| StatefulSet Controller | 管理有状态应用的 Pod,保证顺序和稳定网络标识 |
| DaemonSet Controller | 确保每个(或指定)节点上都有一个 Pod 副本 |
| Job Controller | 管理一次性任务 |
| Endpoint Controller | 维护 Service 和 Pod 之间的 Endpoints 映射 |
| Namespace Controller | 处理 Namespace 的生命周期 |
| ServiceAccount Controller | 为新 Namespace 创建默认 ServiceAccount |
控制循环(Control Loop/Reconcile Loop):
这是 K8s 最核心的设计模式!
// 伪代码,展示控制循环的思想
for {
desired := getDesiredState() // 期望状态(来自 etcd)
actual := getActualState() // 实际状态(真实世界)
if desired != actual {
reconcile(desired, actual) // 调谐:让实际状态 → 期望状态
}
sleep(interval)
}
例如:
- ReplicaSet 期望 3 个 Pod,实际只有 2 个 → 创建 1 个
- Deployment 的镜像版本变了 → 触发滚动升级
- 节点宕机,Pod 消失 → 在其他节点重建 Pod
这就是声明式 API 的魔力:你只告诉 K8s 你想要什么,K8s 自己搞定怎么实现。
2.5 cloud-controller-manager
地位:对接云厂商 API,实现云原生集成。
将 K8s 核心代码与云厂商实现解耦。不同云厂商提供自己的实现:
- Node Controller:调用云 API 检查节点是否真的删除了
- Route Controller:在 VPC 中配置路由
- Service Controller:创建/更新/删除云负载均衡(如 AWS ELB、阿里云 SLB)
如果你在本地或自建集群,不需要关心这个组件。
3. Node 组件
Node(也叫 Worker Node)是真正运行工作负载的机器。每个 Node 上运行以下组件:
3.1 kubelet
地位:Node 上的代理人,负责管理该节点上的 Pod。
kubelet 是每个 Node 上必须运行的进程,它的核心职责:
- 向 apiserver 注册节点
- Watch 分配到本节点的 Pod
- 调用容器运行时创建/删除容器
- 执行健康检查(liveness/readiness/startup probe)
- 上报节点和 Pod 状态
# 查看 kubelet 日志(systemd 管理时)
journalctl -u kubelet -f
# 查看 kubelet 配置
kubectl get cm kubelet-config -n kube-system -o yaml
健康检查(Probes):
spec:
containers:
- name: my-app
image: my-go-app:v1
# 存活探针:失败则重启容器
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10 # 容器启动后等待 10s 才开始检查
periodSeconds: 5 # 每 5s 检查一次
failureThreshold: 3 # 连续失败 3 次才重启
# 就绪探针:失败则从 Service 的 Endpoints 中移除(不再接收流量)
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
# 启动探针:防止慢启动应用被 liveness 误杀
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 30 # 最多等待 30 * 10 = 300s 启动
periodSeconds: 10
在 Go 应用中实现健康检查接口:
package main
import (
"net/http"
"sync/atomic"
)
var ready atomic.Bool
func main() {
// 启动时未就绪
ready.Store(false)
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
})
http.HandleFunc("/ready", func(w http.ResponseWriter, r *http.Request) {
if ready.Load() {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ready"))
} else {
w.WriteHeader(http.StatusServiceUnavailable)
w.Write([]byte("not ready"))
}
})
go func() {
// 初始化完成后设置就绪
initApp()
ready.Store(true)
}()
http.ListenAndServe(":8080", nil)
}
3.2 kube-proxy
地位:实现 Service 的网络代理和负载均衡。
kube-proxy 运行在每个节点上,负责维护网络规则,使得 Service 的虚拟 IP(ClusterIP)能够正确转发到后端 Pod。
实现模式(三种):
1. iptables 模式(默认)
客户端请求 → Service ClusterIP:Port
↓
iptables 规则(kube-proxy 维护)
↓ 随机选择一个后端 Pod
目标 Pod IP:Port
kube-proxy 监听 Service 和 Endpoints 变化,动态更新 iptables 规则。
2. IPVS 模式(高性能,推荐生产使用)
IPVS(IP Virtual Server)是专门为负载均衡设计的内核模块,比 iptables 性能更好:
- 支持更多负载均衡算法(轮询、最少连接、哈希等)
- 规则操作是 O(1) 复杂度(iptables 是 O(n))
# 查看当前代理模式
kubectl get cm kube-proxy -n kube-system -o yaml | grep mode
3. nftables 模式(K8s 1.29+ beta)
iptables 的下一代替代品,性能更好。
3.3 容器运行时
负责实际创建和运行容器。
K8s 通过 CRI(Container Runtime Interface) 标准与容器运行时交互,与具体实现解耦。
kubelet → [CRI gRPC] → 容器运行时
├── containerd(最主流)
├── CRI-O
└── cri-dockerd(Docker 适配层)
containerd 架构:
kubelet
↓ CRI
containerd
↓ OCI
runc(实际创建 Linux 容器的工具)
↓
Linux namespaces + cgroups
查看节点上的容器(containerd):
# 需要在 Node 上执行,需要 crictl 工具
crictl ps # 列出容器
crictl images # 列出镜像
crictl logs <container-id> # 查看日志
4. 组件通信流程
所有组件都通过 kube-apiserver 通信,没有组件直接互相调用。
┌──────────────────────────────────────────────────────────────┐
│ kube-apiserver │
└───────────────────────────┬──────────────────────────────────┘
│ Watch / REST API
┌─────────────────┼─────────────────┐
▼ ▼ ▼
kube-scheduler controller-manager kubelet (各节点)
- Watch 未调度的 Pod - Watch 各类资源 - Watch 本节点的 Pod
- 选择节点 - 执行控制循环 - 管理容器生命周期
- 更新 nodeName - 维护期望状态 - 上报状态
认证通信: 所有组件都使用 TLS 客户端证书与 apiserver 通信,保证安全性。
5. 一次 Pod 创建的全链路
以 kubectl apply -f deployment.yaml 为例,追踪完整流程:
Step 1: kubectl
→ 解析 YAML → 发送 HTTP POST 请求到 kube-apiserver
Step 2: kube-apiserver
→ 认证(你是谁?)
→ 鉴权(你有权限创建 Deployment 吗?)
→ 准入控制(校验/修改 YAML)
→ 写入 etcd(存储 Deployment 对象)
→ 返回 201 Created
Step 3: Deployment Controller(in controller-manager)
→ Watch 到新 Deployment
→ 创建对应的 ReplicaSet 对象 → apiserver → etcd
Step 4: ReplicaSet Controller(in controller-manager)
→ Watch 到新 ReplicaSet
→ 发现需要 3 个 Pod,当前 0 个
→ 创建 3 个 Pod 对象(此时 Pod 没有 nodeName)
Step 5: kube-scheduler
→ Watch 到 3 个待调度 Pod(nodeName 为空)
→ 对每个 Pod 执行调度算法(Filter + Score)
→ 更新 Pod 的 nodeName 字段 → apiserver → etcd
Step 6: kubelet(对应节点上)
→ Watch 到分配给本节点的 Pod
→ 调用 containerd 拉取镜像
→ 创建容器(通过 runc)
→ 设置网络(调用 CNI 插件分配 IP)
→ 挂载存储卷
→ 启动容器
→ 更新 Pod 状态 → apiserver → etcd
Step 7: 完成
→ Pod 状态变为 Running
→ kubectl 可以查看到 Pod 的 IP 和状态
这个流程体现了 K8s 的核心设计:事件驱动 + Watch 机制 + 控制循环。
6. 高可用架构
生产环境的 K8s 集群需要高可用(HA),避免 Control Plane 成为单点故障。
6.1 Control Plane 高可用
┌──────────────────────────────────┐
│ 负载均衡(LB/VIP) │
└──────────────┬───────────────────┘
│
┌─────────────────────┼─────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Control Plane │ │ Control Plane │ │ Control Plane │
│ Node 1 │ │ Node 2 │ │ Node 3 │
│ │ │ │ │ │
│ apiserver │ │ apiserver │ │ apiserver │
│ scheduler │ │ scheduler │ │ scheduler │
│ controller- │ │ controller- │ │ controller- │
│ manager │ │ manager │ │ manager │
│ etcd │ │ etcd │ │ etcd │
└───────────────┘ └───────────────┘ └───────────────┘
Raft 选主
- apiserver:多实例,通过 LB 分发请求(无状态,可随意扩展)
- scheduler:多实例,通过 Leader Election 确保只有一个主动调度
- controller-manager:同上,Leader Election
- etcd:3 或 5 节点,Raft 保证数据一致性(需奇数节点)
6.2 Leader Election 机制
K8s 中 scheduler 和 controller-manager 使用基于 etcd/apiserver 的 Leader Election。
多个实例同时运行,但只有 Leader 真正工作,其他实例待命。Leader 宕机后,剩余实例重新选主,通常在几秒内完成切换。
6.3 生产集群规划
| 集群规模 | Control Plane 节点数 | Worker 节点数 |
|---|---|---|
| 小型(<50 节点) | 3 | 3-50 |
| 中型(50-250) | 3-5 | 50-250 |
| 大型(>250) | 5+ | 250+ |
7. 小结与思维导图
组件职责速查
| 组件 | 位置 | 职责 |
|---|---|---|
| kube-apiserver | Control Plane | 唯一入口,认证鉴权,REST API |
| etcd | Control Plane | 存储所有集群状态 |
| kube-scheduler | Control Plane | Pod 调度决策 |
| kube-controller-manager | Control Plane | 维护期望状态的各类控制器 |
| cloud-controller-manager | Control Plane | 对接云厂商 |
| kubelet | Node | 管理 Pod 和容器生命周期 |
| kube-proxy | Node | 维护 Service 网络规则 |
| 容器运行时 | Node | 真正运行容器 |
核心设计原则
- Watch + 事件驱动:组件通过 Watch API 感知状态变化,而非轮询
- 控制循环(Reconcile Loop):持续比对期望状态和实际状态
- 声明式 API:描述"想要什么",而非"怎么做"
- 单一通信入口:所有组件通过 apiserver 通信
xingliuhua