具有多个 Terraform 配置的有效 GitLab CI/CD 工作流程?

Mon*_*y34 1 continuous-integration gitlab terraform

我的团队将 AWS 用于我们的基础设施,跨越 3 个不同的 AWS 账户。我们将简单地给他们打电话sandboxstagingproduction

我最近针对我们的 AWS 基础设施设置了 Terraform,它的层次结构映射到我们的帐户,然后是应用程序或 AWS 服务本身。回购结构看起来像这样:

staging
  iam
    groups
      main.tf
    users
      main.tf
  s3
    main.tf
sandbox
  iam
    ...
production
  applications
    gitlab
      main.tf
  route53
    main.tf
  ...
Run Code Online (Sandbox Code Playgroud)

我们为每个 AWS 服务(例如,IAM 或 S3)或应用程序(例如,GitLab)使用单独的配置,因此我们最终不会在.tf每个帐户中生成庞大的文件,这需要很长时间才能为任何一项更改应用更新。理想情况下,我们希望摆脱基于服务的配置方法,转向更多基于应用程序的配置,但无论哪种方式,手头的问题都是一样的。

当从命令行手动应用更新时,这种方法一直运行良好,但我很想将它移动到 GitLab CI/CD 以更好地自动化我们的工作流程,而这正是问题所在。

在我现有的设置中,如果我对,比如说,做一个单一的改变staging/s3/main.tf,GitLab 似乎没有一个开箱即用的好方法来只运行terraform planterraform apply用于特定的配置。

如果我改为将所有内容移动到main.tf整个 AWS 帐户的单个文件中(或多个文件但与单个状态文件相关联),我可以简单地让 GitLab 触发一个作业planapply仅触发该配置。根据我们在每个账户中拥有的 AWS 资源数量,运行可能需要 15 分钟,但我认为这是一个潜在的选择。

似乎我的问题最终可能与 GitLab 如何处理“monorepos”有关,而不是与 Terraform 如何处理其工作流程有关(毕竟,如果我只是告诉它发生了什么变化,Terraform 会很乐意计划/应用我的更改),尽管我也会有兴趣了解人们如何构建他们的 Terraform 环境给定——或为了完全避免——这些限制。

有没有人在他们的环境中解决过这样的问题?

yda*_*coR 7

Terraform 的好处是它是幂等的,因此即使没有任何更改,您也可以应用,并且无论如何它都是无操作的操作。

如果出于某种原因,您真的只想在事情发生变化时在特定目录上运行计划/应用程序,那么您可以通过使用来实现这一点,only.changes以便 Gitlab 仅在指定文件发生更改时才运行作业。

所以如果你有你现有的结构,那么它就像做这样的事情一样简单:

stages:
  - terraform plan
  - terraform apply

.terraform_template:
  image: hashicorp/terraform:latest
  before_script:
    - LOCATION=$(echo ${CI_JOB_NAME} | cut -d":" -f2)
    - cd ${LOCATION}
    - terraform init

.terraform_plan_template:
  stage: terraform plan
  extends: .terraform_template
  script:
    - terraform plan -input=false -refresh=true -module-depth=-1 .

.terraform_apply_template:
  stage: terraform apply
  extends: .terraform_template
  script:
    - terraform apply -input=false -refresh=true -auto-approve=true .

terraform-plan:production/applications/gitlab:
  extends: .terraform_plan_template
  only:
    refs:
      - master
    changes:
      - production/applications/gitlab/*
      - modules/gitlab/*

terraform-apply:production/applications/gitlab:
  extends: .terraform_apply_template
  only:
    refs:
      - master
    changes:
      - production/applications/gitlab/*
      - modules/gitlab/*
Run Code Online (Sandbox Code Playgroud)

我还假设存在位于共享位置的模块,以表明此模式如何也可以在存储库中的其他地方查找更改,而不仅仅是您正在运行 Terraform 的目录。

如果情况并非如此,并且您的结构更扁平,并且您很高兴拥有一份申请工作,那么您可以将其简化为:

stages:
  - terraform

.terraform_template:
  image: hashicorp/terraform:latest
  stage: terraform
  before_script:
    - LOCATION=$(echo ${CI_JOB_NAME} | cut -d":" -f2)
    - cd ${LOCATION}
    - terraform init
  script:
    - terraform apply -input=false -refresh=true -auto-approve=true .
  only:
    refs:
      - master
    changes:
      - ${CI_JOB_NAME}/*

production/applications/gitlab:
  extends: .terraform_template
Run Code Online (Sandbox Code Playgroud)

一般来说,尽管这可以通过允许 Terraform 在每次推送时针对所有适当的目录运行来避免(可能只应用于推送到 master 或其他适当的分支),因为如上所述,Terraform 是幂等的,因此它不会做任何事情如果什么都没有改变。这还有一个好处,如果您的自动化代码没有更改,但您的提供程序中的某些内容发生了变化(例如有人打开了一个安全组),那么 Terraform 将在下次触发时将其恢复到应有的状态。