K8s 系列 | 第 1 天(重访):Kubernetes 核心架构再探:控制平面工作原理与组件通信深度解析


title: K8s 系列 | 第 1 天(重访):Kubernetes 核心架构再探:控制平面工作原理与组件通信深度解析
tags:
– Kubernetes
– K8s系列
– DevOps
– 架构设计
– 云原生
– 源码分析


K8s 系列 | 第 1 天(重访):Kubernetes 核心架构再探:控制平面工作原理与组件通信深度解析

第 1/30 天(重访版)—— 从组件内部原理与通信机制的视角,重新审视 K8s 架构

引言

在系列开篇中,我们第一次认识了 Kubernetes 的宏观架构——Master 节点与 Worker 节点、控制平面组件与数据平面组件。但那次介绍更像是一张”游览地图”,告诉我们 K8s 有哪些组件、各自负责什么。

今天,我们以重访的姿态,带着已经积累的经验,从更深的视角再探 K8s 架构:每个组件内部是如何工作的?它们之间如何通信?API 请求从发起到底层状态变更经历了怎样的完整链路? 理解这些底层机制,对于生产环境排障、性能调优和集群运维至关重要。

一、Kubernetes 架构的”八爪鱼”模型

如果说 K8s 是一个活的生物体,那它的架构可以用”八爪鱼”来比喻:

  • 大脑(etcd):存储所有状态,是集群的”唯一真相源”
  • 神经系统(API Server):所有组件通信的中枢,任何信息交换都要经过它
  • 运动系统(Controller Manager):持续观察当前状态与期望状态,做出调整
  • 决策系统(Scheduler):决定 Pod 应该运行在哪个节点上
  • 执行器(Kubelet):每个节点上的代理,负责执行控制平面的指令
  • 网络层(Kube-Proxy):维护网络规则,让 Service 通信可达

与”八爪鱼”不同的是,K8s 的大脑和神经系统是可水平扩展的——你可以运行多个 API Server 实例、多个 Controller Manager 实例,形成高可用架构。

二、API Server(kube-apiserver):集群的神经中枢

2.1 认证 → 授权 → 准入控制 → 存储

API Server 的请求处理管线是其核心设计,共经过四个阶段:

客户端请求 → 认证(Authentication) → 授权(Authorization) → 准入控制(Admission Control) → 持久化存储(etcd)

认证阶段:支持多种认证策略同时生效,包括 X.509 客户端证书、Bearer Token、HTTP Basic Auth、以及 Webhook 外部认证。API Server 逐个尝试认证模块,任何一个通过即视为认证成功。

# kube-apiserver 启动参数示例:启用多种认证方式
# --client-ca-file=/etc/kubernetes/pki/ca.crt          # TLS 证书认证
# --token-auth-file=/etc/kubernetes/pki/tokens.csv     # 静态 Token 认证
# --authorization-mode=Node,RBAC                       # 授权模式链
# --enable-admission-plugins=NodeRestriction,PodSecurity,ResourceQuota

授权阶段:通过 RBAC(基于角色的访问控制)或 ABAC 等模式,判断请求主体是否有权限执行操作。RBAC 是生产环境最常用的模式,核心对象是 Role/ClusterRole 与 RoleBinding/ClusterRoleBinding。

准入控制阶段:这是 K8s 安全策略的关键防线。每个准入控制器(Admission Controller)可以修改(Mutating)或验证(Validating)请求对象。例如:

  • MutatingAdmissionWebhook:动态注入 Sidecar、默认标签等
  • PodSecurity:强制 Pod 安全策略
  • ResourceQuota:检查资源配额是否超限
// 准入控制链的伪代码逻辑
func (s *APIServer) HandleCreate(request *Request) Response {
    // 1. 认证
    user, err := Authenticate(request)
    if err != nil { return Unauthorized() }

    // 2. 授权
    if !Authorize(user, request) { return Forbidden() }

    // 3. Mutating 准入
    for _, mutator := range s.mutatingAdmissions {
        request.Object = mutator.Mutate(request.Object)
    }

    // 4. Validating 准入
    for _, validator := range s.validatingAdmissions {
        if err := validator.Validate(request.Object); err != nil {
            return Reject(err)
        }
    }

    // 5. 写入 etcd
    return s.storage.Create(request.Object)
}

2.2 Watch 机制:K8s 的”消息总线”

API Server 最强大的能力之一是 Watch 机制。它基于 HTTP 长连接(Chunked Transfer Encoding),让客户端可以实时监听资源变化。

# 使用 kubectl 的 raw API 观察 Pod 事件
kubectl get --raw "/api/v1/namespaces/default/pods?watch=true" | head -20

当你在集群中创建一个 Deployment 时,Watch 机制让所有相关组件几乎实时收到通知:

  1. API Server 将 Pod 对象写入 etcd
  2. etcd 返回事件给 API Server
  3. API Server 将事件广播给所有正在 Watch 该资源的客户端
  4. Scheduler 收到 Pod 创建事件 → 开始调度
  5. Kubelet 收到 Pod 绑定事件 → 启动容器

三、etcd:集群的”唯一真相源”

3.1 为什么是 etcd 而不是关系型数据库?

K8s 选择 etcd 作为存储后端,原因在于:

  • 强一致性:etcd 基于 Raft 共识算法,保证所有节点数据一致
  • 键值存储:与 K8s 的声明式 API 天然契合,资源以 /registry/<resource_type>/<namespace>/<name> 的路径存储
  • Watch 支持:原生支持事件监听,这是 K8s 整个控制循环的基础
  • TTL 与 Lease:支持键的自动过期,用于 Node 心跳等场景

3.2 etcd 数据模型

# 查看 etcd 中存储的 K8s 数据(需要在 etcd 节点上执行)
ETCDCTL_API=3 etcdctl get /registry/pods/default/nginx-pod-xxxxx 
  --endpoints=https://127.0.0.1:2379 
  --cacert=/etc/kubernetes/pki/etcd/ca.crt 
  --cert=/etc/kubernetes/pki/etcd/server.crt 
  --key=/etc/kubernetes/pki/etcd/server.key 
  | strings | head -50

etcd 生产环境最佳实践:

# etcd 集群推荐配置(3 节点)
# 硬件要求
# - CPU: 8 核
# - 内存: 16GB(etcd 本身不耗内存,但 Linux 文件缓存需要)
# - 磁盘: 50GB SSD(NVMe 最佳),IOPS ≥ 10000
# - 网络: 低延迟(<10ms 节点间延迟)

# 关键参数
# --quota-backend-bytes=8589934592   # 8GB 数据库大小限制(默认 2GB)
# --auto-compaction-retention=8      # 每 8 小时自动压缩历史版本
# --snapshot-count=100000            # 每 10 万次变更触发一次快照

四、Controller Manager:永不疲倦的”校对员”

4.1 控制器模式的核心思想

控制器模式是 K8s 的精髓:“观察当前状态,与期望状态比较,执行操作使两者一致”

// 通用控制器循环的伪代码
func (c *Controller) Run(stopCh <-chan struct{}) {
    // 等待缓存同步
    if !cache.WaitForCacheSync(stopCh, c.informerSynced...) {
        return
    }

    // 以固定间隔执行 reconciliation 循环
    wait.Until(c.Reconcile, c.syncPeriod, stopCh)
}

func (c *Controller) Reconcile() {
    // 1. 获取当前状态(从 informer 缓存读取)
    currentState := c.lister.List()

    // 2. 获取期望状态(从 API Server 读取)
    desiredState := c.desiredLister.List()

    // 3. 比较差异
    diff := Compare(currentState, desiredState)

    // 4. 执行调整操作
    for _, item := range diff.ToCreate {
        c.kubeClient.Create(item)
    }
    for _, item := range diff.ToDelete {
        c.kubeClient.Delete(item)
    }
    for _, item := range diff.ToUpdate {
        c.kubeClient.Update(item)
    }
}

4.2 Informer 机制:优雅的事件驱动

每个 Controller 内部都运行着一个 Informer,它本质上是一个”带本地缓存的 Watch 客户端”:

# Informer 工作流程
# 1. List:首次启动时全量拉取资源列表
# 2. Watch:通过 HTTP 长连接监听增量变更
# 3. Store:将数据存入本地索引缓存(ThreadSafeStore)
# 4. DeltaFIFO:将变更事件按顺序放入队列
# 5. 回调:触发注册的 EventHandler(AddFunc/UpdateFunc/DeleteFunc)

这种设计带来两个关键好处:
减少 API Server 压力:控制器从本地缓存读取数据,而非每次都请求 API Server
断线重连:Watch 断开后,Informer 会自动重新 List 并 Watch,保证数据不丢失

五、Scheduler:聪明的”分配器”

5.1 调度两阶段:Predicates + Priorities

Kube-Scheduler 的调度过程分为两个阶段:

# 查看调度器当前配置
kubectl describe configmap kube-scheduler -n kube-system

第一阶段:Predicates(预选)—— 过滤掉不满足条件的节点

  • PodFitsResources:节点资源(CPU/内存)是否满足 Pod 需求
  • PodFitsHostPorts:节点端口是否已被占用
  • PodSelectorMatches:节点标签是否匹配 Pod 的 nodeSelector
  • NoDiskConflict:节点挂载的 Volume 是否有冲突
  • PodToleratesNodeTaints:Pod 是否能容忍节点污点

第二阶段:Priorities(优选)—— 对剩余节点打分排序

// 调度器评分优先级示例
priorities := []PriorityConfig{
    {"LeastRequestedPriority", 1},   // 资源利用率低的节点得分高(分散调度)
    {"BalancedResourceAllocation", 1}, // CPU 和内存使用率均衡的节点得分高
    {"NodeAffinityPriority", 2},     // 匹配节点亲和性规则的节点加分
    {"TaintTolerationPriority", 1},  // 容忍更多污点的节点加分
}

// 调度过程
func (s *Scheduler) Schedule(pod *v1.Pod) (string, error) {
    // 1. 预选:过滤节点
    nodes := s.predicatePhase(pod)

    // 2. 优选:对候选节点打分
    scores := s.priorityPhase(pod, nodes)

    // 3. 选择最高分节点
    return s.selectHost(scores)
}

5.2 调度框架的可扩展性

K8s 1.19+ 引入了调度框架(Scheduling Framework),允许通过插件扩展调度行为:

# KubeSchedulerConfiguration 示例
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
  - schedulerName: custom-scheduler
    plugins:
      score:
        enabled:
          - name: MyCustomScorer  # 自定义评分插件
      filter:
        disabled:
          - name: NodeResourcesFit  # 禁用默认的过滤插件

六、Kubelet:节点上的”大管家”

6.1 Pod 生命周期管理

Kubelet 是运行在每个节点上的 Agent,负责管理 Pod 和容器的整个生命周期。它通过 CRI(Container Runtime Interface) 与容器运行时交互。

# 查看 Kubelet 日志(排查 Pod 启动问题)
journalctl -u kubelet -f --no-pager -n 100

# 查看 Kubelet 与 CRI 运行时的交互
crictl ps
crictl images
crictl pods

Kubelet 创建 Pod 的完整流程:

1. Kubelet Watch 到 Pod 被调度到本节点
2. 计算 Pod 的 Sandbox 配置(CNI 网络、Volume 挂载等)
3. 调用 CRI 创建 Pod Sandbox(pause 容器)
4. 调用 CNI 插件配置网络
5. 调用 CSI/CSI 驱动挂载 Volume
6. 依次创建 Init 容器(如果有)
7. 创建主业务容器
8. 启动存活探针(Liveness Probe)和就绪探针(Readiness Probe)

6.2 三种探针的底层实现

# 三种探针的配置示例
apiVersion: v1
kind: Pod
metadata:
  name: probe-demo
spec:
  containers:
  - name: web
    image: nginx:alpine
    livenessProbe:          # 存活探针:失败则重启容器
      httpGet:
        path: /healthz
        port: 80
      initialDelaySeconds: 5
      periodSeconds: 10
    readinessProbe:         # 就绪探针:失败则从 Service 移除
      tcpSocket:
        port: 80
      initialDelaySeconds: 3
      periodSeconds: 5
    startupProbe:           # 启动探针:慢启动容器专用
      exec:
        command:
        - cat
        - /tmp/healthy
      failureThreshold: 30
      periodSeconds: 10

Kubelet 内部实现探针的三条独立 goroutine:
存活探针:失败 → 容器进入 CrashLoopBackOff → 重启策略生效
就绪探针:失败 → Pod 从 EndpointSlice 中移除 → 流量不进入该 Pod
启动探针:成功后才启动存活/就绪探针(解决慢启动容器被误杀的问题)

七、Kube-Proxy:网络规则的”维护工”

7.1 三种代理模式对比

Kube-Proxy 负责维护节点上的网络规则,使 Service 的 ClusterIP 可达。它支持三种模式:

模式 内核依赖 性能 规模建议
userspace 低(用户态转发) 已废弃
iptables iptables 中(规则链遍历) ≤ 5000 Service
IPVS ip_vs 模块 高(哈希查找) ≥ 5000 Service
# 查看当前 kube-proxy 模式
kubectl get configmap kube-proxy -n kube-system -o yaml | grep mode

# IPVS 模式下查看负载均衡规则
ipvsadm -Ln

# iptables 模式下查看 K8s 规则链
iptables -t nat -L KUBE-SERVICES -n

7.2 IPVS 模式的优势

在生产环境中,超过 1000 个 Service 时,iptables 模式会因规则链过长导致性能下降。IPVS 模式使用哈希表替代链表,时间复杂度从 O(n) 降到 O(1):

# 启用 IPVS 模式
# 1. 确保节点已加载 ip_vs 模块
modprobe ip_vs
modprobe ip_vs_rr
modprobe ip_vs_wrr
modprobe ip_vs_sh

# 2. 修改 kube-proxy 配置
kubectl edit configmap kube-proxy -n kube-system
# 将 mode: "" 改为 mode: "ipvs"

# 3. 重启 kube-proxy
kubectl rollout restart daemonset kube-proxy -n kube-system

八、一条请求的完整旅程

让我们追踪一条 kubectl apply -f deployment.yaml 命令的完整旅程:

1. kubectl 将 YAML 文件解析为 API 对象
2. HTTP POST 请求发送到 API Server(经认证/授权/准入控制)
3. API Server 将 Deployment 对象序列化后写入 etcd
4. etcd 返回成功 → API Server 返回 201 Created 给 kubectl
5. Deployment Controller 通过 Watch 收到事件
6. Deployment Controller 创建 ReplicaSet(期望副本数)
7. ReplicaSet Controller 通过 Watch 收到事件
8. ReplicaSet Controller 创建 Pod(N 个副本)
9. Scheduler 通过 Watch 收到未调度的 Pod
10. Scheduler 执行预选+优选,选择目标节点
11. Scheduler 将 Pod 绑定到目标节点(写入 Pod.Spec.NodeName)
12. 目标节点的 Kubelet 通过 Watch 收到 Pod 分配事件
13. Kubelet 调用 CRI 创建 Pod Sandbox
14. Kubelet 调用 CNI 配置网络
15. Kubelet 调用 CSI 挂载 Volume
16. Kubelet 创建业务容器
17. Kubelet 启动探针检查
18. 探针通过 → Pod 状态更新为 Running
19. Endpoint Controller 将 Pod IP 加入 Service EndpointSlice
20. Kube-Proxy 更新节点 iptables/IPVS 规则

整个流程涉及 10+ 个组件协作,但得益于声明式 API 和控制器模式,全部在秒级完成。

九、常见问题与排障思路

9.1 核心组件故障排查

# API Server 不可用
# 1. 检查 API Server 进程
kubectl get --raw /healthz

# 2. 检查 etcd 健康状态
kubectl get --raw /livez?verbose

# 3. 查看 API Server 日志
kubectl logs -n kube-system kube-apiserver-<node> --tail=100

# Controller Manager 异常
# 检查控制器是否在运行
kubectl get pods -n kube-system | grep controller
kubectl logs -n kube-system kube-controller-manager-<node> --tail=50

# Scheduler 异常
kubectl logs -n kube-system kube-scheduler-<node> --tail=50

9.2 性能瓶颈定位

症状 可能原因 解决方向
Pod 创建延迟高 API Server 负载过高 增加 API Server 副本数
调度延迟 Scheduler 积压 启用调度框架的队列排序插件
节点状态频繁 NotReady Kubelet 心跳超时 调整 --node-status-update-frequency
Service 不通 Kube-Proxy 规则未更新 检查 conntrack 表是否溢出

总结

通过这次重访,我们深入到了 K8s 架构的内部:

  • API Server 是集群的神经中枢,认证→授权→准入→存储的四阶段管线是所有请求的必经之路
  • etcd 是集群的”唯一真相源”,基于 Raft 保证强一致性
  • Controller Manager 通过 Informer 机制实现高效的声明式控制循环
  • Scheduler 通过预选+优选两阶段,为每个 Pod 选择最优节点
  • Kubelet 作为节点 Agent,通过 CRI/CNI/CSI 接口管理容器、网络和存储
  • Kube-Proxy 维护网络规则,保证 Service 可达

理解这些组件的工作原理,不仅有助于日常运维和排障,更是深入学习 K8s 高级特性的基础。


下期预告: 第 2 天我们将用 kubeadm 手把手搭建一个生产级高可用 K8s 集群,包括负载均衡配置、etcd 集群部署、以及证书管理的最佳实践。

系列目录: [K8s 系列 30 天合集](https://www.stellardata.top 搜索”K8s 系列”)

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容