Exemplo prático de um serviço web simples na AWS provisionado com Terraform, com promoção do ambiente de desenvolvimento para produção usando workspaces.
Estrutura do projeto
infra/
├── backend.tf
├── main.tf
├── variables.tf
├── outputs.tf
├── dev.tfvars
└── prod.tfvars
Backend remoto (S3 + DynamoDB)
# backend.tf
terraform {
backend "s3" {
bucket = "meu-projeto-tfstate"
key = "app/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.regiao
}Variáveis
# variables.tf
variable "regiao" {
type = string
default = "us-east-1"
}
variable "ambiente" {
type = string
}
variable "instance_type" {
type = string
}
variable "projeto" {
type = string
default = "meu-projeto"
}# dev.tfvars
ambiente = "dev"
instance_type = "t3.micro"
# prod.tfvars
ambiente = "prod"
instance_type = "t3.medium"Infraestrutura: EC2 com NGINX
# main.tf
locals {
nome = "${var.projeto}-${var.ambiente}"
tags = {
Projeto = var.projeto
Ambiente = var.ambiente
ManagedBy = "terraform"
}
}
resource "aws_security_group" "app" {
name = "${local.nome}-sg"
description = "SG da aplicacao ${local.nome}"
tags = local.tags
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["al2023-ami-*-x86_64"]
}
}
resource "aws_instance" "app" {
ami = data.aws_ami.amazon_linux.id
instance_type = var.instance_type
vpc_security_group_ids = [aws_security_group.app.id]
user_data = <<-EOF
#!/bin/bash
dnf install -y nginx
systemctl enable nginx
systemctl start nginx
echo "<h1>${local.nome}</h1>" > /usr/share/nginx/html/index.html
EOF
tags = merge(local.tags, { Name = local.nome })
}# outputs.tf
output "instance_ip" {
value = aws_instance.app.public_ip
}
output "url" {
value = "http://${aws_instance.app.public_ip}"
}Fluxo dev → prod
# 1. Subir ambiente de dev
terraform workspace new dev
terraform workspace select dev
terraform init
terraform plan -var-file="dev.tfvars"
terraform apply -var-file="dev.tfvars"
# Valida no IP exibido pelo output "url"...
# 2. Promover para prod (mesmo código, tfvars diferente)
terraform workspace new prod
terraform workspace select prod
terraform plan -var-file="prod.tfvars"
terraform apply -var-file="prod.tfvars"
# 3. Destruir dev após validação
terraform workspace select dev
terraform destroy -var-file="dev.tfvars"Cada workspace mantém um state independente no mesmo backend S3, evitando que recursos de dev e prod se misturem. O key no backend fica como env:/dev/app/terraform.tfstate e env:/prod/app/terraform.tfstate automaticamente.
Ver também: terraform-state | terraform-variaveis | terraform-providers | terraform