Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
As perguntas relacionadas à estrutura de código do Terraform sào de longe as mais frequentes na comunidade. Todos pensaram na melhor estrutura de código para o projeto em algum momento também.
Esta é uma das questões em que existem muitas soluções e é muito difícil dar conselhos dinâmicos, então vamos começar entendendo com o que estamos lidando.
Qual é a complexidade do seu projeto?
Número de recursos relacionados.
Número de provedores Terraform (veja a nota abaixo sobre “provedores lógicos”).
Com que frequência sua infraestrutura muda?
A partir de uma vez por mês/semana/dia.
Continuamente (toda vez que houver um novo commit).
Iniciadores de mudança de código? Você permite que o servidor CI atualize o repositório quando um novo artefato é criado?
Somente desenvolvedores podem realizar o push para o repositório de infraestrutura.
Todos podem propor uma mudança em qualquer coisa abrindo um PR (incluindo tarefas automatizadas em execução no servidor CI).
Qual plataforma de implementação ou serviço de implementação você utiliza?
AWS CodeDeploy, Kubernetes, ou OpenShift exigem uma abordagem um pouco diferente.
Como os ambientes são agrupados?
Por ambiente, região, projeto...
Colocar todo o código em um único main.tf
é uma boa ideia quando você está começando ou escrevendo um código de exemplo. Em todos os outros casos, será melhor ter vários arquivos divididos logicamente assim:
main.tf
- chame módulos, locais e fontes de dados para criar todos os recursos.
variables.tf
- contém declarações de variáveis utilizadas em main.tf.
outputs.tf
- contém saídas dos recursos criados em main.tf.
versions.tf
- contém requisitos de versão para Terraform e provedores.
terraform.tfvars
não deve ser utilizado em nenhum lugar exceto na composição.
Por favor, certifique-se de entender os principais conceitos - módulo de recursos,
módulo de infraestrutura e composição, conforme são utilizados nos exemplos a seguir.
É mais fácil e rápido trabalhar com um número menor de recursos
terraform plan
e terraform apply
fazem chamada API na nuvem para verificar o status dos recursos.
Se você tiver toda a sua infraestrutura em uma única composição, isso pode levar algum tempo.
O raio afetado é menor com menos recursos
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:
Seu notebook não é lugar para sua fonte de verdade de infraestrutura.
Gerenciar um arquivo tfstate
no git é um pesadelo.
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:
Somente o Terraform. Muito simples, os desenvolvedores precisam conhecer apenas o Terraform para realizar o trabalho.
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.
Roteiros internos (in-house scripts). Muitas vezes isso acontece como um ponto de partida para a orquestração e antes de descobrir o Terragrunt.
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.
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.
Tipo | Descrição | Disponibilidade |
---|---|---|
Tipo | Descrição | Disponibilidade |
---|---|---|
Poucos recursos, sem dependências externas. Conta única da AWS. Região única. Ambiente único.
Sim
Diversas contas e ambientes na AWS, módulos de infraestrutura prontos para o uso utilizando o Terraform.
Sim
Muitas contas na AWS, muitas regiões, necessidade urgente de reduzir copiar e colar, módulos de infraestrutura personalizados, uso intenso de composições. Utilizando o Terraform.
Trabalho em progresso
muito grande (nível Enterprise)
Diversos provedores (AWS, GCP, Azure). Implementações em diversas nuvens. Utilizando o Terraform.
Não
médio
Diversas contas e ambientes na AWS, módulos de infraestrutura prontos para o uso utilizando o Terragrunt.
Não
grande
Muitas contas na AWS, muitas regiões, necessidade urgente de reduzir copiar e colar, módulos de infraestrutura personalizados, uso intenso de composições. Utilizando o Terragrunt.
Não
muito grande (nível Enterprise)
Diversos provedores (AWS, GCP, Azure). Implementações em diversas nuvens. Utilizando o Terragrunt.
Não
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.
Please contact me if you want to become a sponsor.
Entre em contato se você quer ajudar a traduzir este livro para outros idiomas.
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.
Este livro é mantido por Anton Babenko com a ajuda de diversos colaboradores e tradutores.
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.
Direito autoral © 2018-2023 Anton Babenko.
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.
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.
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).
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.
Outro exemplo é o módulo terraform-aws-cloudquery, onde vários módulos do terraform-aws-modules estão sendo utilizados juntos para gerenciar a infraestrutura, assim como utilizar recursos do Docker para criar, enviar e implantar imagens Docker. Tudo em um conjunto.
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.
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.
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).
Provedores, provisionadores e alguns outros termos estão muito bem descritos na documentação oficial e não vale a pena repetir aqui. Na minha opinião, eles têm pouco a ver com escrever bons módulos Terraform.
Enquanto os recursos individuais são como átomos na infraestrutura, os módulos de recursos são moléculas. Um módulo é a menor unidade com versão e compartilhável. Possui uma lista exata de argumentos, implementa lógica básica para que tal unidade realize a função necessária. Por exemplo, o módulo terraform-aws-security-group cria recursos aws_security_group
e aws_security_group_rule
com base no input. Este módulo de recursos por si só pode ser usado em conjunto com outros módulos para criar o módulo de infraestrutura.
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.
Ao colocar os conceitos descritos acima em pseudo-relações, pode-se ficar assim:
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 a mesma versão de módulos/rede
de um módulo interno, pois é originado de um diretório local.
Perfeito para projetos em que a infraestrutura é separada logicamente (contas AWS separadas)
Bom para quando não há necessidade de modificar recursos compartilhados entre contas da AWS (um ambiente = uma conta da AWS = um arquivo de estado)
Bom para quando não há necessidade na orquestração de mudanças entre os ambientes
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.
Fonte:
Cada ambiente utiliza uma versão diferente do módulo de infraestrutura pronto para uso (alb
) originado do
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.
Perfeito para começar e refatorar à medida que avança
Perfeito para pequenos módulos de recursos
Bom para módulos de infraestrutura pequenos e lineares (ex, terraform-aws-atlantis)
Bom para um número pequeno de recursos (menos de 20-30)
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)
CAST AI — Cut your Kubernetes costs by 60%+ on average. First cluster optimization FREE!
Speakeasy — Terraform Providers, SDKs and docs for your API. Make your API enterprise-ready!
FTP (Frequent Terraform Problems)
- Ferramenta de orquestração
- Ferramenta de checagem de código
- Sistema de controle de versão
- Automação de Pull Requests
- Coleção de git hooks para Terraform para ser usado com o
- Estimativas de custo de nuvem para Terraform em solicitações de Pull Requests. Funciona com Terragrunt, Atlantis e pré-commits também.
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 pode ser usado para automatizar as atualizações de dependências seguras e atualizadas. O Dependabot é compatível com as configurações do Terraform.
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.
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.).
Prefira usar letras minúsculas e números (mesmo que o UTF-8 seja suportado).
Não repita a categoria de recurso no nome do recurso (não parcialmente, nem completamente):
resource "aws_route_table" "public" {}
resource "aws_route_table" "public_route_table" {}
resource "aws_route_table" "public_aws_route_table" {}
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 tupoaws_route_table
, então aws_nat_gateway
deve ser nomeado this
e aws_route_table
deve ter nomes mais descritivos - como private
, public
, database
).
Sempre utilize substantivos singulares para nomes.
Utilize -
em valores de argumentos e em locais onde o valor será exposto a um humano (por exemplo, no nome de DNS da instância RDS).
Inclua o(s) argumento(s) count
/ for_each
no bloco de recurso ou fonte de dados como o primeiro argumento na parte superior e separe por uma nova linha depois dele.
Inclua o argumento tags,
se suportadas pelo recurso, como o último argumento real, seguido por depends_on
e lifecycle
, se necessário. Estes devem ser separados por uma única linha vazia.
Ao utilizar condições em um argumento count
/ for_each
, prefira valores boleanos (true
/ false
) em vez de usar length
ou outras expressões.
resource
count
/ for_each
tags
count
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.
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.
Use a forma plural em um nome de variável quando o tipo for list(...)
ou map(...)
.
Chaves de ordem em um bloco variável como: description
, type
, default
, validation
.
Sempre inclua description
em todas as variáveis, mesmo que você julgue ser óbvio (você precisará disso, no futuro).
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.
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
).
Use tipo any
para desabilitar a validação de tipo a partir de uma determinada profundidade ou quando vários tipos devem ser suportados.
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.
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).
O nome do output deve descrever a propriedade que ela contém e ser menos livre do que você normalmente desejaria.
Uma boa estrutura para o nome do output parece com {name}_{type}_{attribute}
, onde:
{name}
um nome de recurso ou fonte de dados sem um prefixo de provedor. O {name}
do aws_subnet
é subnet
, para oaws_vpc
é vpc
.
{type}
é um tipo de fontes de recursos.
{attribute}
é um atributo retornado pelo output.
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.
Se o valor retornado for uma lista, deve ter um nome no plural. Veja exemplos.
Sempre inclua description
para todos os outputs mesmo que você julgue que ser óbvio.
Evite definir o argumento sensitive
, a menos que você controle totalmente o uso desse output em todos os locais em todos os módulos.
Prefira try()
(disponível desde o Terraform 0.13) ao invés de element(concat(...))
(abordagem herdada para a versão anterior a 0.13).
output
Retorne no máximo um ID do security-group
:
Quando há vários recursos do mesmo tipo, this
deve ser omisso no nome do output:
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 regiões (ap-southeast-2
e us-west-1
, por exemplo)
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 a mesma versão de módulos/rede
de um módulo interno, pois é originado de um diretório local.
Perfeito para projetos em que a infraestrutura é separada logicamente (contas AWS separadas)
Bom para quando não há necessidade de modificar recursos compartilhados entre contas da AWS (um ambiente = uma conta da AWS = um arquivo de estado)
Bom para quando não há necessidade na orquestração de mudanças entre os ambientes
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.
Os módulos de exemplos e do Terraform devem conter documentação explicando os recursos e como usá-los.
Todos os links nos arquivos README.md devem ser absolutos para que o site do Terraform Registry os mostre corretamente.
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.
@todo: Document module versions, release, GH actions
locals
para especificar dependências explícitas entre recursosUma maneira útil de dar uma dica ao Terraform de que alguns recursos devem ser excluídos antes mesmo quando não houver dependência direta nas configurações do Terraform.
O argumento obrigatório index_document
deve ser definido, se var.website
não for um mapa vazio.
O argumento opcional error_document
pode ser omitido.
Fonte:
Cada ambiente utiliza uma versão diferente do módulo de infraestrutura pronto para uso (alb
) originado do
Em um grande projeto como o descrito aqui, os benefócios do uso do Terragrunt se tornam muito visíveis. Veja
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 .
- Lista de pessoas que trabalham com o Terraform muito ativamente e podem lhe dizer muito sobre (se você perguntar-lhes).
- Lista com curadoria de recursos no Terraform da HashiCorp.
- O canal do YouTube "Your Weekly Dose of Terraform" de Anton Babenko. Transmissões ao vivo com análises, entrevistas, perguntas e respostas, codificação ao vivo e alguns hacks com o Terraform.
- Boletim semanal Terraform. Várias notícias no mundo Terraform (projetos, anúncios, discussões) por Anton Babenko.
A documentação pode incluir diagramas criados com e plantas criadas com o .
Utilize o 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.
O é 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 ).
Confirma o repositório para se familiarizar com ele e os repositórios existentes (por exemplo, ) onde ele já é utilizado.
O é 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 para atualizar a documentação automaticamente.
Blog post by :
Há também um ‘workshop’ para pessoas que desejam praticar algumas das coisas descritas neste guia.
Você pode conferir o material aqui (em inglês) - https://github.com/antonbabenko/terraform-best-practices-workshop