Módulos no Terraform
1. Introdução aos Módulos no Terraform
Módulos no Terraform são contêineres lógicos para recursos relacionados, que permitem agrupar e reutilizar configurações de infraestrutura como código. Em pipelines DevOps, módulos são essenciais para criar ambientes consistentes, reduzir duplicação e facilitar a manutenção de infraestrutura complexa.
Os principais benefícios dos módulos incluem:
- Reuso: Um módulo bem projetado pode ser utilizado em múltiplos ambientes (dev, staging, production)
- Encapsulamento: Detalhes internos ficam ocultos, expondo apenas interfaces claras via variáveis e outputs
- Versionamento: Módulos podem ser versionados e distribuídos, garantindo rastreabilidade das mudanças
No Terraform, existem dois tipos principais de módulos:
- Módulo root: O diretório raiz onde terraform apply é executado
- Módulos filhos: Módulos chamados pelo módulo root ou por outros módulos
2. Estrutura de um Módulo Terraform
Um módulo Terraform segue uma estrutura de diretórios padronizada:
modules/
k8s-cluster/
main.tf # Recursos principais do módulo
variables.tf # Declaração de variáveis de entrada
outputs.tf # Valores expostos para outros módulos
README.md # Documentação do módulo
Exemplo de módulo simples para cluster Kubernetes
modules/k8s-cluster/variables.tf:
variable "cluster_name" {
description = "Nome do cluster Kubernetes"
type = string
}
variable "node_count" {
description = "Número de nós no cluster"
type = number
default = 3
}
variable "node_instance_type" {
description = "Tipo de instância para os nós"
type = string
default = "t3.medium"
}
modules/k8s-cluster/main.tf:
resource "aws_eks_cluster" "main" {
name = var.cluster_name
role_arn = aws_iam_role.cluster.arn
vpc_config {
subnet_ids = var.subnet_ids
}
}
resource "aws_eks_node_group" "main" {
cluster_name = aws_eks_cluster.main.name
node_group_name = "${var.cluster_name}-nodes"
instance_types = [var.node_instance_type]
node_role_arn = aws_iam_role.node.arn
scaling_config {
desired_size = var.node_count
min_size = 1
max_size = 5
}
subnet_ids = var.subnet_ids
}
modules/k8s-cluster/outputs.tf:
output "cluster_endpoint" {
description = "Endpoint do cluster Kubernetes"
value = aws_eks_cluster.main.endpoint
}
output "cluster_certificate_authority" {
description = "Certificado CA do cluster"
value = aws_eks_cluster.main.certificate_authority[0].data
}
output "node_group_arn" {
description = "ARN do grupo de nós"
value = aws_eks_node_group.main.arn
}
3. Entrada e Saída de Dados em Módulos
Variáveis de entrada com validações
variable "environment" {
description = "Ambiente de deployment"
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "O ambiente deve ser dev, staging ou prod."
}
}
variable "tags" {
description = "Tags para todos os recursos"
type = map(string)
default = {
ManagedBy = "Terraform"
}
}
Outputs para comunicação entre módulos
output "vpc_id" {
description = "ID da VPC criada"
value = aws_vpc.main.id
}
output "private_subnet_ids" {
description = "IDs das subnets privadas"
value = aws_subnet.private[*].id
}
Uso de locals para lógica interna
locals {
name_prefix = "${var.project}-${var.environment}"
common_tags = merge(var.tags, {
Environment = var.environment
Project = var.project
})
}
4. Chamando Módulos no Código Principal
Sintaxe do bloco module
module "vpc" {
source = "./modules/vpc"
vpc_cidr = "10.0.0.0/16"
environment = var.environment
project = var.project
tags = var.tags
}
module "eks_cluster" {
source = "./modules/k8s-cluster"
cluster_name = "${var.project}-${var.environment}"
node_count = var.environment == "prod" ? 5 : 3
node_instance_type = var.environment == "prod" ? "t3.large" : "t3.medium"
subnet_ids = module.vpc.private_subnet_ids
}
Caminhos remotos (Terraform Registry)
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.0.0"
name = "${var.project}-vpc"
cidr = "10.0.0.0/16"
azs = ["us-east-1a", "us-east-1b"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
}
5. Versionamento e Registro de Módulos
Controle de versão com constraints
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 19.0" # Qualquer versão 19.x.x
# ou
# version = ">= 19.0, < 20.0"
}
Estratégias de versionamento semântico
Para módulos internos, recomenda-se:
- Major: Mudanças que quebram compatibilidade
- Minor: Novas funcionalidades compatíveis
- Patch: Correções de bugs
# Publicação no Terraform Registry privado
terraform login registry.internal.com
terraform registry publish modules/network:v1.2.0
6. Módulos no Contexto de Docker e Kubernetes
Módulo para criação de imagens Docker
modules/docker-build/variables.tf:
variable "image_name" {
description = "Nome da imagem Docker"
type = string
}
variable "dockerfile_path" {
description = "Caminho para o Dockerfile"
type = string
}
variable "build_args" {
description = "Argumentos de build"
type = map(string)
default = {}
}
modules/docker-build/main.tf:
resource "docker_image" "app" {
name = var.image_name
build {
path = var.dockerfile_path
build_args = var.build_args
}
}
resource "docker_registry_image" "app" {
name = docker_image.app.name
keep_remotely = true
}
Módulo para deployment no Kubernetes
modules/k8s-deployment/main.tf:
resource "kubernetes_deployment" "app" {
metadata {
name = var.app_name
namespace = var.namespace
labels = var.labels
}
spec {
replicas = var.replicas
selector {
match_labels = var.match_labels
}
template {
metadata {
labels = var.match_labels
}
spec {
container {
image = var.image
name = var.app_name
image_pull_policy = "Always"
port {
container_port = var.container_port
}
resources {
limits = {
cpu = var.cpu_limit
memory = var.memory_limit
}
}
}
}
}
}
}
resource "kubernetes_service" "app" {
metadata {
name = var.app_name
namespace = var.namespace
}
spec {
selector = var.match_labels
port {
port = var.service_port
target_port = var.container_port
}
type = var.service_type
}
}
Exemplo integrado: Docker build + deploy no K8s
module "docker_build" {
source = "./modules/docker-build"
image_name = "myapp:${var.version}"
dockerfile_path = abspath("${path.root}/app")
build_args = {
VERSION = var.version
}
}
module "k8s_deploy" {
source = "./modules/k8s-deployment"
app_name = "myapp"
namespace = var.namespace
image = module.docker_build.image_uri
replicas = var.replicas
container_port = 8080
service_port = 80
service_type = "ClusterIP"
match_labels = {
app = "myapp"
}
labels = {
app = "myapp"
version = var.version
}
}
7. Boas Práticas e Padrões Avançados
Modularização por responsabilidade
Organize módulos por camadas de infraestrutura:
infrastructure/
modules/
network/ # VPC, subnets, gateways
compute/ # EC2, ECS, EKS
database/ # RDS, DynamoDB
storage/ # S3, EFS
monitoring/ # CloudWatch, Prometheus
ci-cd/ # Jenkins, GitLab Runner
Documentação automática com terraform-docs
Adicione ao seu pipeline CI/CD:
# .github/workflows/terraform-docs.yml
name: Generate Terraform Docs
on:
pull_request:
paths:
- 'modules/**/*.tf'
jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: terraform-docs/gh-actions@v1
with:
working-dir: modules
output-file: README.md
output-method: replace
Testes de módulos com Terratest
// test/k8s_module_test.go
package test
import (
"testing"
"github.com/gruntwork-io/terratest/modules/terraform"
)
func TestK8sModule(t *testing.T) {
terraformOptions := &terraform.Options{
TerraformDir: "../modules/k8s-cluster",
Vars: map[string]interface{}{
"cluster_name": "test-cluster",
"node_count": 2,
},
}
defer terraform.Destroy(t, terraformOptions)
terraform.InitAndApply(t, terraformOptions)
endpoint := terraform.Output(t, terraformOptions, "cluster_endpoint")
if endpoint == "" {
t.Errorf("Expected non-empty endpoint")
}
}
Integração contínua em pipelines CI/CD
# .gitlab-ci.yml
stages:
- validate
- plan
- deploy
validate:
stage: validate
script:
- terraform fmt -check -recursive modules/
- terraform validate
plan:
stage: plan
script:
- terraform plan -out plan.tfplan
artifacts:
paths:
- plan.tfplan
deploy:
stage: deploy
script:
- terraform apply plan.tfplan
only:
- main
Referências
- Terraform Modules Documentation (Official) — Documentação oficial sobre a sintaxe e estrutura de módulos no Terraform.
- Terraform Registry - AWS VPC Module — Módulo público para criação de VPCs na AWS, referência para boas práticas de modularização.
- Terraform Modules Best Practices — Guia completo de boas práticas para criação e gerenciamento de módulos Terraform.
- Terratest - Testing Infrastructure Code — Framework para testes de módulos Terraform, incluindo exemplos para Kubernetes e Docker.
- terraform-docs - Generate Documentation — Ferramenta para gerar documentação automática de módulos Terraform a partir do código.
- HashiCorp Learn - Module Creation — Tutorial oficial da HashiCorp para criação de módulos reutilizáveis.
- Kubernetes Terraform Provider — Documentação do provider Kubernetes para Terraform, essencial para módulos de deploy no K8s.
- Docker Terraform Provider — Documentação do provider Docker para construção e gerenciamento de imagens via Terraform.