Automatizando a Infraestrutura com Terraform e Kubernetes

Automatizando a Infraestrutura com Terraform e Kubernetes
Resumo: Este artigo mostra como combinar Terraform e Kubernetes para criar ambientes de produção e teste totalmente declarativos. Você verá a estrutura de um repositório GitOps, exemplos de código Terraform, manifests Kubernetes e um pequeno chart Helm. Ao final, será possível reproduzir todo o fluxo em poucos minutos.
Introdução
A prática de Infraestrutura como Código (IaC) tem mudado a forma como equipes de tecnologia entregam valor. Em vez de configurar servidores manualmente, declaramos recursos em arquivos versionados, permitindo:
Reprodutibilidade – o mesmo código gera o mesmo ambiente em diferentes regiões ou contas. Auditoria – cada mudança fica registrada no histórico do Git. Escalabilidade – recursos podem ser criados ou destruídos em massa com poucos comandos.
Dois pilares dessa revolução são Terraform (para provisionamento de recursos de nuvem) e Kubernetes (para orquestração de containers). Quando usados em conjunto, eles permitem que a camada de infraestrutura (máquinas virtuais, redes, bancos) e a camada de plataforma (pods, serviços, ingressos) sejam geridas de forma unificada.
Neste artigo vamos:
Dica: Embora o exemplo use a AWS, o mesmo conceito se aplica a GCP, Azure ou provedores on‑premises.
1. Estrutura de um repositório GitOps
Organizar o código em diretórios claros facilita a colaboração e a revisão de mudanças. A seguir, um modelo de repositório:
infra/
├── terraform/
│ ├── modules/
│ │ └── eks-cluster/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ └── env/
│ ├── dev/
│ │ ├── backend.tf
│ │ └── main.tf
│ └── prod/
│ ├── backend.tf
│ └── main.tf
apps/
├── helm/
│ └── hello-world/
│ ├── Chart.yaml
│ ├── values.yaml
│ └── templates/
│ ├── deployment.yaml
│ └── service.yaml
│
.github/
└── workflows/
└── deploy.yml
infra/terraform – contém todo o código Terraform, incluindo módulos reutilizáveis. apps/helm – charts Helm que descrevem a aplicação a ser executada no cluster. .github/workflows – workflow de automação que roda o Terraform e o Helm.
Essa separação deixa claro onde cada equipe deve atuar: infra cuida da nuvem, apps cuida das workloads.
2. Provisionando o cluster Kubernetes com Terraform
Vamos criar um módulo simples que provisiona um Amazon EKS (Elastic Kubernetes Service). O módulo pode ser adaptado para outros provedores.
2.1 variables.tf
variable "cluster_name" {
description = "Nome do cluster EKS"
type = string
}
variable "region" {
description = "Região da AWS"
type = string
default = "us-east-1"
}
variable "node_instance_type" {
description = "Tipo de instância para os nós de trabalho"
type = string
default = "t3.medium"
}
2.2 main.tf
provider "aws" {
region = var.region
}
resource "aws_eks_cluster" "this" {
name = var.cluster_name
role_arn = aws_iam_role.eks_cluster.arn
vpc_config {
subnet_ids = aws_subnet.private[].id
}
depends_on = [aws_iam_role_policy_attachment.eks_cluster_AmazonEKSClusterPolicy]
}
resource "aws_eks_node_group" "workers" {
cluster_name = aws_eks_cluster.this.name
node_group_name = "${var.cluster_name}-workers"
node_role_arn = aws_iam_role.eks_node.arn
subnet_ids = aws_subnet.private[].id
scaling_config {
desired_size = 2
max_size = 4
min_size = 1
}
instance_types = [var.node_instance_type]
}
Observação: O exemplo omite recursos auxiliares (VPC, sub‑nets, IAM). Em projetos reais, recomenda‑se usar módulos oficiais da comunidade, como
terraform-aws-modules/vpc/aws.
2.3 outputs.tf
output "cluster_endpoint" {
description = "Endpoint do cluster EKS"
value = aws_eks_cluster.this.endpoint
}
output "kubeconfig_certificate_authority_data" {
description = "CA data para gerar kubeconfig"
value = aws_eks_cluster.this.certificate_authority[0].data
}
2.4 Executando o Terraform
# Inicializa o backend (ex.: S3 + DynamoDB para lock)
terraform init -backend-config="bucket=my-terraform-state" \
-backend-config="key=eks/prod/terraform.tfstate" \
-backend-config="region=us-east-1"
Planeja a criação
terraform plan -var="cluster_name=prod-eks"
Aplica
terraform apply -auto-approve -var="cluster_name=prod-eks"
Ao final, o output cluster_endpoint pode ser usado para gerar um kubeconfig:
aws eks update-kubeconfig --name prod-eks --region us-east-1
3. Deploy de uma aplicação com Helm
Com o cluster pronto, vamos colocar em execução um Hello World escrito em Go. Usaremos um chart Helm para tornar o processo declarativo.
3.1 Chart.yaml
apiVersion: v2
name: hello-world
description: Aplicação mínima que responde "Hello, World!" via HTTP
type: application
version: 0.1.0
appVersion: "1.0"
3.2 values.yaml
replicaCount: 2
image:
repository: ghcr.io/example/hello-world
tag: "1.0.0"
pullPolicy: IfNotPresent
service:
type: LoadBalancer
port: 80
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 50m
memory: 64Mi
3.3 templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "hello-world.fullname" . }}
labels:
{{- include "hello-world.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "hello-world.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "hello-world.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports:
- containerPort: 8080
resources:
{{- toYaml .Values.resources | nindent 12 }}
3.4 templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: {{ include "hello-world.fullname" . }}
labels:
{{- include "hello-world.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: 8080
selector:
{{- include "hello-world.selectorLabels" . | nindent 4 }}
3.5 Instalando o chart
helm repo add my-charts https://example.com/charts
helm upgrade --install hello-world ./apps/helm/hello-world \
--namespace production --create-namespace
O comando cria um Deployment com duas réplicas e um Service do tipo LoadBalancer. O provedor de nuvem provisiona automaticamente um IP público que pode ser testado:
curl http://<load-balancer-ip>
=> Hello, World!
4. Automatizando tudo com um workflow de automação
Para garantir que a infraestrutura e a aplicação sejam mantidas sincronizadas, criamos um workflow que:
infra/terraform.4.1 Arquivo .github/workflows/deploy.yml
```yaml name: Deploy Infra + App
on: push: paths: - 'infra/terraform/' - 'apps/helm/'
jobs: terraform: runs-on: ubuntu-latest defaults: run: working-directory: infra/terraform steps: - name: Checkout repository uses: actions/checkout@v3
- name: Setup Terraform uses: hashicorp/setup-terraform@v2 with: terraform_version: "1.5.0"
- name: Terraform Init & Apply env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} run: | terraform init terraform apply -auto-approve -var="cluster_name=prod-eks"
helm: needs: terraform runs-on: ubuntu-latest steps: -


