DEV Community

Paulo Ponciano
Paulo Ponciano

Posted on • Originally published at Medium

Pipeline de IaC com GitLab, Terraform e GitLab-managed Terraform state

Repositório GitLab.

Pré-requisitos

  • Access Keys AWS

  • GitLab

Serviços AWS

  • SQS

  • S3

Usamos SQS e S3 a título de exemplo nesse laboratório.

Construção

  • Os passos abaixo são basicamente para preparar o repositório no GitLab, criando a branch 'development' e fazendo commit e push dos arquivos para ela:

  • Criamos também a branch 'staging':

  • No GitLab, crie o environment 'default', também 'development' e 'staging' caso ainda não tenha sido criados após o primero push:

Environments

  • Crie as variáveis no GitLab, onde cada 'AWS_ACCESS_KEY_ID' e 'AWS_SECRET_ACCESS_KEY' correspondem as contas de destino do provisionamento de acordo com environment:

VariablesVariables

Cuidado com essas informações de chave!

  • Execute o pipeline para a branch 'development'. Abaixo executamos manualmente, porém esse processo é automático assim que enviamos atualizações para branch:

Run pipeline

Pipeline

  • Execute o pipeline para a branch ‘staging’:

Pipeline

  • Merge request de 'staging' para 'main', esse é o deploy em produção:

New merge request

New merge request

Merge approval

Pipeline

  • Verifique os recursos provisionados em cada conta AWS. Note que, os recursos de development e staging estão na mesma conta, é porque utilizamos a mesma chave para os dois ambientes. Já os recursos de produção, estão em outra conta AWS:

SQS Development and Staging

SQS Production

S3 Production

  • Podemos também acionar manualmente o stage cleanup que realiza o terraform destroy:

PipelinePipeline

  • Veja que o GitLab está cuidando dos Terraform states para nós:

Terraform statesTerraform states

O arquivo gitlab-ci.yml é responsável por toda orquestração do pipeline:

image: registry.gitlab.com/gitlab-org/terraform-images/stable:latest

workflow:
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      variables:
        ENV: "production"
    - if: $CI_COMMIT_BRANCH == "development"
      variables:
        ENV: "development"
    - if: $CI_COMMIT_BRANCH == "staging"
      variables:
        ENV: "staging"

variables:
  TF_ROOT: ${CI_PROJECT_DIR}
  TF_ADDRESS: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/${ENV}_tf_state

cache:
  key: ${ENV}_tf_state
  paths:
    - ${TF_ROOT}/.terraform

before_script:
  - cd ${TF_ROOT}

stages:
  - init
  - validate
  - build
  - deploy
  - cleanup

init_dev:
  stage: init
  script:
    - gitlab-terraform init
  environment:
    name: development
  only:
    - development 

validate_dev:
  stage: validate
  script:
    - gitlab-terraform validate
  environment:
    name: development
  only:
    - development

plan_dev:
  stage: build 
  script:
    - gitlab-terraform plan -var-file=${ENV}.tfvars 
    - gitlab-terraform plan-json -var-file=${ENV}.tfvars
  artifacts:
    name: plan
    paths:
      - ${TF_ROOT}/plan.cache
    reports:
      terraform:  ${TF_ROOT}/plan.json
  environment:
    name: development
  only:
    - development

apply_dev:
  stage: deploy
  script:
    - gitlab-terraform apply
  dependencies:
    - plan_dev
  environment:
    name: development
  only:
    - development

destroy_dev:
  stage: cleanup
  script:
    - gitlab-terraform destroy -var-file=${ENV}.tfvars
  dependencies:
    - plan_dev
    - apply_dev
  when: manual
  environment:
    name: development
  only:
    - development

init_qas:
  stage: init
  script:
    - gitlab-terraform init
  environment:
    name: staging
  only:
    - staging 

validate_qas:
  stage: validate
  script:
    - gitlab-terraform validate
  environment:
    name: staging
  only:
    - staging

plan_qas:
  stage: build 
  script:
    - gitlab-terraform plan -var-file=${ENV}.tfvars 
    - gitlab-terraform plan-json -var-file=${ENV}.tfvars
  artifacts:
    name: plan
    paths:
      - ${TF_ROOT}/plan.cache
    reports:
      terraform:  ${TF_ROOT}/plan.json
  environment:
    name: staging
  only:
    - staging

apply_qas:
  stage: deploy
  script:
    - gitlab-terraform apply
  dependencies:
    - plan_qas
  environment:
    name: staging
  only:
    - staging

destroy_qas:
  stage: cleanup
  script:
    - gitlab-terraform destroy -var-file=${ENV}.tfvars
  dependencies:
    - plan_qas
    - apply_qas
  when: manual
  environment:
    name: staging
  only:
    - staging

init_prd:
  stage: init
  script:
    - gitlab-terraform init
  environment:
    name: default
  only:
    - main 

validate_prd:
  stage: validate
  script:
    - gitlab-terraform validate
  environment:
    name: default
  only:
    - main

plan_prd:
  stage: build
  script:
    - gitlab-terraform plan -var-file=${ENV}.tfvars 
    - gitlab-terraform plan-json -var-file=${ENV}.tfvars
  artifacts:
    name: plan
    paths:
      - ${TF_ROOT}/plan.cache
    reports:
      terraform:  ${TF_ROOT}/plan.json
  environment:
    name: default
  only:
    - main    

apply_prd:
  stage: deploy
  script:
    - gitlab-terraform apply
  dependencies:
    - plan_prd
  environment:
    name: default
  only:
    - main

destroy_prd:
  stage: cleanup
  script:
    - gitlab-terraform destroy -var-file=${ENV}.tfvars
  dependencies:
    - plan_prd
    - apply_prd
  when: manual
  environment:
    name: default
  only:
    - main
Enter fullscreen mode Exit fullscreen mode

Este bloco definido como workflow, é responsável por identificar os ambientes com base na branch onde foi realizado o commit, inserindo essa informação na variável ENV:

workflow:
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      variables:
        ENV: "production"
    - if: $CI_COMMIT_BRANCH == "development"
      variables:
        ENV: "development"
    - if: $CI_COMMIT_BRANCH == "staging"
      variables:
        ENV: "staging"
Enter fullscreen mode Exit fullscreen mode

Nos scripts de cada stage, utilizamos a variável ENV para determinar qual arquivo tfvars será utilizado, de acordo com cada environment (development.tfvars, staging.tfvars, production.tfvars):

script:
  - gitlab-terraform plan -var-file=${ENV}.tfvars 
  - gitlab-terraform plan-json -var-file=${ENV}.tfvars
Enter fullscreen mode Exit fullscreen mode

Happy building!

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay