第十篇:《制品管理:从构建产物到可部署镜像》
在 CI/CD 流水线中,“构建”只是第一步,如何管理构建出来的产物(Artifact)才是决定交付效率的关键。一个常见的反模式是:在测试环境构建一次,在生产环境又构建一次——这不仅浪费计算资源,更致命的是,两次构建可能产生不同的结果,让测试变得毫无意义。本文系统讲解制品管理的核心理念“Build Once, Deploy Anywhere”,并深入介绍 JAR/WAR 包、Docker 镜像、Helm Chart 等不同类型制品的版本策略、存储方案和生命周期管理。
一、制品管理的核心理念:Build Once, Deploy Anywhere
Build Once, Deploy Anywhere 是制品管理的黄金法则:在整个 CI/CD 流水线中,一个制品只构建一次,然后以完全相同的形态依次通过各个环境(测试 → 预发布 → 生产) 。
为什么这很重要?
正确做法:
构建阶段生成唯一的、不可变的制品(如 JAR 包、Docker 镜像)
测试阶段使用该制品进行验证
部署阶段将同一个制品部署到各个环境,只改变配置(环境变量、数据库连接等)
二、制品的类型与存储
不同类型的制品需要不同的存储和管理方式:
💡 实践建议:对于容器化项目,Docker 镜像应成为唯一的交付制品。JAR 包只存在于构建阶段,最终发布到生产的是镜像,而非 JAR 包。
三、镜像版本策略:让每个版本都可追溯
镜像标签(Tag)的设计直接影响部署的可追溯性和回滚效率。
3.1 不可变版本标签(推荐)
每个构建生成一个唯一的、不可变的镜像标签,确保可以精确定位到对应的代码版本:
text
使用 Git Commit SHA 作为标签
registry.example.com/myapp:abc123def456
使用构建编号 + 时间戳
registry.example.com/myapp:build-2025-01-15-1432
语义化版本 + Commit SHA(推荐)
registry.example.com/myapp:v1.2.3-abc123d
优势:
每个镜像对应唯一的代码版本,可精确追溯
部署时不会意外覆盖已有镜像
回滚时只需指定上一个版本的 SHA
3.2 可变版本标签(辅助使用)
除了不可变标签,通常还会维护一些“指针”标签,指向最新的稳定版本:
text
latest - 指向最新的稳定版本
registry.example.com/myapp:latest
环境标签 - 指向当前部署到该环境的版本
registry.example.com/myapp:prod
registry.example.com/myapp:staging
⚠️ 警告:永远不要在生产环境使用 latest 标签部署。因为 latest 指向的镜像会变化,你无法确定生产环境运行的是哪个版本的代码。
3.3 推荐的综合策略
四、镜像构建的最佳实践
4.1 一次构建,多处部署
在 CI 流水线中,镜像构建应该只发生一次,然后通过不同的标签推送到仓库,供各环境使用:
# GitHub Actions 示例jobs:build:steps:-name:Build and push imageuses:docker/build-push-action@v5with:push:truetags:|ghcr.io/${{ github.repository }}:${{ github.sha }} # 不可变标签 ghcr.io/${{ github.repository }}:latest # 最新标签 ghcr.io/${{ github.repository }}:prod # 生产环境指针deploy-staging:needs:buildsteps:# 部署时使用同一个镜像(通过 Commit SHA 引用)-run:kubectl set image deployment/myapp myapp=ghcr.io/...:${{github.sha}}-n stagingdeploy-prod:needs:buildenvironment:productionsteps:# 生产环境也使用同一个镜像-run:kubectl set image deployment/myapp myapp=ghcr.io/...:${{github.sha}}-n prod4.2 多架构镜像构建
如果应用需要同时支持 x86 和 ARM 架构(如 Apple Silicon 开发机、ARM 云服务器),可以使用 Docker Buildx 构建多架构镜像:
-name:Set up Docker Buildxuses:docker/setup-buildx-action@v3-name:Build and push multi-arch imageuses:docker/build-push-action@v5with:platforms:linux/amd64,linux/arm64push:truetags:ghcr.io/${{github.repository}}:${{github.sha}}构建完成后,Docker 会自动生成一个多架构 Manifest,用户执行 docker pull 时,系统会根据自身架构自动拉取对应的镜像。
五、制品生命周期管理
制品不是“存进去就不管了”。随着项目迭代,镜像仓库中的制品会越来越多,需要有策略地管理其生命周期。
5.1 留存策略
5.2 Harbor 自动清理配置
Harbor 支持基于规则的自动清理:
# Harbor 清理策略示例retention:rules:# 保留所有带语义化版本标签的镜像(永久)-tag_selectors:-kind:"doublestar"pattern:"v*"decoration:"matches"time_scale:daysamount:0# 0 表示永久保留# 保留最近 30 天的开发版本-tag_selectors:-kind:"doublestar"pattern:"*-dev-*"decoration:"matches"time_scale:daysamount:30六、小结
Build Once, Deploy Anywhere 是制品管理的核心原则,确保测试和生产使用完全相同的二进制产物
镜像版本策略:使用 Commit SHA 作为不可变标签,语义化版本用于正式发布,环境标签作为指针
一次构建:在 CI 中只构建一次镜像,通过不同标签分发到各环境
生命周期管理:制定合理的留存和清理策略,避免镜像仓库无限膨胀
