容器化部署
概述
容器化让部署从"手动敲命令"变成"一条命令拉起全栈":镜像即部署单元、环境一致、扩缩容简单。本文讲游戏服务器的容器化三件套:Docker 镜像构建(多阶段 JRE 镜像)、Docker Compose 编排(本地/测试环境)、K8s 部署(生产集群)。
一、Docker 镜像构建
1.1 多阶段构建
多阶段构建目的:
构建环境(JDK + Maven)大
运行镜像只要 JRE(小、安全)
构建产物只 COPY 最终 jar
// Dockerfile 多阶段
FROM maven:3.9-eclipse-temurin-17 AS builder
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline # 缓存依赖
COPY src ./src
RUN mvn package -DskipTests
FROM eclipse-temurin:17-jre # 运行阶段
WORKDIR /app
COPY --from=builder /build/target/game-logic.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]1.2 镜像优化
镜像瘦身:
基础镜像:JRE 而非 JDK(temurin-jre / alpine)
分层缓存:依赖层与业务层分离(改代码不重新下依赖)
时区/字体:游戏可能用到(TZ、fontconfig)
安全:非 root 用户运行、最小权限
健康检查:
HEALTHCHECK 探测(/actuator/health)
K8s 依赖它做滚动更新判定// 运行用户 + 健康检查
FROM eclipse-temurin:17-jre
RUN useradd -m appuser
COPY --from=builder /build/target/game-logic.jar /app/app.jar
USER appuser
HEALTHCHECK CMD curl -f http://localhost:8080/actuator/health || exit 1
ENTRYPOINT ["java", "-Xmx2g", "-jar", "/app/app.jar"]二、Docker Compose 编排
2.1 编排文件
Compose 用途:
本地开发 / 测试环境(一条命令拉起全栈)
服务:网关 + 逻辑 + Redis + MySQL + MQ
// docker-compose.yml(简化示例)
services:
gateway:
build: ./gateway
ports: ["8080:8080"]
depends_on: [logic, redis, mysql]
logic:
build: ./game-logic
environment:
- REDIS_HOST=redis
- MYSQL_HOST=mysql
depends_on: [redis, mysql]
redis:
image: redis:7-alpine
ports: ["6379:6379"]
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
volumes: [mysql-data:/var/lib/mysql]# 常用命令
docker compose up -d # 启动全栈
docker compose up -d --build # 重新构建
docker compose logs -f logic # 看日志
docker compose down # 停止2.2 配置管理
容器内配置:
环境变量注入(REDIS_HOST 等)
配置中心(Nacos/Apollo)优先(见配置管理)
本地配置模板(application-prod.yml + env 覆盖)
数据卷:
MySQL 数据卷持久化
日志目录挂载(采集用)
配置文件挂载(热更新场景)三、K8s 部署配置
3.1 核心资源
K8s 核心对象:
Deployment:无状态服务(网关/逻辑)副本管理
Service:服务发现与负载均衡
StatefulSet:有状态(MySQL/Redis 可外部托管)
ConfigMap/Secret:配置与密钥
HPA:自动扩缩容// Deployment 示例(game-logic)
apiVersion: apps/v1
kind: Deployment
metadata: { name: game-logic }
spec:
replicas: 3
selector: { matchLabels: { app: game-logic } }
template:
metadata: { labels: { app: game-logic } }
spec:
containers:
- name: game-logic
image: registry/game-logic:1.4.2
ports: [{ containerPort: 8080 }]
resources:
requests: { cpu: "1", memory: "2Gi" }
limits: { cpu: "2", memory: "4Gi" }
readinessProbe: # 就绪探针
httpGet: { path: /actuator/health, port: 8080 }
---
apiVersion: v1
kind: Service
metadata: { name: game-logic }
spec:
selector: { app: game-logic }
ports: [{ port: 8080, targetPort: 8080 }]3.2 游戏服务的 K8s 注意点
游戏服务特点:
网关有状态(长连接 + 会话)→ 用 Headless Service + 固定路由
逻辑分片(房间绑定节点)→ 节点亲和 / 分片路由(见分片章节)
缩容安全:先摘流再缩(优雅关闭,见灰度章节)
HPA 依据:CPU / 在线连接数(自定义指标)// 节点亲和(分片节点绑定)
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: shard
operator: In
values: ["shard-1"]// HPA(按 CPU 自动扩缩)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata: { name: game-logic-hpa }
spec:
scaleTargetRef: { apiVersion: apps/v1, kind: Deployment, name: game-logic }
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource: { name: cpu, target: { type: Utilization, averageUtilization: 70 } }四、发布与回滚
4.1 滚动发布
K8s 滚动发布:
镜像更新 → 新 Pod 分批替换旧 Pod
readinessProbe 判定就绪才继续
回滚:kubectl rollout undo(保留历史版本)
发布注意:
网关多副本(滚动期间新旧并存)
逻辑节点对局保护(见灰度章节)
数据库兼容(先加字段后启用代码)kubectl set image deploy/game-logic \
game-logic=registry/game-logic:1.5.0
kubectl rollout status deploy/game-logic # 观察
kubectl rollout undo deploy/game-logic # 回滚4.2 存储与有状态组件
有状态组件建议:
MySQL/Redis 用云托管(RDS/云 Redis)而非自建 StatefulSet
确实自建 → StatefulSet + PVC + 备份
游戏自建依赖少,托管省运维
日志采集:
DaemonSet Filebeat 采集容器日志(见日志章节)
或 stdout 由平台采集五、实现要点
容器化核心:
Docker 多阶段构建(JDK 构建 + JRE 运行,镜像小)
Compose 编排本地/测试环境(一条命令全栈)
K8s 生产部署(Deployment/Service/探针/HPA)
发布回滚(滚动更新 + rollout undo)
游戏注意:分片亲和、网关有状态、缩容安全
常见坑:
镜像含 JDK/源码 → 大且不安全
无探针 → 滚动更新误杀
缩容直接杀节点 → 对局中断
配置写死镜像里 → 环境不通用
与其他系统衔接:
配置管理 → Nacos/Apollo(容器内注入)
发布策略 → 灰度发布章节
流水线 → CI/CD 章节
监控 → Prometheus 采集容器指标