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 制品生命周期管理

制品不是存了就不管了。你得制定清理策略:

  1. 保留策略:保留最近 N 个版本,或者保留最近 M 天内的版本
  2. 归档策略:超过一定时间的制品,移到冷存储
  3. 删除策略:确认不再需要的制品,标记删除

举个例子,我们的 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 这些配置管理工具也需要快照。我习惯的做法是:

  1. 版本控制配置:所有 playbook、manifest 都放在 Git 仓库
  2. 标记发布版本:每次变更打一个 Git tag,比如 infra-v2.1.3
  3. 记录执行结果:每次执行后,把节点的最终状态保存下来

我的经验:Ansible 的 --check 模式可以预览变更,但不会真正执行。我建议在回滚前先用 --check 模式跑一遍,确认回滚操作不会引入新问题。

3.4 版本管理与快照的核心逻辑

说了这么多,咱们用一张图把核心逻辑串起来:

版本管理与快照核心逻辑 版本管理与快照核心逻辑 源码仓库 Git commit + tag 构建系统 CI/CD 流水线 制品仓库 Docker / Nexus / S3 IaC 仓库 Terraform / Ansible IaC 状态快照 tfstate / Git tag 部署环境 生产 / 预发 / 测试 回滚流程 从制品仓库拉取旧版本 + 从 IaC 状态快照恢复基础设施 核心逻辑:版本号串联源码→制品→部署,IaC 状态快照保证基础设施可回滚 回滚时,同时拉取旧版本制品和旧版本 IaC 状态,确保应用和基础设施一致

3.5 实战建议

最后,给你几个实战建议:

  • 版本号自动化:在 CI/CD 中自动生成版本号,不要手动填写
  • 制品不可变:一旦上传,禁止覆盖或删除
  • 状态快照定期备份:每天备份一次 IaC 状态,保留最近 30 天
  • 回滚演练:每个月至少演练一次回滚流程,验证版本管理和状态快照是否有效

我曾经踩过的坑:有一次,我们回滚时发现制品仓库里的旧版本被自动清理了。原因是保留策略只保留了最近 5 个版本,而我们要回滚到第 6 个版本。从那以后,我们调整了保留策略,至少保留最近 20 个版本,并且所有 release 版本永久保留。