Chapter 01

Kubernetes 概念与核心设计哲学

理解容器编排的必要性,从 Google Borg 到 K8s 的演进,掌握声明式 API 与控制循环这两个最核心的设计思想。

为什么需要容器编排

当你只有一个 Docker 容器时,docker run 就够了。但当你的系统由数十个微服务组成、需要在数百台服务器上运行时,问题就变得复杂:如何保证服务高可用?容器崩溃后谁来重启?流量如何分发?配置如何统一管理?这些问题催生了容器编排系统。

没有编排时的痛点

  • 手动 SSH 到每台机器部署
  • 容器崩溃后需人工干预
  • 无法自动伸缩应对流量高峰
  • 服务发现靠硬编码 IP
  • 滚动更新复杂且容易出错
  • 资源浪费,无法统一调度

Kubernetes 解决了什么

  • 声明期望状态,自动收敛
  • Pod 失败自动重启迁移
  • HPA 基于指标自动扩缩容
  • 内置 DNS 服务发现
  • 内置滚动更新与回滚
  • Bin-packing 优化资源利用

Google Borg:K8s 的精神前身

Kubernetes 并非凭空而来。它的设计深受 Google 内部使用了十余年的集群管理系统 Borg 的启发。Borg 在 Google 内部管理着数十万台机器上的作业调度,积累了大量实战经验。

Google 集群管理演进

┌─────────────────────────────────────────────────────────┐
                    Google Borg (2003)                     
  · 管理 Google 全部在线/离线作业                            
  · BorgMaster(控制平面) + Borglet(节点代理)               
  · 引入 alloc(资源分配单元,Pod 的前身)                    
└─────────────────┬───────────────────────────────────────┘
                  │ 开源 + 重新设计
┌─────────────────▼───────────────────────────────────────┐
               Kubernetes 1.0 (2014 开源)                  
  · Pod = alloc + 容器                                     
  · 声明式 API (Borg 是命令式配置文件)                      
  · 开放生态,CRD/Operator 扩展                             
└─────────────────────────────────────────────────────────┘
Borg
Google 内部集群管理系统,2003 年起使用,Kubernetes 的直接前身。管理 Google 全球数据中心的在线服务(如 Gmail、Search)和批处理作业(如 MapReduce)。
Omega
Borg 的继任研究原型,探索共享状态调度架构,部分思想影响了 Kubernetes 的调度器设计。
CNCF
Cloud Native Computing Foundation,云原生计算基金会。2016 年接管 Kubernetes 项目,目前托管 Prometheus、Helm、Envoy 等 150+ 云原生项目。

声明式 API vs 命令式 API

这是 Kubernetes 最核心的设计思想之一。声明式(Declarative)意味着你只告诉系统"我想要什么",而不是"如何去做"。Kubernetes 会持续对比当前状态与期望状态,并自动执行必要的操作来使两者一致。

命令式(以 Docker 为例)

# 告诉系统"如何做"
docker run -d --name web nginx
docker stop web
docker rm web
docker run -d --name web nginx:1.25

# 容器崩溃 → 你不知道 → 服务中断

声明式(Kubernetes)

# 告诉系统"想要什么"
spec:
  replicas: 3
  image: nginx:1.25

# K8s 自动保证 3 个副本运行
# Pod 崩溃 → K8s 自动重建
声明式的幂等性

同一份 YAML 文件,无论 kubectl apply 执行多少次,最终结果都相同。这使得 GitOps 成为可能——将 YAML 存入 Git,任何时候都能重现集群状态。

控制循环(Control Loop)原理

Kubernetes 的自愈能力来自于遍布整个系统的控制循环(也叫 Reconciliation Loop,调和循环)。每个 Controller 都在不断地执行同一个逻辑:

控制循环示意

         ┌──────────────────────────┐
               期望状态 (Desired)    
            replicas: 3, nginx:1.25 
         └───────────────┬──────────┘
                         
          ┌──────────────▼──────────────┐
                   Controller           
             ① 观察当前状态 (Observe)   
             ② 计算差异 (Diff)          ◄──┐
             ③ 执行操作 (Act)              │ 循环
          └──────────────┬──────────────┘   
                                        └──┘
         ┌──────────────▼──────────────┐
               当前状态 (Actual)     
           当前 Pod 数量、健康状态等   
         └─────────────────────────────┘

以 Deployment Controller 为例:

  1. 观察:从 etcd 读取 Deployment 的 spec.replicas=3,以及当前实际运行的 Pod 数量
  2. 差异:当前只有 2 个 Pod(有一个崩溃了),差距为 1
  3. 操作:调用 API Server 创建 1 个新 Pod
  4. 返回第 1 步,持续循环
Reconciliation
调和/收敛。控制器使集群实际状态与期望状态保持一致的过程。这是 Kubernetes 自愈能力的核心机制。
Spec
期望状态(Desired State)。你在 YAML 中声明的内容,比如 replicas=3、image=nginx:1.25。
Status
当前状态(Current State)。K8s 组件观察到的实际运行情况,如当前就绪的 Pod 数量、最近一次重启时间等。
Controller
控制器。一个持续运行的 Go 程序,监听某类资源的变更,执行调和操作。K8s 内置了几十种 Controller,用户也可以通过 Operator 模式创建自定义 Controller。
Watch
K8s API 的 Watch 机制。Controller 通过长连接监听 etcd 中的资源变更事件(ADDED/MODIFIED/DELETED),而非轮询,大幅减少 API Server 压力。

K8s 与 Docker Compose 的区别

很多人入门 K8s 时都会问:Docker Compose 不是已经能编排多个容器了吗?为什么还需要 K8s?

对比维度 Docker Compose Kubernetes
运行范围 单台机器 多节点集群(可达数千节点)
高可用 无,单点故障 节点故障自动迁移 Pod
自动扩缩容 手动 scale HPA 基于 CPU/内存/自定义指标
滚动更新 有中断 零停机滚动更新
服务发现 容器名 DNS(限单机) 跨节点 Service DNS
存储 本地 Volume PV/PVC 对接云存储/NFS/CSI
适用场景 本地开发、小规模单机 生产级、多节点、微服务
实用建议

本地开发仍然推荐使用 Docker Compose,快速简单。将 K8s 部署在测试/生产环境。可以使用 Kompose 工具将 docker-compose.yml 转换为 K8s YAML 文件作为起点。

第一个 Kubernetes YAML

让我们看一个完整的 YAML 文件,感受声明式 API 的形态:

apiVersion: apps/v1          # API 版本,决定该资源类型的 schema
kind: Deployment             # 资源类型
metadata:
  name: hello-k8s            # 资源名称,集群内唯一(同 namespace)
  namespace: default         # 所属命名空间
  labels:                    # 标签,用于选择器筛选
    app: hello-k8s
spec:                        # 期望状态(最重要的部分)
  replicas: 3                # 期望运行 3 个 Pod 副本
  selector:
    matchLabels:
      app: hello-k8s        # Deployment 通过此标签关联 Pod
  template:                  # Pod 模板
    metadata:
      labels:
        app: hello-k8s      # Pod 携带的标签,必须匹配 selector
    spec:
      containers:
      - name: web            # 容器名,Pod 内唯一
        image: nginx:1.25   # 容器镜像
        ports:
        - containerPort: 80 # 容器监听端口(文档性质,不影响网络)
# 应用此 YAML(创建或更新)
kubectl apply -f hello-k8s.yaml

# 查看 Deployment 状态
kubectl get deployment hello-k8s

# 查看自动创建的 Pod
kubectl get pods -l app=hello-k8s

# 删除资源
kubectl delete -f hello-k8s.yaml
apiVersion 不要写错

不同资源类型使用不同的 apiVersion。Deployment 用 apps/v1,Pod 用 v1,Ingress 用 networking.k8s.io/v1。写错会导致 no matches for kind 错误。可用 kubectl api-resources 查询所有资源类型及其 apiVersion。

核心术语速查

Cluster
集群。由一个 Control Plane 和若干 Node 组成的 Kubernetes 部署单元。
Namespace
命名空间。逻辑隔离单元,同一集群内可划分多个 Namespace(如 dev、staging、prod),实现资源隔离和配额管理。
Resource / Object
资源/对象。K8s 中的一切都是资源(Pod、Service、ConfigMap…),通过 API Server 的 REST API 进行 CRUD 操作,持久化存储在 etcd 中。
Label
标签。键值对,附着在资源上。通过 Label Selector 筛选资源,是 K8s 中最核心的分组机制(Service 找 Pod、Deployment 关联 ReplicaSet 都靠 Label)。
Annotation
注解。键值对,用于存储非标识性的元数据(如构建信息、操作者邮箱)。与 Label 不同,Annotation 不用于选择器筛选。
kubectl
Kubernetes 命令行工具。通过 HTTPS 调用 API Server 的 REST API,是与集群交互的主要方式。
Manifest
清单文件。描述 K8s 资源的 YAML 或 JSON 文件,通过 kubectl apply 提交给集群。
Operator
运算符/操作员。一种将运维知识(如数据库备份、主从切换)编码为自定义 Controller 的模式,基于 CRD 扩展 K8s 能力。
常见误区:K8s 不是银弹

K8s 引入了大量概念和运维复杂度。小团队或单机服务请评估是否真的需要 K8s。如果你只有 2-3 个服务,Docker Compose + 单台 VPS 可能是更好的选择。K8s 的收益在团队规模较大、服务数量较多(10+ 微服务)时才能真正体现。