3. 版本管理与快照:版本号规范、制品仓库管理、基础设施即代码(IaC)状态快照
版本管理这事儿,看着简单,但坑特别多。我见过不少团队,上线前发现回滚不了,一查原因——版本号乱写,制品找不到了,或者 IaC 状态跟实际环境对不上。说白了,回滚保护的第一步,就是把「版本」这件事管明白。
这一章,咱们就聊聊版本号怎么定、制品怎么存、IaC 状态怎么快照。这三件事做好了,回滚才有底气。
3.1 版本号规范:别让版本号成为回滚的绊脚石
版本号不是随便写的。它承载了语义、顺序、兼容性信息。回滚时,你得知道哪个版本更老、哪个版本兼容哪个环境。
3.1.1 语义化版本号(SemVer)
我个人习惯用语义化版本号,格式是 MAJOR.MINOR.PATCH:
- MAJOR:不兼容的 API 变更
- MINOR:向下兼容的功能新增
- PATCH:向下兼容的问题修复
举个例子:2.1.3 表示主版本 2,次版本 1,补丁 3。回滚时,如果从 2.2.0 回退到 2.1.3,你得确认 API 没变。
核心原则:版本号必须可比较、可追溯、可排序。回滚脚本依赖版本号的大小比较来决定回退到哪个版本。
3.1.2 预发布版本与构建元数据
光有 MAJOR.MINOR.PATCH 还不够。我在项目中遇到过,测试环境和生产环境用同一个版本号,结果回滚时搞混了。后来我们加上了预发布标签:
1.0.0-alpha.1
1.0.0-beta.2
1.0.0-rc.1
1.0.0
预发布版本用 - 分隔,优先级低于正式版本。构建元数据用 + 分隔,比如 1.0.0+build.20250315,但不参与优先级比较。
小技巧:我建议在 CI/CD 中自动生成构建元数据,包含构建时间戳和 Git commit hash。这样每个版本都能追溯到源码。
3.1.3 版本号规范对比
| 类型 | 格式示例 | 适用场景 | 回滚注意事项 |
|---|---|---|---|
| 语义化版本 | 2.1.3 |
通用,适合对外 API | 需检查 MAJOR 是否一致 |
| 日历版本 | 2025.03.15 |
内部工具、夜间构建 | 按日期排序,简单直观 |
| 哈希版本 | git-abc1234 |
开发环境、临时构建 | 不可排序,需配合标签 |
| 混合版本 | 1.2.3-rc.1+build.20250315 |
大型项目,多环境部署 | 解析复杂,需工具支持 |
3.2 制品仓库管理:把制品管好,回滚才有弹药
版本号定好了,制品得存好。制品仓库不是简单的文件服务器,它要支持版本管理、权限控制、元数据检索。
3.2.1 制品仓库选型
我常用的制品仓库有几种:
- Docker Registry:存容器镜像,支持 tag 和 digest
- Nexus / Artifactory:通用制品仓库,支持 Maven、npm、PyPI 等
- S3 / GCS:对象存储,适合大文件,但需要自己管理版本
选型时,我建议优先考虑支持「不可变制品」的仓库。什么意思?就是制品一旦上传,就不能覆盖或删除。这样可以防止回滚时发现制品被误删了。
我曾经踩过的坑:有一次,同事手动覆盖了 Docker 镜像的 latest 标签,结果回滚时拉下来的还是新版本。从那以后,我们强制要求所有生产环境使用 digest 拉取镜像,而不是 tag。
3.2.2 制品生命周期管理
制品不是存了就不管了。你得制定清理策略:
- 保留策略:保留最近 N 个版本,或者保留最近 M 天内的版本
- 归档策略:超过一定时间的制品,移到冷存储
- 删除策略:确认不再需要的制品,标记删除
举个例子,我们的 Docker 镜像保留策略:
# 保留最近 10 个版本
# 保留最近 30 天的版本
# 保留所有带 rc、release 标签的版本
# 其余自动清理
3.2.3 制品元数据管理
制品本身只是二进制文件,但回滚时需要知道它的上下文。我建议在制品仓库中存储以下元数据:
| 元数据字段 | 说明 | 示例 |
|---|---|---|
| 版本号 | 语义化版本号 | 2.1.3 |
| 构建时间 | 制品构建的 UTC 时间 | 2025-03-15T10:30:00Z |
| Git Commit | 对应的源码 commit hash | abc1234def5678 |
| 构建环境 | CI 任务 ID、构建机器信息 | jenkins-build-1234 |
| 依赖清单 | 制品依赖的库和版本 | spring-boot:2.7.0 |
3.3 基础设施即代码(IaC)状态快照
应用回滚了,基础设施也得跟着回滚。IaC 状态快照就是基础设施的「版本号」。
3.3.1 为什么需要 IaC 状态快照?
你想想看,应用回滚到旧版本,但数据库 schema 已经变了,或者负载均衡配置改了,那应用能正常工作吗?肯定不能。
IaC 状态快照记录了某个时间点基础设施的完整状态。回滚时,我们可以把基础设施恢复到那个状态。
3.3.2 Terraform 状态快照
我用 Terraform 比较多。它的状态文件 terraform.tfstate 记录了所有资源的状态。我建议:
- 远程存储状态:存到 S3、GCS 或 Consul,不要放本地
- 状态版本管理:每次
terraform apply前,自动备份当前状态 - 状态锁定:防止多人同时操作导致状态损坏
举个例子,我们的 Terraform 状态快照脚本:
#!/bin/bash
# 在 apply 前备份当前状态
TIMESTAMP=$(date +%Y%m%d%H%M%S)
aws s3 cp s3://my-state-bucket/terraform.tfstate \
s3://my-state-bucket/backups/terraform.tfstate.$TIMESTAMP
# 执行 apply
terraform apply -auto-approve
# 如果失败,回滚状态
if [ $? -ne 0 ]; then
aws s3 cp s3://my-state-bucket/backups/terraform.tfstate.$TIMESTAMP \
s3://my-state-bucket/terraform.tfstate
echo "回滚状态完成"
fi
3.3.3 配置管理工具的快照
除了 Terraform,Ansible、Puppet、Chef 这些配置管理工具也需要快照。我习惯的做法是:
- 版本控制配置:所有 playbook、manifest 都放在 Git 仓库
- 标记发布版本:每次变更打一个 Git tag,比如
infra-v2.1.3 - 记录执行结果:每次执行后,把节点的最终状态保存下来
我的经验:Ansible 的 --check 模式可以预览变更,但不会真正执行。我建议在回滚前先用 --check 模式跑一遍,确认回滚操作不会引入新问题。
3.4 版本管理与快照的核心逻辑
说了这么多,咱们用一张图把核心逻辑串起来:
3.5 实战建议
最后,给你几个实战建议:
- 版本号自动化:在 CI/CD 中自动生成版本号,不要手动填写
- 制品不可变:一旦上传,禁止覆盖或删除
- 状态快照定期备份:每天备份一次 IaC 状态,保留最近 30 天
- 回滚演练:每个月至少演练一次回滚流程,验证版本管理和状态快照是否有效
我曾经踩过的坑:有一次,我们回滚时发现制品仓库里的旧版本被自动清理了。原因是保留策略只保留了最近 5 个版本,而我们要回滚到第 6 个版本。从那以后,我们调整了保留策略,至少保留最近 20 个版本,并且所有 release 版本永久保留。