CI/CD 环境管理实战:让每次部署可控可追溯
CI/CD 环境管理实战:让每次部署可控可追溯
流水线跑绿了,代码到底部署到哪里了?谁点的部署?能不能一键回滚?这些问题在每个上了规模的研发团队里都会出现。CI 做得再好,如果 CD 侧的「环境」只是一堆约定俗成的命名和散落在各处的脚本,交付的可控性就无从谈起。
极狐GitLab CI/CD 提供了一套内建的「环境(Environments)与部署(Deployments)」模型,把部署目标、部署记录、权限控制与审批流程直接长在流水线里,不需要额外引入一套发布系统。本文基于官方文档,梳理这套模型的落地方法。
一、环境是什么:从「部署目标」到「部署台账」
环境代表应用程序的一个特定部署目标,例如开发(development)、测试(testing)、预发布(staging)、生产(production)。只要在部署作业中声明 environment,极狐GitLab 就会自动维护:
部署跟踪:每一次部署的时间、执行人、流水线、commit 全部记录在案,在「运维 → 环境」页面可查;
环境状态:
available/stopping/stopped三种状态,由停止作业或手动操作驱动;环境 URL:部署完成后,环境链接会直接出现在合并请求中,评审人可以一键打开验证。
一个最小可用的示例:
deploy_staging:
stage: deploy
script:
- ./deploy.sh staging
environment:
name: staging
url: https://staging.example.com流水线运行时,如果名为 staging 的环境不存在,会自动创建。环境 URL 会同时展示在环境视图、部署视图与合并请求里——前提是该分支最终被合并进默认分支并部署到了对应环境。
二、动态环境:每个分支一个临时环境
环境分静态与动态两类。静态环境(如 staging、production)被连续的部署重复使用;动态环境则基于 CI/CD 变量动态命名,通常只服务单次部署,是 Review App 的基础:
deploy_review_app:
stage: deploy
script: make deploy
environment:
name: review/$CI_COMMIT_REF_SLUG
url: https://$CI_ENVIRONMENT_SLUG.example.com
rules:
- if: $CI_COMMIT_BRANCH == "main"
when: never
- if: $CI_COMMIT_BRANCH每个分支会得到独立的环境名称,UI 中会自动按 review/ 前缀分组折叠。评审代码时直接打开「这个分支部署出来的应用」,是提升 MR 评审质量最直接的手段之一。
自动回收:auto_stop_in
临时环境最大的问题是忘删。官方提供了 environment:auto_stop_in 关键字,用自然语言指定存活期:
review_app:
script: deploy-review-app
environment:
name: review/$CI_COMMIT_REF_SLUG
on_stop: stop_review_app
auto_stop_in: 1 week
rules:
- if: $CI_MERGE_REQUEST_ID
stop_review_app:
script: stop-review-app
environment:
name: review/$CI_COMMIT_REF_SLUG
action: stop
rules:
- if: $CI_MERGE_REQUEST_ID
when: manual超过一周不活跃的环境会被自动停止。注意两点细节:负责停止的后台 worker 每小时运行一次,停止时间可能有偏差;停止作业需要与部署作业保持相同的 rules 配置,并声明 environment:action: stop,建议同时设置 GIT_STRATEGY: none 避免分支已删除时代码检出失败。
三、受保护环境:生产环境的权限边界
环境可观测只是第一步,更关键的是「谁有权部署到生产环境」。受保护环境(专业版及以上)把部署权限收敛到明确的白名单:
进入项目「设置 → CI/CD → 受保护的环境」;
选择要保护的环境(如
production);在「允许部署」列表中指定角色、用户或群组;
可同时在「审批者」列表配置审批人,并在「审批规则」中设置所需的审批数量。
被保护后,不在「允许部署」列表中的用户发起的部署作业会直接失败——不是事后审计,而是事前拦截。对于只需要「能部署、不需要看代码」的外部协作者,还可以通过 Reporter 角色的受邀群组授予「仅部署访问」权限,实现职责分离。
群组级保护与部署层级
大型组织里,同一个生产环境在不同项目里可能叫 production、gprd 或别的名字。群组级受保护环境通过「部署层级(deployment tier)」统一治理:环境的部署层级可显式声明,也可由名称按正则推断:
deploy_production:
stage: deploy
script: ./deploy.sh prod
environment:
name: production
deployment_tier: production运维团队只需在群组级按 production 层级配置一次保护规则,所有子项目的生产环境全部纳入同一权限边界,且子群组无法覆盖上级的配置。这也正是「开发部署低环境、运维部署高环境」这类经典职责分离模型的直接落地。
四、部署审批:上生产前的最后一道门
配置了审批者的受保护环境,在部署前会要求指定数量的审批人手动批准(详见部署审批文档)。流程上是这样的:部署作业处于阻塞状态 → 审批人收到待办 → 批准后作业才继续执行;拒绝则终止。审批动作本身会进入审计事件,满足合规场景下「双人复核、留痕可查」的要求。
配合 when: manual 手动部署作业,一个典型的生产发布作业大致是:
deploy_production:
stage: deploy
script:
- ./deploy.sh production
when: manual
environment:
name: production
deployment_tier: production
rules:
- if: $CI_COMMIT_BRANCH == "main"只有默认分支触发、只有白名单用户能点、点了还要过审批——三层约束叠加,才敢叫「生产发布流程」。
结语
从 environment 关键字的一行声明,到动态环境加自动回收,再到受保护环境与部署审批,极狐GitLab 把「部署」从脚本里的一句 kubectl apply 升级成了有台账、有权限、有审批的受控过程。如果你的团队还在用文档约定「谁能发生产」,不妨从给 production 加上受保护环境开始——这是投入最小、收益最明确的一步。

