目录

Kubernetes-02 架构深度解析

Kubernetes 架构深度解析

系列第二篇。理解 K8s 的内部架构,是排查问题、优化性能、设计系统的基础。本篇将带你深入 K8s 的每个核心组件。


目录

  1. 整体架构概览
  2. Control Plane(控制平面)
  3. Node 组件
  4. 组件通信流程
  5. 一次 Pod 创建的全链路
  6. 高可用架构
  7. 小结与思维导图

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 资源的操作(增删改查)都要经过它。

核心职责:

  1. 认证(Authentication):确认"你是谁"(证书/Token/OIDC 等)
  2. 鉴权(Authorization):确认"你能干什么"(RBAC)
  3. 准入控制(Admission Control):校验/修改请求(如自动注入 sidecar)
  4. 数据持久化:把资源写入 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 上必须运行的进程,它的核心职责:

  1. 向 apiserver 注册节点
  2. Watch 分配到本节点的 Pod
  3. 调用容器运行时创建/删除容器
  4. 执行健康检查(liveness/readiness/startup probe)
  5. 上报节点和 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 真正运行容器

核心设计原则

  1. Watch + 事件驱动:组件通过 Watch API 感知状态变化,而非轮询
  2. 控制循环(Reconcile Loop):持续比对期望状态和实际状态
  3. 声明式 API:描述"想要什么",而非"怎么做"
  4. 单一通信入口:所有组件通过 apiserver 通信