Escolar Documentos
Profissional Documentos
Cultura Documentos
Seja Bem-Vindo(a)
Este documento é uma tentativa de descrever sistematicamente as melhores
práticas usando o Terraform, e, fornecer recomendações para os problemas mais
frequentes de seus usuários.
O Terraform é um projeto relativamente novo (como a maioria das ferramentas de DevOps, na verdade) que
foi iniciado em 2014.
O Terraform é poderoso (se não o mais poderoso que existe atualmente) e uma das ferramentas mais
utilizadas que permitem o gerenciamento de infraestrutura como código (IaC). Ele permite que os
desenvolvedores realizem uma grande variedade de coisas e não os restringe de fazê-las de forma com
que sejam difíceis de integrar ou suportar à longo prazo.
Algumas informações descritas neste livro podem não parecer as melhores práticas. Sei disso, e, para
ajudar os leitores a separar as melhores práticas estabelecidas e do que apenas mais uma maneira
opinativa, às vezes, dou dicas para fornecer algum contexto e ícones para especificar o nível de maturidade
em cada subseção relacionada às melhores práticas.
Este livro começou na ensolarada Madri em 2018 e está disponível gratuitamente aqui -
https://www.terraform-best-practices.com/
Alguns anos depois, ele foi atualizado com mais práticas atuais recomendadas disponíveis com o Terraform
1.0. Eventualmente, este livro deve conter a maioria das melhores práticas e recomendações
incontestáveis para usuários do Terraform.
Traduções
English
Español (Spanish)
Bosanski (Bosnian)
Français (French)
Deutsch (German)
)Hebrew( עברית
Italiano (Italian)
ಕನ್ನಡ (Kannada)
हिंदी (Hindi)
Polski (Polish)
Română (Romanian)
Türkçe (Turkish)
Українська (Ukrainian)
Entre em contato se você quer ajudar a traduzir este livro para outros idiomas.
Contribuições
Continuarei atualizando este livro conforme a comunidade amadurece e novas ideias são implementadas e
verificadas. Por favor, deixe seu comentário ou crítica construtiva para que o livro esteja sempre em boa
qualidade.
Se você tem interesse em determinados tópicos, abra um problema no Github, ou curta um já aberto que
você julga ser importante e deva ter prioridade.
Autores
Este livro é mantido por Anton Babenko com a ajuda de diversos colaboradores e tradutores.
Patrocinadores
Licença
Este trabalho está licenciado sob a Licença Apache 2. Veja LICENSE para maiores detalhes.
Os autores e colaboradores deste conteúdo não podem garantir a validade das informações aqui
encontradas. Certifique-se de que entende que as informações aqui contidas estão sendo fornecidas
livremente, e que, nenhum acordo ou contrato é criado entre você e quaisquer pessoas associadas a este
conteúdo ou projeto. Os autores e colaboradores não assumem e, por meio deste, se isentam de qualquer
responsabilidade perante qualquer parte, por qualquer perda, dano ou interrupção causada por erros, ou
omissões nas informações contidas, associadas ou vinculadas a este conteúdo, sejam tais erros ou
omissões resultantes de negligência, acidente ou qualquer outra causa.
A documentação oficial do Terraform descreve todos os aspectos da configuração em detalhes. Leia-o com
atenção para entender o restante desta seção.
Recursos
Um recurso é aws_vpc , aws_db_instance , etc. Um recurso pertence a um provedor, aceita
argumentos, produz atributos e tem ciclos de vida. Um recurso pode ser criado, recuperado, atualizado e
excluído.
Módulo de Recursos
O módulo de recursos é uma coleção de recursos conectados, que juntos, executam a ação comum (por
exemplo, o módulo AWS VPC Terraform cria VPC, sub-redes, gateway NAT, etc.). Depende da
configuração do provedor, que pode ser definida nele, ou em estruturas de nível superior (por exemplo, no
módulo de infraestrutura).
Módulo de infraestrutura
Um módulo de infraestrutura é uma coleção de módulos de recursos, que podem ser logicamente não
conectados, mas na situação/projeto/configuração atual servem ao mesmo propósito. Ele define a
configuração para provedores, passada para os módulos de recursos downstream e para os recursos.
Normalmente é limitado a trabalhar em uma entidade por separar lógico (por exemplo, região da AWS,
projeto do Google).
Por exemplo, o módulo terraform-aws-atlantis utiliza módulo de recursos tais como o terraform-aws-vpc e
terraform-aws-security-group para gerenciar infraestrutura necessária para executar o Atlantis no AWS
Fargate.
Composição
Composição é uma coleção de módulos de infraestrutura, que podem abranger várias áreas separadas
logicamente (por exemplo, regiões da AWS, várias contas da AWS). A composição é usada para descrever
a infraestrutura completa necessária para toda a organização ou projeto.
Uma composição consiste em módulos de infraestrutura, que consistem em módulos de recursos, que
implementam recursos individuais.
Composição de infraestrutura simples
Fonte de Dados
A fonte de dados executa uma operação somente leitura e é dependente da configuração do provedor, é
também usada em um módulo de recursos e em um módulo de infraestrutura.
A fonte de dados terraform_remote_state atua como uma “cola” para módulos e composições de
nível superior.
Já uma fonte de dados externa, permite que um programa externo atue como fonte de dados, expondo
informações arbitrários para uso em outro lugar na configuração do Terraform. Aqui está um exemplo do
módulo terraform-aws-lambda, onde o nome do arquivo é calculado chamando um script Python externo.
A fonte de dados http realiza uma solicitação HTTP GET para o URL fornecido e exporta informações
sobre a resposta, o que geralmente é útil para obter informações de terminais onde um provedor Terraform
nativo não existe.
Estado Remoto
Módulos de infraestrutura e composições devem manter seu estado Terraform em um local remoto, onde
possam ser recuperados por outros de maneira controlável (por exemplo, especificar ACL, versionamento,
logging).
O acesso aos dados entre moléculas (módulos de recursos e módulos de infraestrutura) é realizado
utilizando saídas e fontes de dados dos módulos.
O acesso entre composições geralmente é realizado usando fontes de dados de estado remoto. Existem
várias maneiras de compartilhar dados entre as configurações.
composition-1 {
infrastructure-module-1 {
data-source-1 => d1
resource-module-1 {
data-source-2 => d2
resource-1 (d1, d2)
resource-2 (d2)
}
resource-module-2 {
data-source-3 => d3
resource-3 (d1, d3)
resource-4 (d3)
}
}
}
Estrutura do código
Isolar recursos não relacionados uns aos outros, colocando-os em composições separadas, reduz
o risco se algo der errado.
Inicie seu projeto utilizando o estado remoto porque:
Mais tarde, quando as camadas de infraestrutura começarem a crescer em várias direções (número
de dependências ou recursos), será mais fácil manter as coisas sob controle.
Pratique uma estrutura consistente e uma convenção de nomenclatura:
Assim como o código procedural, o código do Terraform deve ser escrito para que as pessoas leiam
primeiro, a consistência ajudará quando as mudanças ocorrerem daqui a seis meses.
É possível mover recursos no arquivo de estado do Terraform, mas pode ser mais difícil de efetuar
se você tiver estrutura e nomenclatura inconsistentes.
Mantenha os módulos de recursos o mais simples possível.
Não codifique valores que possam ser passados como variáveis ou descobertos usando fontes de
dados.
Use fontes de dados e o terraform_remote_state especificamente como uma cola entre os
módulos de infraestrutura na composição.
Neste livro, os projetos de exemplo são agrupados por complexidade - de infraestruturas pequenas a muito
grandes. Essa separação não é rígida, portanto, verifique também outras estruturas.
Ter uma infraestrutura pequena significa haver um pequeno número de dependências e poucos recursos. À
medida que o projeto cresce, torna-se óbvia a necessidade de encadear a execução das configurações do
Terraform, conectar diferentes módulos de infraestrutura e passar valores em uma composição.
Existem pelo menos 5 grupos distintos de soluções de orquestração que os desenvolvedores usam:
1. Somente o Terraform. Muito simples, os desenvolvedores precisam conhecer apenas o Terraform para
realizar o trabalho.
2. Terragrunt. Ferramenta de orquestração pura que pode ser usada para orquestrar toda a infraestrutura,
bem como lidar com dependências. O Terragrunt opera com módulos e composições de infraestrutura
nativamente, reduzindo assim a duplicação de código.
3. Roteiros internos (in-house scripts). Muitas vezes isso acontece como um ponto de partida para a
orquestração e antes de descobrir o Terragrunt.
4. Ansible ou ferramenta de automação de uso geral similar. Geralmente utilizado quando o Terraform é
adotado após o Ansible, ou quando a “interface” do usuário do Ansible é usada ativamente.
5. Crossplane e outras soluções inspiradas no Kubernetes. Às vezes, faz sentido utilizar o ecossistema
Kubernetes e empregar um recurso de “loop” de reconciliação para atingir o estado desejado de suas
configurações do Terraform. Observe o vídeo Crossplane vs Terraform para mais informações.
Com isso em mente, este livro analisa às duas primeiras dessas estruturas de projeto, apenas Terraform e
Terragrunt.
Veja exemplos de estruturas de código para o Terraform e/ou Terragrunt no próximo capítulo.
Exemplos de estrutura de códigos
Esses exemplos estão mostrando o provedor da AWS, mas a maioria dos princípios mostrados
nos exemplos pode ser aplicada a outros provedores de núvem pública, bem como a outros tipos
de provedores (DNS, DB, Monitoring, etc).
Fonte: https://github.com/antonbabenko/terraform-best-practices/tree/master/examples/small-terraform
Este exemplo contém código como um exemplo de estruturação de configurações do Terraform para uma
infraestrutura de pequeno porte, onde nenhuma dependência externa é utilizada.
Um arquivo de estado único para todos os recursos pode tornar o processo de trabalho com o
Terraform lento, se o número de recursos estiver crescendo (considere utilizar o argumento -
target para limitar o número de recursos)
Infraestrutura média com o Terraform
Fonte: https://github.com/antonbabenko/terraform-best-practices/tree/master/examples/medium-terraform
Este exemplo contém código como um exemplo de estruturação de configurações do Terraform para uma
infraestrutura de médio porte, que utiliza:
2 contas na AWS
2 ambientes separados ( prod e stage que não compartilham nada entre eles). Cada ambiente está
em uma conta separada na AWS.
Cada ambiente utiliza uma versão diferente do módulo de infraestrutura pronto para uso ( alb )
originado do Terraform Registry
Cada ambiente utiliza a mesma versão de módulos/rede de um módulo interno, pois é originado de
um diretório local.
Bom para quando os recursos de infraestrutura são diferentes por ambiente de propósito e
não podem ser generalizados (por exemplo, alguns recursos estão ausentes em um
ambiente ou em algumas regiões)
À medida que o projeto cresce, será mais difícil manter esses ambientes atualizados entre sí.
Considere o uso de módulos de infraestrutura (já prontos ou internos) para tarefas repetíveis.
Infraestrutura grande com o Terraform
Fonte: https://github.com/antonbabenko/terraform-best-practices/tree/master/examples/large-terraform
Este exemplo contém código como um exemplo de estruturação de configurações do Terraform para uma
infraestrutura de médio porte, que utiliza:
2 contas na AWS
2 ambientes separados ( prod e stage que não compartilham nada entre eles). Cada ambiente está
em uma conta separada na AWS.
Cada ambiente utiliza uma versão diferente do módulo de infraestrutura pronto para uso ( alb )
originado do Terraform Registry
Cada ambiente utiliza a mesma versão de módulos/rede de um módulo interno, pois é originado de
um diretório local.
Em um grande projeto como o descrito aqui, os benefócios do uso do Terragrunt se tornam muito
visíveis. Veja Estruturas de código de exemplos com o Terragrunt.
À medida que o projeto cresce, será mais difícil manter esses ambientes atualizados entre sí.
Considere o uso de módulos de infraestrutura (já prontos ou internos) para tarefas repetíveis.
Convenções de nomenclatura
Convenções gerais
Não deve haver razão alguma para não seguir pelo menos essas convenções :)
Esteja ciente de que os recursos reais da núvem geralmente têm restrições em nomes
permitidos. Alguns recursos, por exemplo, não podem conter travessões, alguns devem ser em
caixa de camelo (mais conhecido como CamelCase). As convenções neste livro referem-se aos
próprios nomes do Terraform.
1. Utilize _ (subtraço) ao invés do - (traço) em todo o lugar (nomes de recursos, nomes de fontes de
dados, nomes de variáveis, outputs, etc.).
2. Prefira usar letras minúsculas e números (mesmo que o UTF-8 seja suportado).
2. O nome do recurso deve ser nomeado this se não houver mais um nome descritivo e geral
disponível ou se o módulo de recurso criar um único recurso desse tipo (por exemplo, no módulo AWS
VPC há um único recurso do tipo aws_nat_gateway e vários recursos do
tupo aws_route_table , então aws_nat_gateway deve ser nomeado this e
aws_route_table deve ter nomes mais descritivos - como private , public , database ).
depends_on e lifecycle , se necessário. Estes devem ser separados por uma única linha vazia.
main.tf
resource "aws_route_table" "public" {
count = 2
vpc_id = "vpc-12345678"
# ... argumentos restantes omitidos
}
vpc_id = "vpc-12345678"
# ... argumentos restantes omitidos
}
main.tf
resource "aws_route_table" "public" {
vpc_id = "vpc-12345678"
count = 2
main.tf
resource "aws_nat_gateway" "this" {
count = 2
allocation_id = "..."
subnet_id = "..."
tags = {
Name = "..."
}
depends_on = [aws_internet_gateway.this]
lifecycle {
create_before_destroy = true
}
}
main.tf
resource "aws_nat_gateway" "this" {
count = 2
tags = "..."
depends_on = [aws_internet_gateway.this]
lifecycle {
create_before_destroy = true
}
allocation_id = "..."
subnet_id = "..."
}
outputs.tf
resource "aws_nat_gateway" "that" { # Perfeito
count = var.create_public_subnets ? 1 : 0
}
Variáveis
1. Não reinvente a roda em módulos de recursos: use name , description , e valor default para
variáveis conforme definido na seção “Referência de argumento” para o recurso com o qual você está
trabalhando.
2. O suporte para validação em variáveis é bastante limitado (por exemplo, não pode acessar outras
variáveis ou fazer pesquisas). Planeje de acordo porque em muitos casos esse recurso é inútil.
3. Use a forma plural em um nome de variável quando o tipo for list(...) ou map(...) .
5. Sempre inclua description em todas as variáveis, mesmo que você julgue ser óbvio (você
precisará disso, no futuro).
6. Prefira usar tipos simples ( number , string , list(...) , map(...) , any ) sobre tipos
específicos como object() , a menos que você precise ter restrições estritas em cada chave.
7. Use tipos específicos como map(map(string)) se todos os elementos do mapa tiverem o mesmo
tipo (ex. string ) ou podem ser convertidos para ele (ex. number pode ser convertido para
string ).
8. Use tipo any para desabilitar a validação de tipo a partir de uma determinada profundidade ou
quando vários tipos devem ser suportados.
9. O valor {} às vezes é um mapa, mas às vezes é um objeto. Use tomap(...) para criar um mapa
porque não há como criar um objeto.
Outputs
Torne os outputs consistentes e compreensíveis fora de seu escopo (quando um usuário está usando um
módulo, deve ser óbvio que tipo e atributo do valor ele retorna).
1. O nome do output deve descrever a propriedade que ela contém e ser menos livre do que você
normalmente desejaria.
2. Uma boa estrutura para o nome do output parece com {name}_{type}_{attribute} , onde:
4. Veja exemplos.
3. Se o output estiver retornando um valor com funções de interpolação e vários recursos, {name} e
{type} devem ser o mais genéricos possível ( this como prefixo deve ser omisso). Veja exemplos.
4. Se o valor retornado for uma lista, deve ter um nome no plural. Veja exemplos.
5. Sempre inclua description para todos os outputs mesmo que você julgue que ser óbvio.
6. Evite definir o argumento sensitive , a menos que você controle totalmente o uso desse output em
outputs.tf
output "security_group_id" {
description = "The ID of the security group"
value = try(aws_security_group.this[0].id, aws_security_group.name_prefix[0]
}
Quando há vários recursos do mesmo tipo, this deve ser omisso no nome do output:
outputs.tf
output "this_security_group_id" {
description = "The ID of the security group"
value = element(concat(coalescelist(aws_security_group.this.*.id, aws_securi
}
output "rds_cluster_instance_endpoints" {
description = "A list of all cluster instance endpoints"
value = aws_rds_cluster_instance.this.*.endpoint
}
Estilo de código
Todos os links nos arquivos README.md devem ser absolutos para que o site do Terraform
Registry os mostre corretamente.
A documentação pode incluir diagramas criados com mermaid e plantas criadas com o
cloudcraft.co.
Utilize o Terraform pre-commit hooks para garantir que o código seja válido, formatado
corretamente e documentado automaticamente antes de ser enviado para o git e revisado
por humanos.
Documentação
O pre-commit é um framework para gerenciar e manter hooks pré-commit multi-idioma. Ele é escrito em
Python e é uma ferramente poderosa para fazer algo automaticamente na máquina de um desenvolvedor
antes que o código seja enviado para o repositório git. Normalmente, ele é usado para executar linters e
formatar código (veja supported hooks).
Com as configurações do Terraform, o pre-commit pode ser usado para formatar e validar o código, bem
como para atualizar a documentação.
Confirma o repositório pre-commit-terraform para se familiarizar com ele e os repositórios existentes (por
exemplo, terraform-aws-vpc) onde ele já é utilizado.
terraform-docs
O terraform-docs é uma ferramente que faz a geração de documentação a partir de módulos Terraform em
vários formatos de saída (output). Você pode executá-lo manualmente (sem ganchos — pre-commit hooks
— de pré-commit) ou usar o pre-commit-terraform hooks para atualizar a documentação automaticamente.
Recursos
Não existe uma ferramenta de gerenciamento de dependência mestre, mas existem algumas dicas para
tornar a dependência menos problemática. Por exemplo, o Dependabot pode ser usado para automatizar
as atualizações de dependências seguras e atualizadas. O Dependabot é compatível com as
configurações do Terraform.
Referências
Existem muitas pessoas que criam ótimos conteúdos e gerenciam projetos de código aberto
relevantes para a comunidade Terraform, mas não consigo pensar na melhor estrutura para obter
esses links listados aqui sem copiar listas como a awesome-terraform.
https://weekly.tf - Boletim semanal Terraform. Várias notícias no mundo Terraform (projetos, anúncios,
discussões) por Anton Babenko.
Escrevendo configurações do Terraform
https://raw.githubusercontent.com/antonbabenko/terraform-best-practices/master/snippets/locals.tf
1. O argumento obrigatório index_document deve ser definido, se var.website não for um mapa
vazio.
2. O argumento opcional error_document pode ser omitido.
main.tf
variable "website" {
type = map(string)
default = {}
}
dynamic "website" {
for_each = length(keys(var.website)) == 0 ? [] : [var.website]
content {
index_document = website.value.index_document
error_document = lookup(website.value, "error_document", null)
}
}
}
terraform.tfvars
website = {
index_document = "index.html"
}
Workshop
Há também um ‘workshop’ para pessoas que desejam praticar algumas das coisas descritas neste guia.