第三章 开发环境搭建:Git版本控制、Docker容器化部署、CI/CD流水线
说实话,很多新手项目死在第一步——环境不一致。你在本地跑得好好的,部署到服务器就崩了。我见过太多次了。所以这一章,咱们把地基打牢。
3.1 Git版本控制:不只是git add和git commit
Git这东西,很多人用了好几年还停留在「三板斧」阶段。但做游戏服务器,分支策略直接决定团队协作效率。
3.1.1 分支模型怎么选?
我个人习惯用Git Flow的简化版。为什么?因为游戏服务器迭代快,但又要稳定。
- master分支:只放线上版本。每次合并必须经过Code Review。
- develop分支:日常开发的主干。所有feature分支从这里拉。
- feature/xxx分支:每个新功能一个分支。比如feature/chat-system。
- release分支:发版前一周拉出来,只修bug,不加功能。
- hotfix分支:线上出紧急bug时用。修完直接合master和develop。
避坑指南:我曾经有个项目,团队20个人全在develop上开发。结果某天有人push了一个未完成的副本系统,整个服务器启动不了。从那以后,我强制要求feature分支必须经过CI才能合入。
3.1.2 提交信息规范
你想想看,如果提交信息全是「fix bug」、「update」,三个月后谁看得懂?我定了个简单规则:
类型(模块): 简短描述
示例:
feat(login): 添加微信登录支持
fix(match): 修复匹配超时后玩家状态未重置
refactor(db): 重构玩家数据缓存逻辑
docs(readme): 更新部署文档
类型我用这几个:feat、fix、refactor、docs、test、chore。模块名对应项目里的目录名。
3.1.3 .gitignore里该放什么?
嗯,这里要注意。游戏服务器项目里,有些文件绝对不能进版本库:
- 编译产物:.o、.exe、.dll
- 配置文件里的敏感信息:数据库密码、密钥
- 日志文件:*.log
- IDE配置:.idea、.vscode
- 临时文件:*.tmp、*.swp
小技巧:我习惯在项目根目录放一个gitignore模板,每次新项目直接复制。省得漏掉什么。
3.2 Docker容器化部署:一次构建,到处运行
说白了,Docker就是给你的游戏服务器套个「箱子」。箱子里环境一模一样,不管搬到哪台机器上都能跑。
3.2.1 Dockerfile怎么写?
以C++游戏服务器为例,我一般用多阶段构建:
# 第一阶段:编译
FROM ubuntu:20.04 AS builder
WORKDIR /app
COPY . .
RUN apt-get update && apt-get install -y cmake g++
RUN cmake . && make -j4
# 第二阶段:运行
FROM ubuntu:20.04
WORKDIR /app
COPY --from=builder /app/server .
COPY config/ ./config/
EXPOSE 8888
CMD ["./server"]
为什么用多阶段?因为最终镜像里只有可执行文件和配置,没有编译工具链。镜像体积从2GB降到200MB。我在项目中遇到过,镜像太大导致部署时网络传输慢,玩家等得骂娘。
3.2.2 docker-compose编排多服务
游戏服务器通常不是单体的。登录服、游戏服、数据库、缓存,得一起跑。docker-compose就是干这个的:
version: '3.8'
services:
login-server:
build: ./login
ports:
- "8080:8080"
depends_on:
- redis
- mysql
game-server:
build: ./game
ports:
- "8888:8888"
depends_on:
- redis
- mysql
redis:
image: redis:6-alpine
volumes:
- redis-data:/data
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- mysql-data:/var/lib/mysql
volumes:
redis-data:
mysql-data:
注意:密码别硬编码在docker-compose.yml里。用环境变量文件.env,记得把.env加到.gitignore里。我曾经看到有人把生产库密码直接push到GitHub上,那场面...嗯,不提了。
3.3 CI/CD流水线:让机器替你干活
手动部署?那是上个时代的事了。CI/CD的核心思想很简单:代码一提交,自动编译、测试、部署。我选GitLab CI,因为和GitLab集成得好,不用额外搭Jenkins。
3.3.1 .gitlab-ci.yml配置
stages:
- build
- test
- deploy
build-job:
stage: build
script:
- docker build -t game-server:${CI_COMMIT_SHORT_SHA} .
- docker tag game-server:${CI_COMMIT_SHORT_SHA} registry.example.com/game-server:latest
- docker push registry.example.com/game-server:latest
only:
- develop
- master
test-job:
stage: test
script:
- docker run game-server:${CI_COMMIT_SHORT_SHA} ./run_tests
only:
- develop
deploy-staging:
stage: deploy
script:
- ssh deploy@staging-server "docker pull registry.example.com/game-server:latest && docker-compose up -d"
only:
- develop
deploy-production:
stage: deploy
script:
- ssh deploy@prod-server "docker pull registry.example.com/game-server:latest && docker-compose up -d"
only:
- master
when: manual
你看,develop分支的代码合并后,自动构建镜像、跑测试、部署到测试服。master分支的部署到生产服,但需要手动确认——这个「手动确认」救过我很多次。
3.3.2 流水线里加什么检查?
我建议至少加这三道关卡:
- 编译检查:代码能不能编译通过?
- 单元测试:核心逻辑有没有被破坏?
- 代码风格检查:有没有人偷偷用了tab而不是空格?
个人经验:我曾经在流水线里加了性能测试——每次提交都跑一次压测,看响应时间有没有明显变化。虽然跑一次要10分钟,但抓到过好几次因为加日志导致性能下降的问题。
3.4 统一开发规范:别让代码变成「屎山」
游戏服务器项目,代码量动辄几十万行。没有规范,三个月后连自己写的代码都看不懂。
3.4.1 代码风格
我用的C++,风格是这样的:
| 规则 | 示例 | 说明 |
|---|---|---|
| 命名 | 类名:PlayerManager 函数:GetPlayerById 变量:player_count |
类名大驼峰,函数大驼峰,变量小写下划线 |
| 缩进 | 4个空格 | 不用tab,不同编辑器tab宽度不一样 |
| 大括号 | if (condition) { doSomething(); } |
左大括号不换行 |
| 行长度 | 不超过120字符 | 太长的话,代码review时横向滚动很烦 |
3.4.2 日志格式
日志这东西,平时没人看,出问题的时候就是救命稻草。我定了个统一格式:
[时间] [日志级别] [模块] [线程ID] 消息内容
示例:
[2024-01-15 14:30:22.123] [INFO] [LoginServer] [12345] 玩家[10001]登录成功,IP: 192.168.1.1
[2024-01-15 14:30:22.456] [ERROR] [GameServer] [12346] 玩家[10001]创建房间失败,原因:房间已满
为什么要有线程ID?因为游戏服务器是多线程的,没有线程ID,你根本不知道日志是哪个线程打的,排查并发问题时会疯掉。
小技巧:我习惯在日志里加一个「请求追踪ID」。玩家每次操作都带一个唯一ID,这样可以把一次操作的所有日志串起来。排查线上问题时,直接搜这个ID就行。
3.4.3 配置文件规范
配置文件用JSON还是YAML?我选YAML。因为支持注释,而且可读性好。但有个坑:YAML对缩进敏感,一个空格不对就解析失败。
# 游戏服务器配置
server:
name: "game-server-01"
port: 8888
max_connections: 10000
database:
host: "192.168.1.100"
port: 3306
name: "game_db"
# 密码通过环境变量注入,不写在这里
password: ${DB_PASSWORD}
log:
level: "info"
path: "/var/log/game-server/"
max_size: 100 # MB
max_backups: 30
嗯,到这里,开发环境的基础设施就搭好了。Git管代码,Docker管环境,CI/CD管自动化,规范管质量。这套东西我用了好几年,从几个人到上百人的团队都适用。下一章,咱们开始写真正的游戏服务器代码。