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



我的团队在 3 个不同的 AWS 账户中使用 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
...

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

从命令行手动应用更新时,这种方法一直运行良好,但我很想将其移动到 GitLab CI/CD 以更好地自动化我们的工作流程,这就是事情崩溃的地方。

在我现有的设置中,如果我对staging/s3/main.tf进行一次更改,GitLab 似乎没有开箱即用的好方法,只能针对该特定配置运行terraform planterraform apply

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

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

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

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/*

我还假设存在位于共享位置的模块,以指示此模式如何还可以在存储库中的其他位置查找更改,而不仅仅是您运行 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

一般来说,虽然可以通过允许 Terraform 在每次推送时针对所有适当的目录运行来避免这种情况(可能只适用于推送到主节点或其他适当的分支),因为如前所述,Terraform 是幂等的,所以如果没有任何变化,它不会做任何事情。这也有一个好处,如果你的自动化代码没有改变,但你的提供者发生了一些变化(比如有人打开了一个安全组),那么 Terraform 会在下次触发时把它放回应有的状态。

最新更新