CI/CD 流水线
用自动化生产线替代手工操作,让每次发版不再手忙脚乱
前置知识:Git 基本操作 + 基本的命令行使用
阅读指南(初学者必看)
为什么你需要学习 CI/CD?
你一定经历过这些场景:
- 改了一行代码,手动打包→手动上传→手动重启,结果忘了一步出问题了
- 上线后发现有个低级 Bug,但这个 Bug 本来可以自动检测出来
- 凌晨 2 点紧急修复,迷迷糊糊打包出错了
CI/CD 就是让机器替你做这些重复又容易出错的事。 代码推送后自动检测、自动构建、自动部署,不会漏步、不会出错。
学完本章,你能回答:
- CI 和 CD 分别是什么?有什么区别?
- 怎么用 GitHub Actions 搭建一条完整的游戏 CI/CD 流水线?
- 游戏项目的 CI/CD 和普通 Web 项目有什么不同?
- Git Flow 和 GitHub Flow 怎么选?
本文结构
第一部分:CI/CD 核心概念(建立认知)
第二部分:分支策略(团队协作基础)
第三部分:GitHub Actions 实战(动手搭建)
第四部分:GitLab CI 与 Jenkins(工具选型)
第五部分:游戏项目 CI/CD 的特殊考虑(游戏特有挑战)
一、什么是 CI/CD?
生活类比:CI/CD 就像"汽车工厂的自动化生产线"。
- CI(持续集成)= 零件自动检测:每个零件上线前自动检查质量
- CD(持续交付)= 自动组装出厂:检测通过的零件自动组装成整车
没有 CI/CD 时:
1. 开发者写代码
2. 手动运行测试
3. 手动打包
4. 手动上传到服务器
5. 手动重启服务
→ 容易出错、效率低、忘了某步就出问题
有 CI/CD 时:
1. 开发者推送代码到 Git
2. 自动触发流水线
3. 自动运行测试
4. 自动构建
5. 自动部署
→ 全自动,不会漏步
| 对比项 | 手动流程 | CI/CD 流程 |
|---|---|---|
| 测试 | 容易忘记 | 每次自动运行 |
| 构建 | 手动执行命令 | 自动触发 |
| 部署 | 手动上传+重启 | 自动部署+健康检查 |
| 出错率 | 高(人为疏漏) | 低(流程固定) |
| 回滚 | 麻烦 | 一键回滚 |
二、分支策略
Git Flow(适合大型项目)
使用 main、develop、feature、release、hotfix 多条分支,流程严谨但复杂。
| 分支 | 说明 |
|---|---|
| master/main | 线上环境!稳定!只能合入,不能直接提交! |
| develop | 开发环境!最新的开发代码! |
| feature/xxx | 功能分支!从 develop 切!开发完合回 develop! |
| release/xxx | 发布分支!从 develop 切!发布前测试!测完合 master+develop! |
| hotfix/xxx | 紧急修复!从 master 切!修完合 master+develop! |
# 开发新功能
git checkout develop
git checkout -b feature/add-shop
# ... 开发 ...
git checkout develop
git merge feature/add-shop
# 发布
git checkout develop
git checkout -b release/1.0.0
# ... 测试 ...
git checkout master
git merge release/1.0.0
git tag 1.0.0
GitHub Flow(适合敏捷团队)
只有 main 和 feature 分支,简单直接:
- 从 main 拉 feature 分支
- 开发完成后提 PR
- PR 合并后自动触发 CI/CD 部署
选型建议:10 人以下团队用 GitHub Flow;大型项目用 Git Flow。
三、GitHub Actions 实战
# .github/workflows/game-ci.yml
name: Game CI/CD
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
# 阶段1:代码检查和测试
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Lint
run: npm run lint
- name: Unit tests
run: npm run test:unit
- name: Integration tests
run: npm run test:integration
# 阶段2:构建
build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build game client
run: |
npm ci
npm run build:prod
- name: Build game server
run: |
cd server
mvn package -DskipTests
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: game-build
path: |
dist/
server/target/*.jar
# 阶段3:部署
deploy:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Deploy to staging
run: |
# 部署到预发布环境
ssh deploy@staging.example.com << 'EOF'
cd /opt/game
docker-compose pull
docker-compose up -d
EOF
- name: Run smoke tests
run: |
curl -f http://staging.example.com/health || exit 1
- name: Deploy to production
if: success()
run: |
# 灰度发布:先更新 10% 的服务器
# 确认无异常后全量发布
流水线三阶段解读
| 阶段 | 做什么 | 失败了怎么办 |
|---|---|---|
| Test | Lint + 单元测试 + 集成测试 | 阻止代码合并,开发者修复后重新推送 |
| Build | 构建客户端 + 服务端 + 上传产物 | 不进入部署阶段,检查构建配置 |
| Deploy | 部署到预发布 → 冒烟测试 → 部署到生产 | 自动回滚到上一版本 |
缓存与产物
缓存 = 把常用的东西放在手边,加速下次构建
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
产物 = 流水线中间产出的半成品,供后续阶段使用
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: game-build
path: dist/
四、GitLab CI 与 Jenkins
GitLab CI 示例
# .gitlab-ci.yml
stages:
- build
- test
- deploy
build:
stage: build
image: node:20-alpine
script:
- npm ci
- npm run build
artifacts:
paths:
- dist/
expire_in: 1 hour
test:
stage: test
image: node:20-alpine
script:
- npm ci
- npm run test
deploy:
stage: deploy
script:
- echo "Deploying to production..."
only:
- main
工具选型建议
| 工具 | 特点 | 推荐场景 |
|---|---|---|
| GitHub Actions | GitHub 自带,生态丰富 | 代码在 GitHub 的项目 |
| GitLab CI | GitLab 自带,自托管友好 | 代码在 GitLab 或需要私有化部署 |
| Jenkins | 老牌,插件极多 | 复杂流水线、多项目统一管理 |
五、游戏项目 CI/CD 的特殊考虑
游戏和普通 Web 项目的区别:
1. 客户端构建
- Cocos/Laya 构建耗时长(5~15 分钟)
- 需要构建多平台(Web/微信/Android/iOS)
- 资源压缩和加密
2. 服务端部署
- 不能直接停机更新(玩家在线!)
- 需要优雅停机(等当前战斗结束)
- 热更新 vs 全量更新
3. 版本兼容
- 老版本客户端需要兼容新版本服务器
- 协议版本号管理
- 强更 vs 非强更策略
4. 回滚
- 游戏回滚比 Web 复杂(涉及数据迁移)
- 需要数据库备份和回滚方案
5. 安全扫描
- 依赖漏洞扫描(Trivy, Snyk)
- 镜像签名确保可信
游戏 CI/CD 与普通 Web CI/CD 对比
| 对比项 | 普通 Web | 游戏项目 |
|---|---|---|
| 构建时间 | 1-3 分钟 | 5-15 分钟(多平台) |
| 部署方式 | 直接替换 | 优雅停机 + 热更新 |
| 版本兼容 | 通常只管最新 | 新服务器兼容老客户端 |
| 回滚难度 | 简单(切换版本) | 复杂(可能涉及数据迁移) |
| 测试重点 | 功能正确性 | 功能 + 性能 + 弱网 |
| 安全要求 | 常规 | 更高(防充值漏洞、物品复制) |
自问自答
Q:CI 和 CD 有什么区别? A:CI(持续集成)关注的是"代码合并后自动检测问题"——自动运行测试、Lint 等。CD(持续交付/持续部署)关注的是"检测通过后自动部署到环境"。CI 是 CD 的前提。
Q:GitHub Actions 的流水线在什么时候触发?
A:可以在 on 字段配置。常见的触发条件:push(代码推送时)、pull_request(创建 PR 时)、schedule(定时触发)、workflow_dispatch(手动触发)。游戏项目通常在 push 到 main/develop 时自动触发。
Q:游戏服务端为什么不能直接停机更新? A:因为玩家可能正在进行战斗!直接停机会导致玩家战斗中断、数据丢失。需要"优雅停机":先停止接受新连接,等当前战斗结束后再关闭。
Q:什么是灰度发布?为什么游戏需要灰度发布? A:灰度发布是逐步扩大新版本的覆盖范围(1%→5%→10%→100%)。游戏需要灰度发布因为:1)新版本可能有未发现的 Bug,灰度可以控制影响范围;2)游戏涉及真实充值,出问题损失大;3)游戏用户量大,全量出问题影响面太广。
Q:GitHub Actions 和 GitLab CI 选哪个? A:看你代码放在哪。GitHub 项目用 Actions,GitLab 项目用 GitLab CI。两者概念相似,会一个很容易迁移到另一个。
实践任务
- 任务1:搭建 GitHub Actions 流水线,实现推送代码后自动运行 Lint 和测试
- 任务2:实现多平台自动构建(Web + 微信小游戏),上传构建产物
- 任务3:实现自动部署 + 健康检查,部署失败自动回滚
- 任务4:配置流水线通知(部署成功/失败发钉钉或企业微信消息)
- 任务5:集成安全扫描(Trivy 扫描 Docker 镜像漏洞)
- 任务6:编写流水线 README 文档,记录触发条件、阶段说明、常见问题
初学者常见错误
错误1:YAML 缩进错误
问题: YAML 对缩进极其敏感,多空格或少空格都会报错。 解决: 使用编辑器显示空格字符;用在线 YAML 校验工具。
错误2:缓存配置不当
问题: 没有缓存依赖,每次构建都重新下载,耗时很长。
解决: 正确配置 actions/cache,缓存 ~/.npm、~/.m2 等目录。
错误3:在代码中提交密钥
问题: 把密码、API Key 直接写在配置文件里提交到仓库。 解决: 使用仓库 Secrets(GitHub Settings → Secrets and variables → Actions)。
错误4:流水线没有失败通知
问题: 流水线失败了但没人知道,问题被掩盖。 解决: 配置通知渠道(钉钉/企业微信/邮件),失败时立即通知。
与其他章节的关联
| 本章内容 | 关联章节 | 关联点 |
|---|---|---|
| Docker 构建 | 第02章 Docker 容器化 | CI/CD 的构建阶段产出 Docker 镜像 |
| K8s 部署 | 第03章 Kubernetes 编排 | CI/CD 的部署阶段将镜像部署到 K8s |
| 测试阶段 | 第05章 游戏自动化测试 | CI/CD 自动运行单元测试和压力测试 |
| 灰度发布 | 第09章 版本管理与灰度发布 | CI/CD 部署阶段实现灰度发布策略 |
| Git 规范 | 第04章 代码质量与工程实践 | 分支策略是 CI/CD 触发的基础 |
上一章:学习路线图 | 下一章:02-Docker容器化