Terraform e a infraestrutura como código reutilizável

Thiago da Silva Nogueira
#EmpiricusTech
Published in
7 min readApr 5, 2021

Cada vez mais, empresas do mundo todo têm migrado suas aplicações para as famosas “nuvens públicas”. Existem vários motivos para essa adoção, como redução de custos relacionados a hardware, resiliência, disponibilidade e escalabilidade das aplicações, configurações simplificadas, integração com muitas ferramentas (open source ou não), entre outros.

Toda essa facilidade proporcionada pelas consoles intuitivas, gera uma necessidade de um maior controle sobre a infraestrutura criada, seja para um possível “disaster recovery” ou para replicar a estrutura para uma nova aplicação.

Para atuar nessa questão, eu falarei sobre o Terraform, ferramenta para Infrastructure as Code (IaC), escolhida para o gerenciamento da infraestrutura da Empiricus.

O que é o Terraform?

O Terraform é uma ferramenta criada pela Hashicorp para criar, alterar e manter versões de infraestrutura com eficiência e segurança em diversos provedores de nuvem pública. Você pode efetuar toda a configuração em um único ou vários arquivos, que irão determinar quais recursos / componentes serão criados, alterados ou excluídos.

Um plano de execução é gerado para que você possa verificar em detalhes o que será aplicado. Após confirmar as alterações, o Terraform iniciará a execução das mudanças na infraestrutura, apresentando um resumo das ações ao final da execução.

Também é possível reutilizar o código existente para a criação de uma nova infraestrutura, que pode ser definida apenas para uma aplicação ou para um datacenter inteiro. O código também pode ser enviado a um repositório git, trabalhando com branchs e pull requests, como um código de aplicação.

O arquivo “tfstate”

Quando um plano de execução é aplicado, um arquivo chamado “terraform.tfstate” é gerado, e nele é armazenado o estado atual da infraestrutura. Toda vez que um novo plano de execução é gerado, o Terraform consulta este arquivo fazendo a comparação do que existe versus o que será criado / alterado.

O tfstate pode ser armazenado localmente junto com todo o código da infraestrutura ou de forma remota, armazenado em um bucket s3 por exemplo. Vejamos as diferenças:

Armazenamento local:

Comumente utilizado para infraestruturas mais simples, nas quais não existem muitas pessoas criando / alterando recursos. Conforme a infra cresce, o arquivo tfstate também aumenta de tamanho, o que em alguns casos pode ser problemático armazenar em repositórios git, além de aumentar as chances de “git conflict”, caso tenha pessoas alterando a mesma infra em paralelo.

Armazenamento remoto:

Normalmente utilizado quando existe uma ou mais equipes administrando a mesma infraestrutura. Diminui consideravelmente as chances de ocorrer “git conflict”, devido ao fato de que o arquivo tfstate remoto será atualizado para todas as equipes sem a necessidade de efetuar pull / push.

Terraform na prática

Para este exemplo, efetuarei a instalação do terraform v0.13.4 em um Ubuntu Linux. Para outros Sistemas Operacionais, acesse: https://learn.hashicorp.com/tutorials/terraform/install-cli#install-terraform

Primeiro vamos baixar o binário compactado do terraform:

$ wget https://releases.hashicorp.com/terraform/0.13.4/terraform_0.13.4_linux_amd64.zip

Instale agora o pacote “zip” caso não o tenha e extraia o binário terraform:

$ sudo apt install zip -y; unzip terraform_0.13.4_linux_amd64.zip

Mova o binário para /usr/local/bin/:

$ sudo mv terraform /usr/local/bin/

Confirme a versão, e caso não apresente erro, podemos considerar que o terraform está devidamente instalado:

$ terraform version
Terraform v0.13.4
Your version of Terraform is out of date! The latest version
is 0.14.7. You can update by downloading from https://www.terraform.io/downloads.html

Vamos agora mostrar um pequeno exemplo de como criar um repositório ECR na AWS via Terraform.

1 — Crie um arquivo chamado “main.tf” e digite o seguinte código:

## AWS PROVIDER
# Aqui iremos informar qual provedor iremos utilizar,
# no caso iremos utilizar o provedor para AWS
provider "aws" {
region = "us-east-1" # Informe a região em que o recurso será criado, ex: us-east-1
shared_credentials_file = "path/you/aws/credentials" # Informe o path de onde está localizado seu "aws-credentials" file.
profile = "name_you_aws_profile" # Informe o nome do seu "profile"
}
resource "aws_ecr_repository" "ecr_main" {
name = "dev-myapp"
image_tag_mutability = "MUTABLE"
image_scanning_configuration {
scan_on_push = true
}
}

2 — Como é a primeira execução, vamos utilizar o comando “terraform init”, e com isso todas as dependências para o AWS PROVIDER serão baixadas:

3 — Agora utilizaremos o comando “terraform plan”. A partir dele será gerado um “plano de mudança” para que possamos validar as alterações:

4 — Caso as alterações estejam de acordo com o esperado, utilizaremos o comando “terraform apply” para aplicar as alterações:

Durante o processo o “plano de alteração” será exibido novamente, porém, desta vez, você deverá confirmar as alterações digitando “yes”, ou “no” para cancelar a alteração.

Após a confirmação o Terraform irá iniciar as alterações em sua infraestrutura, exibindo um status de cada alteração feita.

Agora se listarmos os arquivos no diretório atual, veremos que o arquivo “terraform.tfstate” foi criado e possui o status atual da infra:

Exemplo do conteúdo de um arquivo tfstate.
Exemplo do conteúdo de um arquivo tfstate.

5 — Agora conheceremos o comando “terraform destroy”. Esse comando é utilizado para deletar toda a infraestrutura criada (com base no arquivo tfstate) e dificilmente será utilizado, visto que, para remover apenas alguns recursos da infra, basta remover o código relacionado ou caso utilize módulos, desativar a chamada ao mesmo.

O “terraform destroy” apresentará o “plano de deleção” e você deverá confirmar se deseja ou não continuar com o plano:

Dados sensíveis ocultos no “plano de destroy”

Embora simples e funcional, esse exemplo ainda não possui as características de um código reutilizável, então iremos incrementá-lo e deixá-lo reutilizável.

Para esse exemplo, utilizaremos a seguinte estrutura:

├── config
│ └── ecr-lifecycle.json
├── ecr.tf
├── env
│ └── environment.tfvars
├── provider.tf
├── terraform.tfstate
└── vars.tf

config/: diretório utilizado para armazenar configurações dos recursos (ex: iam policy, ecr lifecycle).
config/ecr-lifecycle.json: arquivo JSON para configurar lifecycle de imagens ECR.
ecr.tf: arquivo contendo o código para criar um repositório ECR.
env/: diretório utilizado para armazenar variáveis da infraestrutura e backend
env/environments.tfvars: arquivo contendo as variáveis da infraestrutura
provider.tf: arquivo contendo o código para AWS Provider.
terraform.tfstate: arquivo que armazena o estado atual da infraestrutura
vars.tf: arquivo para declarar as variáveis utilizadas.

Conteúdo dos arquivos (já com os comentários):

config/ecr-lifecycle.json:

{
“rules”: [
{
“rulePriority”: 1,
“description”: “Expire images older than 15 days”,
“selection”: {
“tagStatus”: “untagged”,
“countType”: “sinceImagePushed”,
“countUnit”: “days”,
“countNumber”: 15
},
“action”: {
“type”: “expire”
}
}
]
}

ecr.tf:

# Cria o resource AWS ECR
resource “aws_ecr_repository” “ecr_main” {
name = “${var.AMBIENTE}-${var.REPOSITORY_NAME}”
image_tag_mutability = “MUTABLE”
image_scanning_configuration {
scan_on_push = true
}
tags = local.common-tags
}
# Cria uma policy de lifecycle com base em um arquivo JSON
resource “aws_ecr_lifecycle_policy” “ecr_lifecycle” {
repository = aws_ecr_repository.ecr_main.name
policy = file(“config/ecr-lifecycle.json”)}

env/environments.tfvars:

# Variaveis para aws provider
AWS_REGION = “us-east-1”
AWS_AUTH_FILE = “/path/of/aws-credentials/file”
AWS_AUTH_PROFILE = “profile-name”
# Variaveis para ecr
AMBIENTE = “dev”
REPOSITORY_NAME = “myapp”
# Variaveis para tags
tgOwner = “MS”
tgProject = “MyApp”
tgAmbiente = “dev”

provider.tf:

# AWS PROVIDER
# Aqui iremos informar qual provedor iremos utilizar,
# no caso iremos utilizar o provedor para AWS
provider "aws" {
region = var.AWS_REGION # Informe a região em que o recurso será criado, ex: us-east-1
shared_credentials_file = var.AWS_AUTH_FILE # Informe o path de onde está localizado seu "aws-credentials" file.
profile = var.AWS_AUTH_PROFILE # Informe o nome do seu "profile"
}

vars.tf:

# Neste arquivo iremos declarar as variaveis que serão utilizadas pelo terraform.
# Também estaremos utilizando "locals" para definir valores em comum para nossa infra (ex: tags)
locals {
common-tags = {
Owner = var.tgOwner
Project = var.tgProject
Environment = var.tgAmbiente
}
}
# AUTH VARS
variable "AWS_REGION" {}
variable "AWS_AUTH_FILE" {}
variable "AWS_AUTH_PROFILE" {}
# ECR VARS
variable "AMBIENTE" {}
variable "REPOSITORY_NAME" {}
# TAGS
variable "tgOwner" {}
variable "tgProject" {}
variable "tgAmbiente" {}

Neste exemplo, além de adicionarmos mais configurações, também dividimos o código em vários arquivos, cada um com seu recurso específico.

Também temos agora um arquivo de environment (environment.tfvars), onde especificamos detalhes do nosso ambiente, e nesse modelo, podemos criar diversos ambientes, apenas alterando os detalhes no arquivo.

Vejamos na prática:

1 — Execute o “terraform init”:

2 — Agora iremos executar o “terraform plan” passando o arquivo de environment como parâmetro:

terraform plan –var-file env/environment.tfvars
terraform plan com o parâmentro de env-file

3 — Ao executarmos o comando “terraform apply”, também devemos informar o mesmo parâmetro:

terraform apply –var-file env/environment.tfvars:

Após verificar se as alterações estão corretas, basta digitar “yes” para que o plano de mudanças seja executado.

Com esses exemplos, podemos ter uma ideia de como o Terraform pode ser útil para gerirmos desde uma infra pequena e simples, até mesmo um datacenter inteiro.

Também existe a opção de utilizarmos “módulos” de recursos no terraform, onde podemos “ligar e desligar” novos recursos ou algum recurso que não desejamos mais utilizar, porém isso é papo para outro artigo.

Caso tenha interesse em se aprofundar no assunto, vou deixar alguns links que podem ajudar:

Site oficial:
https://www.terraform.io/
Docs e exemplos:
https://registry.terraform.io/providers/hashicorp/aws/latest/docs
Terraform modules:
https://www.terraform.io/docs/language/modules/develop/index.html

--

--

Thiago da Silva Nogueira
#EmpiricusTech

Site Reliability Engineer de Services @ Empiricus | Entusiasta DevOps | Amante de tecnologia e viagens | atleta Brazilian Jiu Jitsu.