# K8s 架构总览与核心概念


## 导读

Kubernetes 解决的核心问题是：如何在多台机器上可靠地运行数百个容器，并在节点故障时自动恢复。理解它的架构设计和核心对象模型，是后续所有实操的基础。本篇将拆解控制平面与数据平面的组件职责，厘清 Pod、Node、Namespace 三者的关系，并解释声明式 API 为何改变了运维的思维方式。

## 核心概念

### 什么是 Kubernetes

Kubernetes（简称 K8s）是一个开源的容器编排系统，负责自动化容器的部署、扩缩容和运维。如果你用 Docker 跑过容器，就已经解决了"单机运行"的问题；K8s 解决的是"多机运行"的问题——跨节点调度、故障自愈、滚动更新、服务发现，这些在单机 Docker 中都需要手动处理。

K8s 的设计哲学围绕三个关键词：**声明式 API**、**自愈**、**弹性伸缩**。你告诉系统"我要 3 个 Nginx 副本"，而不是"启动一个 Nginx 容器"。系统会持续比对期望状态与实际状态，发现偏差时自动纠正——某个 Pod 崩溃了，调度器会在其他节点重新拉起一个；流量突增时，水平扩缩器自动增加副本数。

### 集群与节点模型

一个 K8s 集群由至少一个控制平面节点（Control Plane Node，也称 Master）和若干工作节点（Worker Node）组成。控制平面是集群的"大脑"，负责全局决策和事件响应；工作节点是"手脚"，负责运行实际的容器负载。

Node 是 K8s 中对物理机或虚拟机的抽象。每个 Node 包含 CPU、内存等资源容量，调度器根据这些容量决定将 Pod 放在哪个节点上。Node 有两种角色：`control-plane`（同时承担控制职责）和 `<none>`（纯工作节点）。生产环境通常将控制平面与工作节点分离部署，控制平面至少 3 个节点以实现高可用。

Node 的状态通过 Conditions 字段报告，关键的几项包括 `Ready`（节点健康可调度）、`MemoryPressure`（内存不足）、`DiskPressure`（磁盘不足）、`PIDPressure`（进程数过多）。当 `Ready` 为 `False` 时，调度器不再往该节点分配新 Pod。

### 核心对象模型

K8s 通过一组核心对象来描述集群中运行的一切：

- **Pod** —— K8s 的最小调度单元。一个 Pod 包含一个或多个紧密耦合的容器，它们共享网络命名空间和存储卷。Pod 是临时的，IP 会随重建而变化，因此不应直接依赖 Pod IP。
- **Namespace** —— 集群内的逻辑隔离边界。不同 Namespace 下的资源名称可以重复，RBAC 权限和资源配额都以 Namespace 为作用域。生产环境通常按团队或环境（dev/staging/prod）划分 Namespace。
- **Label 与 Selector** —— K8s 的关联机制。Label 是挂在资源上的键值对（如 `app=nginx, tier=frontend`），Selector 通过 Label 筛选资源。Service 通过 Selector 找到后端 Pod，Deployment 通过 Selector 管理它创建的 Pod。

下面的架构图展示了控制平面与工作节点的组件拓扑，以及核心对象在其中的位置。

```mermaid
graph TB
    subgraph "控制平面 Control Plane"
        API[kube-apiserver<br/>统一入口]
        ETCD[etcd<br/>集群状态存储]
        SCHED[kube-scheduler<br/>Pod 调度]
        CM[kube-controller-manager<br/>控制器集合]
        CCM[cloud-controller-manager<br/>云平台对接]
    end

    subgraph "工作节点 Worker Node 1"
        KL1[kubelet<br/>节点代理]
        KP1[kube-proxy<br/>网络规则]
        CR1[容器运行时<br/>containerd]
        P1[Pod A]
        P2[Pod B]
    end

    subgraph "工作节点 Worker Node 2"
        KL2[kubelet]
        KP2[kube-proxy]
        CR2[容器运行时<br/>containerd]
        P3[Pod C]
        P4[Pod D]
    end

    API --> ETCD
    SCHED --> API
    CM --> API
    CCM --> API
    KL1 --> API
    KL2 --> API
    KL1 --> CR1
    KL2 --> CR2
    CR1 --> P1
    CR1 --> P2
    CR2 --> P3
    CR2 --> P4
    KP1 -.-> API
    KP2 -.-> API
```

图 1 展示了 K8s 集群的组件拓扑。所有组件只与 kube-apiserver 通信，不直接读写 etcd，这保证了状态变更的一致性。kubelet 在每个工作节点上运行，负责向 apiserver 上报节点状态并管理本节点的 Pod 生命周期。kube-proxy 负责将 Service 的虚拟 IP 规则写入节点 iptables 或 IPVS，使流量能正确路由到后端 Pod。

## 图解原理

### 控制平面组件职责

控制平面包含五个核心组件，各司其职：

- **kube-apiserver** —— 集群统一的 API 入口，所有组件和 kubectl 命令都通过它读写集群状态。它负责认证、授权和准入控制，是唯一直接操作 etcd 的组件。
- **etcd** —— 分布式键值存储，保存集群的全部状态数据（Pod、Service、ConfigMap 等所有资源定义）。etcd 的一致性直接决定集群的可靠性，生产环境必须以集群方式部署。
- **kube-scheduler** —— 监听新建但未调度的 Pod，根据资源请求、亲和性规则、污点容忍等策略，为 Pod 选择最合适的节点。
- **kube-controller-manager** —— 运行一组控制器，每个控制器负责一种资源对象的调和循环。例如 Deployment Controller 确保副本数符合期望，Node Controller 监控节点健康状态。
- **cloud-controller-manager** —— 将云厂商特定的逻辑（如负载均衡器创建、节点路由配置）与 K8s 核心代码解耦，使各云厂商只需实现自己的插件。

### 声明式与命令式的本质区别

命令式操作是"告诉系统做什么"：`docker run nginx` 直接启动一个容器。声明式操作是"告诉系统想要什么"：提交一段 YAML 描述"我要 3 个 Nginx 副本"，系统自行决定如何达到这个状态。

声明式的核心优势在于可恢复性。当节点故障导致 Pod �丢失时，Deployment Controller 检测到实际副本数低于期望值，自动在其他节点创建新 Pod。这个过程不需要人工干预，也不需要记录"之前做了什么操作"——系统只需要比对当前状态与期望状态的差异。

下面的流程图展示了从 kubectl 命令到 Pod 调度运行的完整链路。

```mermaid
flowchart LR
    A[kubectl apply -f deploy.yaml] --> B[kube-apiserver]
    B --> C[写入 etcd]
    B --> D[kube-scheduler 监听到新 Pod]
    D --> E{过滤阶段<br/>资源足够? 污点? 亲和性?}
    E -->|通过| F{打分阶段<br/>资源均衡? 亲和性权重?}
    E -->|不通过| G[Pod 保持 Pending]
    F --> H[选择最优节点]
    H --> B
    B --> I[目标节点 kubelet 收到 Pod]
    I --> J[容器运行时拉取镜像]
    J --> K[Pod Running]
    K --> L[kube-controller-manager<br/>持续监控副本数]
    L -.->|副本不足| D
```

图 2 描述了从提交 YAML 到 Pod 运行的完整链路。注意 scheduler 和 controller-manager 都通过监听 apiserver 的事件来驱动工作，而不是直接被调用。这种事件驱动架构是 K8s 控制平面的核心设计模式——每个组件自治地响应状态变化，形成多层调和循环。

## 动手实操

以下命令使用 `kubectl` 与集群交互，验证本篇涉及的架构概念。

查看集群节点及其角色和状态：

```bash
kubectl get nodes -o wide
```

输出示例：

```
NAME           STATUS   ROLES           AGE   VERSION
control-plane  Ready    control-plane   10d   v1.30.0
worker-1       Ready    <none>          10d   v1.30.0
worker-2       Ready    <none>          10d   v1.30.0
```

查看某个节点的详细状态，包括 Conditions 和资源容量：

```bash
kubectl describe node worker-1
```

关注输出中的 `Conditions` 部分（`Ready`、`MemoryPressure` 等）和 `Capacity` 部分（CPU、内存总量），这些是调度器决策的依据。

查看控制平面组件状态：

```bash
kubectl get componentstatuses
```

创建一个 Namespace 并部署一个简单 Pod，观察 Label 和 Selector 的关联：

```bash
# 创建 Namespace
kubectl create namespace demo

# 部署带 Label 的 Pod
kubectl run nginx --image=nginx:1.27 --labels=app=nginx,tier=frontend -n demo

# 通过 Label Selector 查找 Pod
kubectl get pods -l app=nginx -n demo
```

查看 Pod 的详细信息，注意其所在节点和 IP：

```bash
kubectl describe pod nginx -n demo
```

## 常见问题与避坑

**控制平面组件不可在同一节点混用**——在生产环境中，etcd 与工作负载混部会导致资源争抢，etcd 写延迟升高会直接影响整个集群的响应速度。建议控制平面节点仅运行控制组件，不调度业务 Pod（通过污点实现）。

`Pending` 状态的 Pod 通常不是调度器故障，而是资源不足。先用 `kubectl describe pod <name>` 查看 Events 部分，如果出现 `FailedScheduling` 并提示 `Insufficient cpu`，说明没有节点能满足 Pod 的资源请求。此时应检查资源请求值是否合理，或扩容集群节点。

Pod IP 是易变的。如果你在代码或配置中硬编码了 Pod IP，当 Pod 重建后 IP 变化会导致连接失败。始终通过 Service 的稳定 ClusterIP 或 DNS 名称访问服务。

## 小结与进阶

K8s 通过控制平面（apiserver/etcd/scheduler/controller-manager）集中决策、工作节点（kubelet/kube-proxy/容器运行时）分散执行的架构，实现了容器负载的自动化管理。Pod 是最小调度单元，Namespace 提供逻辑隔离，Label/Selector 建立资源间的关联。声明式 API 让系统持续向期望状态收敛，这是 K8s 自愈能力的根基。

下一篇将从零搭建一个本地集群，用 kubectl 命令实际操作这些概念。

