部署安全

部署作业是一种特定的 CI/CD 作业,比流水线中的其它作业更敏感,极狐GitLab 具有多项有助于维护部署安全性和稳定性的功能。

您可以:

如果您使用的是持续部署工作流,并希望确保不会发生对同一环境的并发部署,则应启用以下选项:

限制对关键环境的写访问

默认情况下,任何至少具有开发者角色的团队成员都可以修改环境。 如果您想限制对关键环境(例如“生产”环境)的写访问,您可以设置受保护的环境

确保一次只运行一个部署作业

GitLab CI/CD 中的流水线作业并行运行,因此两个不同流水线中的两个部署作业可能会尝试同时部署到同一环境。这不是预期的行为,因为部署应该按顺序进行。

您可以使用 .gitlab-ci.yml 中的 resource_group 关键字 确保一次只运行一个部署作业。

例如:

deploy:
 script: deploy-to-prod
 resource_group: prod

使用资源组之前,有问题的流水线工作流示例:

  1. Pipeline-A 中的 deploy 作业开始运行。
  2. Pipeline-B 中的 deploy 作业开始运行。这是可能导致意外结果的并发部署。
  3. Pipeline-A 中的 deploy 作业完成。
  4. Pipeline-B 中的 deploy 作业完成。

使用资源组之后,改进的流水线工作流示例:

  1. Pipeline-A 中的 deploy 作业开始运行。
  2. Pipeline-B 中的 deploy 作业尝试启动,但等待第一个 deploy 作业完成。
  3. Pipeline-A 中的 deploy 作业完成。
  4. Pipeline-B 中的 deploy 作业开始运行。

阻止过期的部署作业

于 15.5 版本,变更为阻止过期的部署作业运行

流水线作业的有效执行顺序可能因运行而异,可能会导致不良行为。例如,较新流水线中的部署作业可能在旧流水线中的部署作业之前完成。 这会产生一个竞争条件,旧部署稍后完成,覆盖“较新”部署。

您可以通过启用跳过过期的部署作业功能,来确保在较新的部署作业启动时自动取消较旧的部署作业。

您可以通过启用阻止过期的部署作业功能,来防止较旧的部署作业在启动较新的部署作业时运行。

当较旧的部署作业开始时,它会失败并被标记为:

  • 流水线视图中:failed outdated deployment job
  • 查看已完成作业:The deployment job is older than the latest deployment, and therefore failed.

当较旧的部署作业是手动的时,运行按钮会被禁用,并显示一条消息 This deployment job does not run automatically and must be started manually, but it's older than the latest deployment, and therefore can't run.

作业年龄由作业开始时间决定,而不是提交时间,因此在某些情况下可以阻止更新的提交。

如何回滚到过期的部署

通过作业重试回滚功能重新引入于 15.6 版本。

在某些情况下,您需要回滚到过期的部署。 该特性明确允许通过环境回滚功能进行回滚,以便您在紧急情况下可以快速回滚。

或者,您可以使用先前的提交运行新流水线,它包含比最新部署更新的部署作业。

示例

启用跳过过时的部署作业之前,有问题的流水线工作流示例:

  1. Pipeline-A 是在默认分支上创建的。
  2. 稍后,在默认分支上创建了 Pipeline-B(使用更新的提交 SHA)。
  3. Pipeline-B 中的 deploy 作业首先完成,并部署较新的代码。
  4. Pipeline-A 中的 deploy 作业稍后完成,并部署旧代码,覆盖较新(最新)的部署。

启用跳过过时的部署作业之后,改进的流水线工作流示例:

  1. Pipeline-A 是在默认分支上创建的。
  2. 稍后,在默认分支上创建了 Pipeline-B(使用更新的 SHA)。
  3. Pipeline-B 中的 deploy 作业首先完成,并部署较新的代码。
  4. Pipeline-A 中的 deploy 作业被自动取消,因此它不会覆盖来自较新流水线的部署。

在部署冻结窗口期间阻止部署

如果您想在特定时期阻止部署,例如在大多数员工外出的计划假期期间,您可以设置部署冻结。 在部署冻结期间,不能执行任何部署。这有助于确保部署不会意外发生。

保护生产 secrets

成功部署需要生产 secrets。例如,在部署到云时,云提供商需要这些 secrets 才能连接到他们的服务。在项目设置中,您可以为这些 secrets 定义和保护 CI/CD 变量。受保护的变量仅传递到受保护分支受保护的标签。 其他流水线没有得到受保护的变量。您还可以将变量作用于特定环境。 我们建议您在受保护的环境中使用受保护的变量,以确保不会无意中泄露 secrets。您还可以在 runner 端 定义生产 secrets。 这可以防止具有维护者角色的其他用户读取 secrets,并确保 runner 仅在受保护的分支上运行。

用于部署的单独项目

具有项目维护者角色的所有用户都可以访问生产 secrets。如果需要限制可以部署到生产环境的用户数量,可以创建一个单独的项目,并配置一个新的权限模型,将 CD 权限与原始项目隔离,阻止具有项目维护者角色的原始用户访问生产 secrets 和 CD 配置。您可以使用多项目流水线,将 CD 项目连接到您的开发项目。

保护 .gitlab-ci.yml 免受更改

.gitlab-ci.yml 可能包含将应用程序部署到生产服务器的规则。此部署通常在推送合并请求后自动运行。为了防止开发人员更改 .gitlab-ci.yml,您可以在不同的仓库中定义它。配置可以引用具有完全不同权限集的另一个项目中的文件(类似于区分部署项目)。 在这种情况下,.gitlab-ci.yml 是可公开访问的,但只能由其他项目中具有适当权限的用户进行编辑。

部署前需要批准

在将部署推广到生产环境之前,与专门的测试组进行交叉验证是确保安全的有效方法。有关详细信息,请参阅部署批准

故障排查

流水线作业失败,并显示 The deployment job is older than the previously succeeded deployment job...

这是由阻止过期的部署作业功能引起的。 如果同一个环境有多个作业(包括非部署作业),可能会遇到这个问题,例如:

build:service-a:
 environment:
   name: production

build:service-b:
 environment:
   name: production

阻止过期的部署作业可能不适用于此配置,必须禁用。