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!

Top comments (0)