1. 制品治理全景

在 GitLab 中,“制品”并不是一个单一概念,而是覆盖了包、容器镜像、通用文件等多种形态的集合。它们共同承担一个使命:把一次流水线中产生的可交付成果,稳定地保存下来,并让后续的部署、回滚、审计都能找到确定的版本。理解制品治理,首先要理解 GitLab 提供的三类主要制品载体,以及它们各自适合承载什么。

第一类是包(Package),通过 GitLab Package Registry 管理。它面向语言生态的依赖分发,支持 npm、Maven、PyPI、NuGet、Composer、Go Proxy 等格式。包的核心特征是“按坐标寻址”:例如 Maven 包由 groupId、artifactId、version 三者共同确定,npm 包由包名和版本确定。第二类是容器镜像(Container Image),通过 GitLab Container Registry 管理,以仓库名加 tag 或 digest 定位。镜像适合承载完整运行环境,是部署到 Kubernetes 或容器平台的主要交付物。第三类是通用包(Generic Package),同样走 Package Registry,但不绑定特定语言格式,可以上传任意文件,例如二进制、压缩包、配置文件、安装脚本。它常被用来存放不适合纳入语言包体系的构建产物。

三类制品并非互斥,而是经常在同一条流水线中协同出现。一个典型的前端项目可能同时产出 npm 包、Docker 镜像和一份部署用的通用压缩包。治理的目标不是限制使用哪一种,而是让每一种制品都有明确的版本、来源和生命周期。

制品从构建到归档的完整链路 构建阶段 CI Job 编译 / 打包 生成产物 + 元数据 写入版本号与提交 SHA 包 Package Registry npm / Maven / PyPI / NuGet 容器镜像 Container Registry tag / digest 定位 通用包 Generic Package 二进制 / 压缩包 / 配置 版本语义 SemVer: MAJOR.MINOR.PATCH 预发布: -rc.1 / -beta 构建元数据: +build.42 发布 生命 周期 开发 预发布 正式 归档与治理层 不可变存储 已发布版本禁止覆盖 保留策略 按时间 / 数量清理 来源追溯 提交 SHA + 流水线 ID 访问控制 项目 / 群组权限 版本确定后归档

版本语义是制品治理的骨架。GitLab 本身不强制你使用某种版本规则,但工程实践中普遍采用语义化版本(SemVer):MAJOR.MINOR.PATCH。MAJOR 表示不兼容的变更,MINOR 表示向后兼容的功能新增,PATCH 表示向后兼容的缺陷修复。预发布版本用连字符追加标识,例如 2.1.0-rc.1;构建元数据用加号追加,例如 2.1.0+build.42。在 CI 中,版本号通常来自 Git tag,例如 tag v2.1.0 去掉前缀后得到 2.1.0。如果流水线运行在分支上而非 tag 上,则应生成快照版本,例如 2.1.0-SNAPSHOT.20240612.abc1234,避免与正式版本冲突。

发布生命周期把制品从“能构建”推进到“可交付”。一个清晰的阶段划分是:开发版、预发布版、正式版。开发版对应主干或特性分支的每次提交,允许频繁覆盖;预发布版对应 release 分支或 rc tag,用于集成验证;正式版对应正式 tag,一旦发布即不可变。GitLab 的 Package Registry 和 Container Registry 都支持对已发布版本设置保护,防止被同名覆盖。容器镜像尤其要注意:同一个 tag 被重新推送会改变其指向的 digest,因此正式发布应使用不可变 tag 或直接引用 digest。

治理目标可以归纳为四点。第一,可追溯:每个制品都能回答“它由哪次提交、哪条流水线、哪个 Job 产生”。GitLab 在包和镜像的元数据中记录了 pipeline ID 和 commit SHA,但前提是你在构建时正确传递了这些信息。第二,不可变:正式版本发布后不允许被覆盖,保证下游引用稳定。第三,可清理:通过保留策略控制存储成本,例如只保留最近 10 个正式版本和最近 30 天的开发版本。第四,可控制:通过项目或群组权限控制谁可以发布、谁可以下载、谁可以删除。

下面给出一个可直接参考的版本与归档策略示例,适用于中等规模项目:

制品类型 版本来源 发布阶段 保留策略 不可变
npm 包 package.json + tag 开发 / 正式 正式版永久,开发版 30 天 正式版是
Maven 包 pom.xml + tag 开发 / 预发布 / 正式 正式版永久,快照 14 天 正式版是
容器镜像 tag + commit SHA 开发 / 预发布 / 正式 正式版永久,开发版 7 天 正式版是
通用包 自定义版本文件 正式 按项目需要 是

在流水线中落地这套策略,关键动作有三个。其一,在构建 Job 中显式写入版本和来源信息。例如使用 CI_COMMIT_TAG 或 CI_COMMIT_SHORT_SHA 拼接版本号,并在上传时附带 CI_PIPELINE_ID。其二,区分“上传”和“发布”两个动作:上传只是把文件放进 Registry,发布则是打上正式版本标记并触发下游。其三,配置清理规则。GitLab 支持在项目设置中为 Package Registry 和 Container Registry 配置保留策略,也可以使用 API 定期清理。对于容器镜像,还可以在 CI 中调用 gitlab-ci-token 删除旧 tag。

版本号一旦用于正式发布,就不要再修改。如果发现正式版本有问题,正确做法是发布一个新的 PATCH 版本,例如从 2.1.0 发布 2.1.1,而不是覆盖 2.1.0。覆盖会破坏所有已经引用该版本的部署和缓存。

最后需要强调,制品治理不是发布之后才考虑的事,而是从第一次构建就应该纳入流水线设计。构建时写入来源、上传时区分阶段、发布时锁定版本、归档后执行清理,这四个动作贯穿制品的一生。只有把这条链路打通,后续的部署、回滚和审计才有可靠的基础。