首页 > 解决方案 > Gitlab - 从部署中分离 CI

问题描述

我们目前正在使用 Jenkins,并计划迁移到 Gitlab。我们实际上在每个 repo 中有 2 个 Jenkinsfiles,1 个设置为 Multibranch 管道并在所有更改上运行。它是合并检查,运行所有各种 linting、测试、构建 docker 容器等。第二个 Jenkinsfile 仅从 Jenkins 手动运行,它接受所有各种输入参数并部署代码。这主要来自于 linted Ansible/Terraform 并选择了一个已经通过 CI 方面构建的 docker 镜像。

我知道 gitlab 不支持这个模型,但是这个项目已经是 MVP,所以重新开发开发人员如何将他们的逻辑和部署代码组合在一起可能不会发生。

是否有可能,在 1 个 gitlab-ci.yml 文件中说run these jobs on merge/pushes并且只运行this on manual deployment.

例如

workflow:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
    - if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS'
      when: never
    - if: '$CI_COMMIT_BRANCH'

stages:
  - test
  - test
  - deploy
  - destroy

test-python-job:
  stage: test
  rules:
     - if: '$CI_PIPELINE_SOURCE == "push"'
     - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
  script:
    - echo "Test Python"
    - black
    - bandit
    - flake8
    - tox

test-terraform-job:
  stage: test
  rules:
     - if: '$CI_PIPELINE_SOURCE == "push"'
     - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
  script:
    - echo "Test Terraform"
    - terraform validate --yadda

test-ansible-job:
  stage: test
  rules:
     - if: '$CI_PIPELINE_SOURCE == "push"'
     - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
  script:
    - echo "Test Ansible"
    - ansible-lint --yadda

deploy-job:
  stage: deploy
  variables:
    DEPLOYMENT_ID: "Only deploy-job can use this variable's value"
  secrets:
    DATABASE_PASSWORD:
      vault: production/db/password@ops
  rules:
    - when: manual
  script:
    - echo "Terraform Deploy"
    - terraform deploy
    - ansible-playbook yaddas

destroy-job:
  stage: destroy
  variables:
    DEPLOYMENT_ID: "Only destroy-job can use this variable's value"
  secrets:
    DATABASE_PASSWORD:
      vault: production/db/password@ops
  rules:
    - when: manual
  script:
    - terraform destroy

我们甚至还没有部署 gitlab,所以我把它写在我的脑海中,但我想知道我的痛苦程度。

标签: gitlab

解决方案


有多种选择可以通过最少的配置工作来实现您的目标:

  1. 使用私有作业并使用继承或引用来简化配置 - 可在一个文件中完成
  2. 将部件提取到子管道中以便于使用

在一个文件中减少配置

我想你最讨厌你必须重新定义你的工作规则。有两种方法可以减少这些重复。

遗产

可以减少大量重复,但也可能导致问题,出现意外的副作用。

.test:
  stage: test
  rules:
     - if: '$CI_PIPELINE_SOURCE == "push"'
     - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

test-python-job:
  extends: .test
  script:
    - echo "Test Python"
    - black
    - bandit
    - flake8
    - tox

test-terraform-job:
  extends: .test
  script:
    - echo "Test Terraform"
    - terraform validate --yadda

test-ansible-job:
  extends: .test
  script:
    - echo "Test Ansible"
    - ansible-lint --yadda

作品

通过使用!reference,您可以结合工作的某些方面,请参阅https://docs.gitlab.com/ee/ci/yaml/#reference-tags

.test:
  rules:
     - if: '$CI_PIPELINE_SOURCE == "push"'
     - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

test-python-job:
  stage: test
  rules:
     - !reference [.test, rules]
  script:
    - echo "Test Python"
    - black
    - bandit
    - flake8
    - tox

test-terraform-job:
  stage: test
  rules:
     - !reference [.test, rules]
  script:
    - echo "Test Terraform"
    - terraform validate --yadda

  stage: test
  rules:
     - !reference [.test, rules]
  script:
    - echo "Test Ansible"
    - ansible-lint --yadda

父子管道

有时也可能适合将功能提取到子管道中。当您调用子管道并由于代码行较少而获得概览时,您可以更轻松地控制在一个阶段发生的事情。它增加了构建的复杂性。但通常它会生成一个更清洁、更容易维护的 ci 结构(我的观点)。

这种方法只会在需要时添加子管道 - 此外,如果部署类似,您还可以集中该文件

.gitlab-ci.yml

deploy:
  stage: deploy
  trigger:
    include:
      - local: Deploy.gitlab-ci.yml
    strategy: depend
  rules:
    - if: $CI_PIPELINE_SOURCE == 'web' #maybe also useful, as it will only happen on a web interaction
      when: manual
    - if: $CI_PIPELINE_SOURCE == 'schedule' #maybe also useful, for schedules

部署.gitlab-ci.yml

deploy-job:
  stage: deploy
  variables:
    DEPLOYMENT_ID: "Only deploy-job can use this variable's value"
  secrets:
    DATABASE_PASSWORD:
      vault: production/db/password@ops
  script:
    - echo "Terraform Deploy"
    - terraform deploy
    - ansible-playbook yaddas

destroy-job:
  stage: destroy
  variables:
    DEPLOYMENT_ID: "Only destroy-job can use this variable's value"
  secrets:
    DATABASE_PASSWORD:
      vault: production/db/password@ops
  script:
    - terraform destroy

旁注

这不是 100% 回答你的问题,但它向你展示了很大的灵活性,你很快就会意识到模仿 jenkins 并不是 100% 理想的。例如,将部署作业直接附加到提交并在该提交上可见,可以更好地了解确切部署的内容。如果您需要手动运行这些东西,我强烈建议您使用具有预配置值的时间表,因为它们只有一个播放按钮。此外,您已经有了工件并从您的管道构建,为什么不添加使用它们的额外步骤,而不是提供此信息

我希望我的见解对您有用,祝您迁移愉快;)


推荐阅读