Construa um pequeno módulo reutilizável

AWSBeginner
Pratique Agora

Introdução

Duas equipes precisam do mesmo projeto simples de armazenamento de relatórios, com nomes, responsáveis e textos de relatórios diferentes. Conclua a interface de um módulo fornecido, chame-o a partir de dois diretórios raiz independentes e amplie uma coleção estável de relatórios sem substituir os membros existentes.

Você deve compreender módulos locais, variáveis, saídas e endereços de recursos. A estrutura inicial dos recursos e as entradas dos chamadores são fornecidas; você define o contrato entre eles e os implanta neste novo ambiente, com ferramentas preparadas e sem precisar de uma conta pessoal da AWS.

Relação com certificações

Certificação Tarefa do exame Prática
CloudOps Engineer – Associate (SOA-C03) Tarefa 3.1, Habilidade 3.1.6 Prática básica com Terraform: manter a infraestrutura por meio de alterações revisadas na configuração e no estado, preservando os recursos em uso.

Visão geral do laboratório

Diagrama conceitual: a tarefa de manutenção preserva a relação entre a configuração, o estado e o armazenamento de relatórios existente.

Defina uma interface de módulo com tipos explícitos

Nesta etapa, conclua o contrato de entradas e saídas de um pequeno módulo de armazenamento reutilizável. Um módulo filho agrupa recursos por trás de uma interface; um módulo raiz fornece entradas concretas e tem seu próprio estado.

cd /home/labex/project/reusable-reports
cat modules/report-store/main.tf
cat dev/main.tf

A estrutura inicial dos recursos fornecida usa var.bucket_name, var.owner e var.reports. for_each cria uma instância de objeto por chave do mapa, usando endereços como aws_s3_object.reports["daily"]. Chaves nomeadas estáveis mantêm um objeto existente separado de um membro recém-adicionado. O recurso de versionamento do bucket é uma dependência explícita para que as gravações dos relatórios recebam identidades de versão.

Defina a interface. map(object({ body = string })) aceita uma coleção nomeada cujos membros devem fornecer, cada um, o texto de um relatório. Isso explicita as expectativas do módulo, em vez de depender de estruturas de entrada não documentadas:

cat > modules/report-store/variables.tf <<'HCL'
variable "bucket_name" {
  type        = string
  description = "Unique bucket name supplied by this environment root."
}
variable "owner" {
  type        = string
  description = "Owner tag supplied by the caller."
}
variable "reports" {
  type        = map(object({ body = string }))
  description = "Stable report keys and their text content."
}
HCL

As saídas expõem informações úteis sobre os recursos sem exigir que o chamador acesse os detalhes internos do módulo. A expressão for abaixo constrói um mapa de cada chave para a chave do objeto correspondente:

cat > modules/report-store/outputs.tf <<'HCL'
output "bucket_id" {
  value = aws_s3_bucket.store.id
}
output "object_keys" {
  value = { for key, report in aws_s3_object.reports : key => report.key }
}
HCL

Inicialize o diretório raiz dev e verifique o contrato:

terraform -chdir=dev init
terraform -chdir=dev validate
terraform -chdir=dev plan

Espere uma configuração válida e 3 to add: o bucket, a configuração de versionamento e o objeto do relatório diário. Não aplique até verificar o nome do bucket, o responsável e o texto do relatório definidos pelo chamador. A referência financeira independente não está relacionada a este módulo e deve permanecer inalterada.

Chame o mesmo módulo a partir de dois diretórios raiz independentes

Nesta etapa, implante dev e preview por meio do mesmo módulo, com entradas diferentes. Os diretórios raiz compartilham os arquivos-fonte do módulo, não o estado. Seus diretórios de trabalho separados usam atualmente estados locais separados; for_each apenas separa recursos dentro de um estado.

Revise e aplique o plano salvo de dev:

terraform -chdir=dev plan -out=dev.tfplan

Espere 3 to add, 0 to change, 0 to destroy.

terraform -chdir=dev apply dev.tfplan

Leia o chamador de preview antes de inicializá-lo:

cat preview/main.tf
terraform -chdir=preview init
terraform -chdir=preview validate
terraform -chdir=preview plan -out=preview.tfplan

Suas entradas distintas selecionam module-preview-reports, o responsável preview e preview daily report. Espere outro plano de criação de três recursos, sem alterações em dev.

terraform -chdir=preview apply preview.tfplan

Inspecione as saídas e o endereço estável da instância em cada diretório raiz:

terraform -chdir=dev output
terraform -chdir=preview output
terraform -chdir=dev state list
terraform -chdir=preview state list

Os dois diretórios raiz expõem bucket_id e object_keys; cada um tem uma instância de relatório com a chave "daily", mas esses endereços pertencem a estados locais e buckets diferentes. Leia o conteúdo armazenado:

aws s3 \
  cp s3://module-dev-reports/reports/daily.txt -
aws s3 \
  cp s3://module-preview-reports/reports/daily.txt -

Espere dev daily report e preview daily report. O AWS View mostra dois armazenamentos independentes e a referência financeira. Exiba o VersionId atual do relatório diário de dev para compará-lo após ampliar a coleção:

aws s3api \
  head-object \
  --bucket module-dev-reports \
  --key reports/daily.txt \
  --query VersionId \
  --output text

Adicione um membro estável à coleção sem substituir relatórios existentes

Nesta etapa, amplie apenas o mapa de dev. Alterar as chaves de uma coleção altera a identidade das instâncias de recursos; manter a chave daily e adicionar weekly deve preservar o objeto diário intacto.

Substitua o chamador de dev pelas mesmas entradas existentes, acrescidas de um novo membro:

cat > dev/main.tf <<'HCL'
module "report_store" {
  source      = "../modules/report-store"
  bucket_name = "module-dev-reports"
  owner       = "dev"
  reports = {
    daily  = { body = "dev daily report\n" }
    weekly = { body = "dev weekly report\n" }
  }
}
output "bucket_id" { value = module.report_store.bucket_id }
output "object_keys" { value = module.report_store.object_keys }
HCL

Revise a alteração:

terraform -chdir=dev plan -out=extra.tfplan

Espere 1 to add, 0 to change, 0 to destroy, adicionando apenas module.report_store.aws_s3_object.reports["weekly"]. Se o objeto diário existente ou o bucket for substituído, pare e compare as chaves e as entradas que deveriam permanecer inalteradas.

terraform -chdir=dev apply extra.tfplan

Compare o VersionId do relatório diário com a saída da etapa anterior:

aws s3api \
  head-object \
  --bucket module-dev-reports \
  --key reports/daily.txt \
  --query VersionId \
  --output text

Ele deve corresponder à mesma versão original. Leia o novo membro e o relatório independente de preview:

aws s3 \
  cp s3://module-dev-reports/reports/weekly.txt -
aws s3 \
  cp s3://module-preview-reports/reports/daily.txt -

Espere dev weekly report e o conteúdo inalterado preview daily report. A verificação em segundo plano compara as versões nativas da primeira gravação, em vez de aceitar bytes idênticos em objetos substitutos.

terraform -chdir=dev output
terraform -chdir=dev plan
terraform -chdir=preview plan

O mapa de saída de dev contém as duas chaves; preview continua tendo apenas daily. Os dois diretórios raiz devem convergir com No changes. Mantenha os armazenamentos em funcionamento disponíveis. Este módulo define uma interface e uma coleção de recursos; escolher chaves separadas para o backend remoto é uma decisão adicional de isolamento de ambientes, abordada posteriormente.

Consulte as orientações sobre composição de módulos da HashiCorp para usar entradas e saídas de módulos como limites de interface.

Resumo

Você definiu uma interface de módulo com tipos explícitos, retornou saídas úteis a dois diretórios raiz independentes e adicionou um membro estável de for_each sem substituir os relatórios originais. Uma coleção de recursos é diferente de um limite de estado de ambiente.