Neste artigo, gostaria de mostrar uma configuração de ponta a ponta para criar pipelines do Gitlab CI para Terraform, usando GCP como Armazenamento Remoto, passo a passo.
Configuração de Conta GCP
A configuração da conta pode ser feita de várias maneiras diferentes. Minha escolha é ter um projeto para DevOps, e um projeto por ambiente, conforme ilustrado na imagem abaixo.
No projeto DevOps, precisamos configurar uma Conta de Serviço com Permissão de Editor que será usada pelos pipelines para implantar os recursos. Para fazer isso:
- Vá para o IAM no projeto DevOps e crie uma Conta de Serviço.
Escolha um nome
Conceda Permissão de Editor e crie (você pode pular a etapa 3)
Agora, vamos criar uma chave para a Conta de Serviço. Por favor, selecione a conta de serviço, vá para a seção Chave e adicione uma chave no formato JSON. Salve-a para usarmos no Gitlab CI.
Agora, precisamos conceder acesso a essa conta de serviço para poder criar recursos nos projetos de desenvolvimento, estágio e produção. Para isso, vá a cada projeto de ambiente, na página IAM e clique em Conceder Acesso.
Adicione o e-mail da conta de serviço criada no projeto DevOps e conceda também Permissão de Editor (repita esse processo em cada projeto de ambiente).
Infelizmente, diferente de Terragrunt, o código Terraform puro não cria automaticamente o bucket para o estado remoto. Então, vá a cada projeto de ambiente e crie um bucket para ser usado para armazenar o estado remoto de cada ambiente.
Aviso: É altamente recomendado habilitar a versionamento do bucket.
E isso é tudo para o GCP.
Configuração do Gitlab
No Gitlab, precisamos apenas configurar nossa Conta de Serviço como uma Variável.
- Na sua Página de Configurações do Gitlab, na Subseção CICD, crie uma variável chamada “SA” do tipo Arquivo.
- Cole o valor do JSON SA que você baixou nas etapas anteriores.
Estrutura de Código
Neste exemplo, estou usando uma estrutura de pastas como abaixo, mas você pode adaptá-la de acordo com suas necessidades.
terraform-infra-live/
├─ infra/
│ ├─ stage/
│ │ ├─ main.tf
│ ├─ prod/
│ │ ├─ main.tf
│ ├─ dev/
│ │ ├─ main.tf
├─ modules/
│ ├─ gcp/
│ │ ├─ gce/
│ │ ├─ firewall-rule/
│ │ ├─ gcs/
O código principal contém um código como abaixo, que você precisa alterar em cada arquivo main.tf os valores do bucket e seu ID de projeto para cada ambiente.
terraform {
required_providers {
google = "4.10.0"
}
backend "gcs" {
bucket = "REPLACE-WITH-YOUR-BUCKET-NAME-dev"
prefix = "terraform/state"
}
}
provider "google" {
project = "REPLACE-WITH-YOUR-PROJECT-ID-dev"
region = "us"
}
locals {
project_id = "REPLACE-WITH-YOUR-PROJECT-ID-dev"
environment = "dev"
}
...
## Adicione seus módulos e o código restante...
Pipelines
Os pipelines são muito simples e criados para fluxos de trabalho baseados em recursos
Um pipeline para Merge Request, onde as validações serão feitas.
Um pipeline para a branch principal, onde o código será implantado automaticamente em cada ambiente não produtivo em paralelo, e o ambiente de produção manualmente.
O código
image:
name: hashicorp/terraform:1.3.2
entrypoint:
- "/usr/bin/env"
- "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
stages:
- test
- deploy-non-prod
- deploy-prod
before_script:
- cp $SA /tmp/credentials.json
- export GOOGLE_APPLICATION_CREDENTIALS="/tmp/credentials.json"
.deploy: &deploy
script:
- terraform init
- terraform plan -lock=false -out plan.json
- terraform apply -auto-approve plan.json
test:
stage: test
script:
- terraform fmt --recursive -check
- cd infra/$ENV_NAME
- terraform init
- terraform validate
- terraform plan -lock=false
parallel:
matrix:
- ENV_NAME: [ dev, stage, prod ]
only:
- main
- merge_requests
deploy-non-prod:
stage: deploy-non-prod
script:
- cd infra/$ENV_NAME
- !reference [.deploy, script]
parallel:
matrix:
- ENV_NAME: [ dev, stage ]
only:
- main
dependencies:
- test
deploy-prod:
stage: deploy-prod
script:
- cd infra/$ENV_NAME
- !reference [.deploy, script]
parallel:
matrix:
- ENV_NAME: [ prod ]
only:
- main
when: manual
dependencies:
- deploy-non-prod
after_script:
- rm /tmp/credentials.json
Outras Considerações
Como o pipeline realizará uma verificação de lint, é uma boa ideia executar um “terraform fmt -recursive” antes de enviar seu código.
Você pode verificar o exemplo completo de código no meu Github: https://github.com/andersondario/terraform-infra-gitlab-example
Suporte
Se você achar meus posts úteis e gostaria de me apoiar, por favor, me compre um café:
Anderson Dario é blog pessoal e blog de tecnologia
Isso é tudo. Obrigado.