第九章

Kubernetes 入门:容器多了谁来管

第八层 + 第九层 · Pod/Deployment/Service/HPA 容器多了,谁来管它们

一、三台服务器,二十个容器,docker-compose 撑不住了

云间书店开分店,服务器从 1 台变 3 台。小陈发现 docker-compose 不好使了:

docker-compose 的局限:
  ① 只能在"一台机器"上编排 —— 3 台服务器要各管各的
  ② 没有自动调度 —— 容器不会自己跑到"空闲的那台"去
  ③ 没有自动扩容 —— 流量大了不会自动多开几个容器
  ④ 没有自愈 —— 一台机器挂了,它上面的容器不会自动迁移
  ⑤ 没有跨机网络 —— 各机器的容器互相发现是个难题

结论:单机编排用 compose,跨机集群要用 Kubernetes!

老周:"K8s 是什么?它是 Google 开源的容器编排平台——管理'一群服务器上的所有容器',自动调度、自动扩容、自动自愈。它是容器世界的'操作系统':Docker 是进程,K8s 是管理所有进程的操作系统。"


二、K8s 的架构:Master 和 Worker

"先看 K8s 的骨架。"老周画:

Kubernetes 集群架构:
  ┌────────────────────────────────────────┐
  │ 控制平面(Master/Control Plane)—— 大脑    │
  │  ├─ kube-apiserver :所有请求的入口        │
  │  ├─ scheduler     :决定 Pod 跑哪台机器    │
  │  ├─ controller    :保证"期望状态"(说3个就3个)│
  │  └─ etcd          :集群的"数据库"(状态)   │
  ├────────────────────────────────────────┤
  │ 工作节点(Worker Node)—— 干活的          │
  │  ├─ Node1 ── kubelet + 容器运行时(Docker) │
  │  │    └─ 跑着一些 Pod                     │
  │  ├─ Node2 ── kubelet + 容器运行时          │
  │  │    └─ 跑着一些 Pod                     │
  │  └─ Node3 ── kubelet + 容器运行时          │
  │       └─ 跑着一些 Pod                     │
  └────────────────────────────────────────┘

"关键概念:声明式管理(Declarative)——你告诉 K8s'我想要 3 个 web 容器',K8s 保证任何时候都有 3 个(多了杀掉、少了补上)。你不指挥细节,你声明目标,K8s 自己搞定。 这就是 K8s 和手动操作的本质区别。"


三、第一个 K8s 对象:Pod

"K8s 最小的调度单位不是容器,是 Pod。"老周说:

Pod(豆荚):
  一组"紧耦合的容器"的集合(通常 1 个主容器 + 几个辅助容器)
  - 同一个 Pod 里的容器共享网络(同一个 IP)和存储
  - Pod 是"临时"的:挂了就被 K8s 重建(新 IP)

类比:
  容器 = 进程
  Pod  = 一个"工作单元"(一小组进程待在一起)
  节点 = 一台机器
  集群 = 整个机房

示例:云间书店的 AI 服务 Pod
  Pod "ai-pod":
    ├── 主容器:ai-recommend(AI 荐书服务)
    └── 辅助容器:sidecar(日志收集,共享日志文件)
# pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: ai-pod
spec:
  containers:
    - name: ai-recommend
      image: harbor.yunjian.com/library/ai:v1.2.3
      ports:
        - containerPort: 8000

"不过注意:生产上你很少直接创建 Pod——因为 Pod 挂了就没了。你要的是'永远有 Pod 在跑',这就要用 Deployment。"


四、Deployment:声明"我要几个 Pod"

"Deployment 是管理 Pod 的'指挥官'——它保证集群里始终有指定数量的 Pod。"老周说:

# deployment.yaml —— 云间书店 API 服务
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-deploy
spec:
  replicas: 3                  # 声明:我要 3 个副本
  selector:
    matchLabels:
      app: api
  template:                    # Pod 模板
    metadata:
      labels:
        app: api
    spec:
      containers:
        - name: api
          image: harbor.yunjian.com/library/api:v1.2.3
          ports:
            - containerPort: 5000
          resources:            # 资源限制(K8s 也要配!)
            requests:           # 申请量(调度依据)
              cpu: 250m
              memory: 256Mi
            limits:             # 上限(Cgroup)
              cpu: 500m
              memory: 512Mi
# 部署 / 查看 / 扩容 / 滚动更新
kubectl apply -f deployment.yaml     # 部署
kubectl get pods                     # 看 Pod
kubectl scale deploy api-deploy --replicas=5   # 手动扩容到 5 个
kubectl set image deploy api-deploy api=...:v1.3.0   # 滚动更新(不中断!)
kubectl rollout undo deploy api-deploy    # 回滚到上一版本

"Deployment 的三个能力:确保副本数、滚动更新(逐个替换,不中断服务)、一键回滚。 你只需要声明'要 3 个',Pod 挂了它自动补,更新时它逐个换——这就是'自愈 + 零停机发布'。"


五、Service:稳定的入口

"Pod 是临时的,IP 会变。Service 给一组 Pod 提供一个稳定的入口。"老周说:

# service.yaml —— 给 api-deploy 提供固定入口
apiVersion: v1
kind: Service
metadata:
  name: api-service
spec:
  selector:              # 挑哪些 Pod(按标签)
    app: api
  ports:
    - port: 5000         # Service 的端口
      targetPort: 5000   # 转发到 Pod 的端口
  type: ClusterIP        # 集群内部访问
Service 三种类型:
  ClusterIP :集群内部访问(默认,只能集群内)
  NodePort  :通过"节点 IP:端口"从外部访问
  LoadBalancer:云厂商负载均衡器(外部直接访问,生产常用)

工作方式:
  外部 → LoadBalancer → Service(api-service:5000) → 3 个 api Pod(自动负载均衡)
  Pod 挂了换了 IP 也没关系——Service 永远在,Pod 一直换

"Service = 稳定门牌号;Pod = 随时换房的住户。 门牌号永远不变,住户随便换——对外部来说,服务一直是稳定的。"


六、K8s 进阶三件套:HPA、ConfigMap、存储

"入门之后,还有三个进阶概念,先混个脸熟:"老周说:

① HPA(Horizontal Pod Autoscaler)弹性伸缩:
   根据 CPU/内存/流量,自动增减 Pod 数量
   → 双十一流量涨了?自动从 3 个 Pod 扩到 20 个
   → 流量降了?自动缩回 3 个

② ConfigMap / Secret 配置管理:
   ConfigMap:非敏感配置(如开关、URL)
   Secret   :敏感配置(密码、密钥,Base64 加密存储)
   → 配置和镜像分离,改配置不用重新打镜像!

③ 存储(PV/PVC):
   PV(PersistentVolume):一块"持久化存储"(像数据卷)
   PVC(PersistentVolumeClaim):Pod 申请用一块存储
   → 容器/Pod 随便换,数据在 PV 里不丢(和 Docker Volume 一个道理)
# hpa.yaml —— 自动扩缩容
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-deploy
  minReplicas: 3
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 60   # CPU 超 60% 就扩容

"HPA 是'自动档'——云间书店双十一再也不用半夜爬起来手动加服务器了。K8s 帮你盯着指标,自己扩、自己缩。"


七、章末:老周的第八、九层总结

第八层:K8s 入门
├── 架构:Master(大脑)+ Worker(干活)
├── 声明式:说目标,不指挥细节("要3个"就保持3个)
├── Pod:最小调度单位(一组容器)
├── Deployment:保证副本数 + 滚动更新 + 回滚
└── Service:稳定入口(ClusterIP/NodePort/LoadBalancer)
第九层:K8s 进阶
├── HPA:按指标自动扩缩容
├── ConfigMap/Secret:配置与镜像分离
└── PV/PVC:持久化存储(数据不随 Pod 丢)

"小陈,K8s 是很深的海洋,这一章只是带你'见了海'。但你已经知道核心思想了:声明目标,机器干活。 有了 K8s,云间书店的容器能跨机器调度、自动扩容、自动自愈——基础设施真正'活'了。"

"师傅,那代码改了之后,怎么自动变成新镜像、自动部署到 K8s?"小陈问,"难道还手动 build、手动 kubectl apply?"

"好问题!这就引出了容器时代最重要的自动化——CI/CD。下一章,我们打通'提交代码 → 自动构建 → 自动测试 → 自动部署'的流水线,让云间书店的发布变成'一键全自动'。"

✌ 语言