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:按这个顺序:
kubectl describe pod <name>看 Eventskubectl logs <name>看应用日志kubectl get events --sort-by=.metadata.creationTimestamp看集群事件- 检查资源限制是否太小导致 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.requests 和 resources.limits。
与其他章节的关联
| 本章内容 | 关联章节 | 关联点 |
|---|---|---|
| 容器镜像 | 第02章 Docker 容器化 | K8s 运行的就是 Docker 镜像 |
| 自动部署 | 第01章 CI/CD 流水线 | CI/CD 构建镜像后推送到 K8s |
| HPA 扩缩容 | 第06章 游戏性能监控 | HPA 基于监控指标自动扩缩 |
| 灰度发布 | 第09章 版本管理与灰度发布 | K8s 的滚动更新就是灰度发布 |
上一章:02-Docker容器化 | 下一章:04-代码质量与工程实践