目录

Kubernetes-02 架构深度解析

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 通信