Kubernetes 持久性系列 第3部分:控制器与弹性 — 为什么 Kubernetes 自动修复

发布: (2026年1月11日 GMT+8 08:42)
8 min read
原文: Dev.to

Source: Dev.to

您将学到

  • 应用控制器(NGINX Ingress、cert‑manager)在驱逐过程中的持久化方式
  • 为什么控制器是无状态的,并且可以在任何地方重新启动
  • 从硬件到应用的完整持久化链路
  • 哪些在 Pod 驱逐后仍然存活,哪些则不会

之前

  • 第 1 部分 – 在 GKE 节点升级后调试缺失的 Ingress。
  • 第 2 部分 – 探讨 systemd 如何监管 kubelet,以及 kubelet 如何通过静态 Pod 引导控制平面。

现在我们进入最后一层:你的应用控制器——以及使 Kubernetes 真正具备弹性的优雅洞见。

第 4 层:应用控制器

应用控制器如何持久化

NGINX Ingresscert‑managerPrometheus Operator 这样的控制器通常以 DeploymentsStatefulSets 的形式部署:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: ingress-nginx
  template:
    spec:
      containers:
        - name: controller
          image: registry.k8s.io/ingress-nginx/controller:v1.9.0

当该 Pod 被驱逐时:

  1. kubelet 停止上报该 Pod → 控制平面将其标记为 Terminated(已终止)。
  2. ReplicaSet 控制器 看到 currentReplicas (0) ……
    关键点: 控制器本身不存储状态;它从 API Server(由 etcd 支持)读取所有信息。

Helm 发布持久化

Helm 将发布信息存储在 Kubernetes Secrets 中:

kubectl get secret -n monitoring -l owner=helm -o yaml
apiVersion: v1
kind: Secret
metadata:
  name: sh.helm.release.v1.prometheus.v3
  labels:
    owner: helm
    name: prometheus
    version: "3"
type: helm.sh/release.v1
data:
  release: H4sIAAAAAAAAA...   # Base64‑encoded release manifest

该 Secret 包含:

  • 已安装的 Chart
  • 使用的 Values(值)
  • 所有资源的计算后 Manifest(清单)

由于该 Secret 通过 API Server 存储在 etcd 中,Helm 发布能够在任何 Pod 被驱逐后仍然保留。

完整的持久化链

┌─────────────────────────────────────────────────────────────────────┐
│                     Linux Host (Physical/VM)                        │
├─────────────────────────────────────────────────────────────────────┤
│  systemd (PID 1)                                                    │
│  ├── Supervises all system services                                 │
│  ├── Restarts failed services automatically                         │
│  └── Config: /etc/systemd/system/                                   │
│      │                                                              │
│      └── kubelet.service                                            │
│          ├── Started and supervised by systemd                      │
│          ├── Watches /etc/kubernetes/manifests/ for static pods     │
│          ├── Watches API server for scheduled pods                  │
│          └── Ensures containers match pod specs                     │
│              │                                                      │
│              ├── Static Pods (/etc/kubernetes/manifests/)           │
│              │   ├── etcd ──────────────────┐                       │
│              │   ├── kube-apiserver ◄───────┤ Persistent            │
│              │   ├── kube-controller-manager│ State Store           │
│              │   └── kube-scheduler         │                       │
│              │                              │                       │
│              └── Regular Pods ◄─────────────┘                       │
│                  │                 (scheduled via API server)       │
│                  │                                                  │
│                  ├── kube-system namespace                          │
│                  │   ├── CoreDNS                                    │
│                  │   ├── kube-proxy                                 │
│                  │   └── CNI plugins                                │
│                  │                                                  │
│                  ├── ingress-nginx namespace                        │
│                  │   └── NGINX Ingress Controller                   │
│                  │       └── Watches Ingress resources              │
│                  │                                                  │
│                  └── Application namespaces                         │
│                      ├── cert-manager                               │
│                      ├── Prometheus Operator                        │
│                      └── Your applications                          │
└─────────────────────────────────────────────────────────────────────┘

关键洞察:控制器是无状态的

这是设计的优雅核心:控制器不存储状态

控制器的作用工作方式
读取 期望状态从 API 服务器(由 etcd 支持)
监视 更改通过 API 服务器的 watch 机制
进行更改通过向 API 服务器提交更新
可以在任何地方重新启动信息不丢失;API 服务器仍然是唯一的事实来源

API server + etcd唯一的事实来源,而不是控制器本身。

无状态控制器架构

监督层级 (Mermaid 图)

flowchart LR
    subgraph Source["Source of Truth"]
        etcd[(etcd)]
        api[API Server]
    end

    subgraph StatelessControllers["Stateless Controllers"]
        deploy[Deployment Controller]
        rs[ReplicaSet Controller]
        nginx[NGINX Ingress]
        cert[cert-manager]
    end

    etcd -->> api
    api -->> deploy
    api -->> rs
    api -->> nginx
    api -->> cert

    style etcd fill:#e67700,color:#fff
    style api fill:#e67700,color:#fff

(如果图表未渲染,请使用上面的代码在 Mermaid Live Editor 中直接查看。)

为什么这很重要

  • 删除任何控制器 Pod → 它会重新启动并赶上最新状态。
  • 将控制器移动到不同节点 → 它们只需重新连接到 API Server。
  • 将控制器扩展为多个副本 → 它们通过 API Server 协调工作。
  • 升级控制器 → 新版本会从 etcd 读取相同的状态。

什么会保留,什么不会

在任何 Pod 驱逐情况下仍然保留

资源为什么会保留
etcd 中的 Kubernetes 对象与 Pod 独立存储
Helm 发布以 Secret 形式存储在 etcd 中
Operator 管理的 CRD由 Operator 持续调和
持久卷存储位于集群外部
ConfigMap / Secret存储在 etcd 中

在没有帮助的情况下不会保留

资源为什么不会保留
Pod 本地 EmptyDir随 Pod 被删除
手动应用且缺少依赖的资源重新创建时被验证 webhook 拒绝
内存缓存进程重启后内存丢失
节点本地状态除非显式持久化,否则会丢失

设计的优雅

Kubernetes 的架构遵循若干关键设计原则:

  • 声明式优于命令式 – 描述期望的状态,而不是实现步骤。
  • 调和优于事务 – 持续收敛到期望状态。
  • 无状态控制器 – 状态保存在 etcd 中,而不是控制器进程。
  • 层级监督 – 每一层监视其上层。
  • 故障是常态 – 为恢复而设计,而不是为防止故障。

正因为这些原则,Kubernetes 集群可以:

  • 节点意外失效。
  • 因资源压力而驱逐 Pod。
  • 发生网络分区。
  • 进行滚动升级。

……并仍然保持应用可用性。

结论

从调试缺失的 Ingress 到了解完整的监督层级的过程,揭示了使 Kubernetes 具备弹性的精密机制。

systemd → kubelet → static pods → control plane → controllers → your apps

每一层都监督下一层,etcd 充当持久化内存,能够在任何组件故障后仍然存活。

关键洞见: Kubernetes 并不是阻止故障,而是通过分层监督、etcd 中的持久状态以及持续的调和循环,自动从故障中恢复。

这正是 Kubernetes 的真正力量:并非系统永不出错,而是当错误发生时,系统能够自行恢复到期望的状态。

系列回顾

进一步阅读

觉得本系列有用吗?关注获取更多 Kubernetes 内部原理内容!

Back to Blog

相关文章

阅读更多 »

StatefulSet 项目

先决条件:StatefulSet 需要以下组件: - Headless Service —— 为每个 pod 提供稳定的 DNS。 - StatefulSet manifest —— 定义 pod……