Kubernetes 编排

用自动化车队管理系统管理你的容器,实现弹性扩缩容和自愈

前置知识:第01章 CI/CD 流水线 + 第02章 Docker 容器化


阅读指南(初学者必看)

为什么你需要学习 Kubernetes?

Docker 解决了"应用怎么标准化运行"的问题,但带来了新问题:

  • 一个游戏有 5 个服务,每个服务 3 个实例,怎么管理 15 个容器?
  • 突然来了一批玩家,怎么自动扩容?玩家走了怎么缩容?
  • 一个容器挂了,怎么自动恢复?

Kubernetes 就是容器的"自动化车队管理系统"。 你声明"我要 3 个房间服务器",K8s 保证始终有 3 个在运行——少了自动补,多了自动减。

学完本章,你能回答:

  • K8s 的 Pod、Deployment、Service、HPA 分别是什么?
  • 怎么把游戏服务器部署到 K8s?
  • 游戏服务器的有状态、长连接、优雅关闭怎么处理?
  • minikube 和 kind 怎么选?

本文结构

第一部分:K8s 核心概念(建立认知)
第二部分:游戏服务器 K8s 部署(动手部署)
第三部分:游戏服务器的特殊考虑(游戏特有挑战)
第四部分:常用命令与滚动更新

一、K8s 核心概念

生活类比:K8s 就像"自动化车队管理系统"。

  • Pod = 一辆卡车(可能装一个或多个集装箱)
  • Deployment = 车队(管理一组卡车)
  • Service = 调度中心(知道哪辆卡车在哪)
  • Ingress = 收费站入口(把流量导向正确的车)
K8s 架构:

Master 节点(控制面)
├── API Server    ── 接收操作指令
├── Scheduler     ── 决定 Pod 运行在哪个节点
├── Controller    ── 维护期望状态
└── etcd          ── 存储集群状态

Worker 节点(数据面)
├── kubelet       ── 管理 Pod 生命周期
├── kube-proxy    ── 网络代理
└── 容器运行时     ── Docker/containerd

K8s 核心资源对比

资源 类比 作用 游戏场景
Pod 卡车 最小运行单元 一个游戏服务进程
Deployment 车队 管理 Pod 副本数 3 个房间服务器副本
Service 调度中心 稳定访问入口 room-server:9000
HPA 调度策略 自动扩缩容 玩家多时自动扩容
Ingress 收费站 外部流量入口 域名路由到服务
ConfigMap 配置手册 配置管理 数据库连接串等
Secret 保险柜 敏感信息 密码、密钥等

二、游戏服务器 K8s 部署

# room-server-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: room-server
spec:
  replicas: 3  # 3 个房间服务器
  selector:
    matchLabels:
      app: room-server
  template:
    metadata:
      labels:
        app: room-server
    spec:
      containers:
      - name: room-server
        image: game/room-server:v1.2.0
        ports:
        - containerPort: 9000
        resources:
          requests:
            cpu: "500m"
            memory: "1Gi"
          limits:
            cpu: "2000m"
            memory: "4Gi"
        env:
        - name: JAVA_OPTS
          value: "-XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:+UseContainerSupport"
        - name: SPRING_DATASOURCE_URL
          valueFrom:
            configMapKeyRef:
              name: game-config
              key: database-url
        livenessProbe:
          httpGet:
            path: /health
            port: 9000
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 9000
          initialDelaySeconds: 10
          periodSeconds: 5
---
# Service
apiVersion: v1
kind: Service
metadata:
  name: room-server
spec:
  selector:
    app: room-server
  ports:
  - port: 9000
    targetPort: 9000
  type: ClusterIP
---
# HPA(自动扩缩容)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: room-server-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: room-server
  minReplicas: 3
  maxReplicas: 20
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Pods
    pods:
      metric:
        name: active_rooms
      target:
        type: AverageValue
        averageValue: "500"  # 每个 Pod 最多 500 个房间

两种探针的区别

探针 作用 失败后果 游戏场景
Liveness Probe 判断容器是否存活 重启容器 服务死锁时自动重启
Readiness Probe 判断容器是否就绪 从 Service 摘除 启动中不接收流量

三、游戏服务器的特殊考虑

游戏 K8s 部署的难点:

1. 有状态 vs 无状态
   - 匹配服务:无状态,随便扩缩
   - 房间服务:有状态!缩容时要等房间结束

2. 长连接管理
   - WebSocket 连接在 Pod 里
   - Pod 被杀 → 连接断开
   - 需要:优雅关闭 + 断线重连

3. 优雅关闭
   - K8s 删 Pod 时发送 SIGTERM
   - 应用需要:
     a. 停止接受新连接
     b. 等待现有战斗结束(或迁移)
     c. 关闭连接
   - 设置 terminationGracePeriodSeconds: 300(5分钟)

4. 就绪探针
   - 新 Pod 启动后,先通过就绪检查才接收流量
   - 避免请求打到还没准备好的 Pod

有状态服务 vs 无状态服务

对比项 无状态(匹配服务) 有状态(房间服务)
扩缩容 随意扩缩 缩容需等房间结束
负载均衡 随机分配 需要考虑房间亲和
持久化 不需要 需要保存战斗状态
失败恢复 直接重启新实例 需要恢复战斗数据
网络标识 不需要固定 可能需要固定 Service

四、常用命令与滚动更新

K8s 常用命令速查

# 查看资源
kubectl get pods                     # 查看 Pod
kubectl get deployments              # 查看 Deployment
kubectl get services                 # 查看 Service
kubectl get hpa                      # 查看 HPA

# 部署与更新
kubectl apply -f room-server.yaml    # 部署/更新
kubectl set image deployment/room-server room-server=game/room-server:v1.3.0  # 更新镜像
kubectl rollout status deployment/room-server  # 查看滚动更新状态
kubectl rollout undo deployment/room-server    # 回滚到上一版本

# 调试
kubectl logs <pod-name>              # 查看日志
kubectl exec -it <pod-name> -- /bin/sh  # 进入容器
kubectl describe pod <pod-name>      # 查看 Pod 详情
kubectl top pods                     # 查看 Pod 资源使用

滚动更新流程

当前状态: [Pod-v1] [Pod-v1] [Pod-v1]
              |
              v
创建新 Pod: [Pod-v1] [Pod-v1] [Pod-v1] [Pod-v2]
              |
              v
新 Pod Ready: [Pod-v1] [Pod-v1] [Pod-v2]
              |
              v
继续替换: [Pod-v1] [Pod-v2] [Pod-v2]
              |
              v
完成: [Pod-v2] [Pod-v2] [Pod-v2]

minikube vs kind

工具 特点 适用场景
minikube 单节点 K8s 集群,简单易用 本地开发和学习
kind 用 Docker 容器模拟 K8s 节点,可创建多节点集群 CI/CD 测试、多节点场景验证

学习推荐 minikube(更简单),CI/CD 推荐 kind(更快更轻量)。


自问自答

Q:Pod 和容器是什么关系? A:Pod 是 K8s 最小调度单元,一个 Pod 可以包含一个或多个容器。大多数情况下一个 Pod 只有一个容器。多容器 Pod 用于"边车"模式,比如主容器 + 日志采集容器。

Q:为什么游戏房间服务不适合直接用 HPA 缩容? A:HPA 缩容时会随机杀 Pod,但房间服务 Pod 里可能有正在进行的战斗!直接杀掉会导致玩家断线。解决方案:1)自定义指标(active_rooms)避免缩容有房间的 Pod;2)优雅关闭等战斗结束;3)使用 StatefulSet 管理有状态服务。

Q:livenessProbe 和 readinessProbe 有什么区别? A:Liveness 失败 → K8s 重启容器(服务死锁了需要重启)。Readiness 失败 → K8s 把 Pod 从 Service 摘除(服务还在启动中,暂时不接收流量)。两个都要配!

Q:minikube 和 kind 有什么区别? A:minikube 是单节点 K8s 集群,适合本地开发和测试。kind(Kubernetes in Docker)用 Docker 容器模拟 K8s 节点,可以创建多节点集群。学习推荐 minikube(更简单),CI/CD 推荐 kind(更快更轻量)。

Q:K8s 看起来好复杂,小公司需要吗? A:10 人以下团队,Docker Compose + 云服务器就够了。但建议了解 K8s 概念,面试和架构设计时很有用。当服务超过 5 个、服务器超过 3 台时,再考虑 K8s。

Q:怎么排查 K8s Pod 启动失败? A:按这个顺序:

  1. kubectl describe pod <name> 看 Events
  2. kubectl logs <name> 看应用日志
  3. kubectl get events --sort-by=.metadata.creationTimestamp 看集群事件
  4. 检查资源限制是否太小导致 OOMKilled

实践任务

  • 任务1:搭建 K8s 集群(minikube 或 kind),部署一个 Nginx 应用验证集群正常
  • 任务2:部署游戏服务器到 K8s,配置 Deployment + Service + ConfigMap
  • 任务3:配置 HPA,模拟负载测试自动扩缩容(用 Locust)
  • 任务4:实现优雅关闭机制,验证 Pod 删除时能正确处理完进行中的战斗
  • 任务5:模拟 Pod 故障,验证 K8s 自动恢复能力(手动删 Pod 看是否自动重建)

初学者常见错误

错误1:K8s 中 Service 选不到 Pod

问题: Service 的 selector 和 Pod 的 labels 不匹配。 解决: kubectl get pods --show-labels 检查标签。

错误2:YAML 缩进错误

问题: YAML 对缩进极其敏感,多空格或少空格都会报错。 解决: 使用编辑器显示空格字符;用在线 YAML 校验工具。

错误3:没有配置资源限制

问题: Pod 无限使用资源,导致节点 OOM,影响其他服务。 解决: 在 Pod spec 中配置 resources.requestsresources.limits


与其他章节的关联

本章内容 关联章节 关联点
容器镜像 第02章 Docker 容器化 K8s 运行的就是 Docker 镜像
自动部署 第01章 CI/CD 流水线 CI/CD 构建镜像后推送到 K8s
HPA 扩缩容 第06章 游戏性能监控 HPA 基于监控指标自动扩缩
灰度发布 第09章 版本管理与灰度发布 K8s 的滚动更新就是灰度发布

上一章:02-Docker容器化 | 下一章:04-代码质量与工程实践