O Packer é uma ferramenta open-source da HashiCorp que automatiza a criação de imagens de máquina para múltiplas plataformas a partir de um único template. Em vez de configurar um servidor manualmente, tirar um snapshot e torcer para ter documentado cada etapa, o Packer codifica todo o processo. Você escreve um template, executa packer build, e obtém imagens idênticas para AWS, Azure, Docker e VMware — tudo a partir de uma única definição.
Este guia cobre a instalação do Packer, a sintaxe de templates HCL, builders, provisioners, builds multi-plataforma e a integração do Packer em pipelines de CI/CD para entrega automatizada de imagens.
Pré-requisitos
- Packer instalado (v1.9+)
- Uma conta em pelo menos uma plataforma alvo (AWS, Azure, Docker ou VirtualBox)
- AWS CLI configurado (caso esteja construindo AMIs)
- Conhecimento básico de imagens de máquina e provisionamento de servidores
- Familiaridade com a sintaxe HCL (similar ao Terraform)
Instalando o Packer
Instale a partir do repositório da HashiCorp para receber atualizações automáticas:
# Ubuntu/Debian
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install packer
# macOS
brew install packer
# Verificar instalação
packer version
Seu Primeiro Template Packer
O Packer usa templates HCL (HashiCorp Configuration Language). Veja um exemplo mínimo que constrói uma imagem Docker:
# docker-nginx.pkr.hcl
packer {
required_plugins {
docker = {
version = ">= 1.0.0"
source = "github.com/hashicorp/docker"
}
}
}
source "docker" "nginx" {
image = "ubuntu:22.04"
commit = true
}
build {
name = "custom-nginx"
sources = ["source.docker.nginx"]
provisioner "shell" {
inline = [
"apt-get update",
"apt-get install -y nginx curl",
"rm -rf /var/lib/apt/lists/*"
]
}
post-processor "docker-tag" {
repository = "myorg/custom-nginx"
tags = ["latest", "1.0"]
}
}
Execute o build:
# Inicializar plugins
packer init docker-nginx.pkr.hcl
# Validar o template
packer validate docker-nginx.pkr.hcl
# Construir a imagem
packer build docker-nginx.pkr.hcl
Criando AWS AMIs com o Packer
O caso de uso mais comum do Packer é a criação de Amazon Machine Images (AMIs):
# aws-webserver.pkr.hcl
packer {
required_plugins {
amazon = {
version = ">= 1.2.0"
source = "github.com/hashicorp/amazon"
}
}
}
variable "aws_region" {
type = string
default = "us-east-1"
}
variable "app_version" {
type = string
default = "1.0.0"
}
source "amazon-ebs" "webserver" {
ami_name = "webserver-{{timestamp}}"
instance_type = "t3.micro"
region = var.aws_region
source_ami_filter {
filters = {
name = "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"
root-device-type = "ebs"
virtualization-type = "hvm"
}
owners = ["099720109477"] # Canonical
most_recent = true
}
ssh_username = "ubuntu"
tags = {
Name = "WebServer"
Version = var.app_version
Builder = "Packer"
Environment = "production"
}
}
build {
sources = ["source.amazon-ebs.webserver"]
provisioner "shell" {
inline = [
"sudo apt-get update",
"sudo apt-get install -y nginx nodejs npm certbot",
"sudo systemctl enable nginx"
]
}
provisioner "file" {
source = "config/nginx.conf"
destination = "/tmp/nginx.conf"
}
provisioner "shell" {
inline = [
"sudo cp /tmp/nginx.conf /etc/nginx/nginx.conf",
"sudo nginx -t",
"sudo systemctl restart nginx"
]
}
}
# Build com sobrescrita de variáveis
packer build -var "aws_region=eu-west-1" -var "app_version=2.1.0" aws-webserver.pkr.hcl
Tipos de Provisioners
O Packer suporta múltiplos provisioners que executam dentro da instância de build temporária:
Provisioner Shell
provisioner "shell" {
scripts = [
"scripts/base-setup.sh",
"scripts/install-app.sh",
"scripts/harden.sh"
]
environment_vars = [
"APP_ENV=production",
"DEBIAN_FRONTEND=noninteractive"
]
}
Provisioner Ansible
provisioner "ansible" {
playbook_file = "ansible/playbook.yml"
extra_arguments = [
"--extra-vars", "app_version=${var.app_version}",
"--tags", "setup,deploy"
]
ansible_env_vars = [
"ANSIBLE_HOST_KEY_CHECKING=False"
]
}
Provisioner de Arquivo
provisioner "file" {
source = "app/dist/"
destination = "/opt/app/"
}
Cenário real: Sua empresa opera 50 instâncias EC2 atrás de um load balancer. A cada deploy, você constrói uma nova AMI com o Packer contendo o código mais recente da aplicação, a configuração do Nginx e os patches de segurança. O Terraform então realiza uma atualização gradual — lançando novas instâncias com a AMI nova e drenando as antigas. Se a nova imagem apresentar problemas, você reverte para a AMI anterior em minutos. Sem SSH em servidores, sem configuration drift, sem servidores snowflake.
Builds Multi-Plataforma
Crie imagens para múltiplas plataformas a partir de um único template:
source "amazon-ebs" "aws" {
ami_name = "myapp-aws-{{timestamp}}"
instance_type = "t3.micro"
region = "us-east-1"
source_ami_filter {
filters = { name = "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*" }
owners = ["099720109477"]
most_recent = true
}
ssh_username = "ubuntu"
}
source "docker" "container" {
image = "ubuntu:22.04"
commit = true
}
source "virtualbox-iso" "local" {
iso_url = "https://releases.ubuntu.com/22.04/ubuntu-22.04.3-live-server-amd64.iso"
iso_checksum = "sha256:abcdef..."
ssh_username = "vagrant"
ssh_password = "vagrant"
# ... configuração adicional do VirtualBox
}
build {
sources = [
"source.amazon-ebs.aws",
"source.docker.container",
]
provisioner "shell" {
inline = [
"sudo apt-get update",
"sudo apt-get install -y nginx",
]
}
}
Execute packer build . e o Packer constrói ambas as imagens em paralelo.
Comparação: Packer vs Alternativas
| Funcionalidade | Packer | Dockerfile | AWS Image Builder | Ansible (imagens) |
|---|---|---|---|---|
| Multi-plataforma | Sim (qualquer nuvem + local) | Apenas Docker | Apenas AWS | Sim (com plugins) |
| Linguagem de config | HCL | Sintaxe Dockerfile | JSON/YAML | YAML |
| Cache de camadas | Não (rebuild completo) | Sim (camadas) | Parcial | Não |
| Velocidade de build | Minutos | Segundos a minutos | Minutos | Minutos |
| Suporte a provisioners | Shell, Ansible, Chef, Puppet | Comandos RUN | SSM/AWSTOE | Nativo |
| Integração CI/CD | Excelente | Excelente | Apenas AWS | Boa |
| Saída imutável | Sim (snapshot) | Sim (imagem) | Sim (AMI) | Depende |
| Curva de aprendizado | Média | Baixa | Média | Média |
Quando escolher o Packer: Ambientes multi-cloud, deployments baseados em VMs, pipelines de golden image, ou quando você precisa da mesma imagem no AWS e no VMware simultaneamente.
Armadilhas e Casos Especiais
-
Filtros de AMI desatualizados: Se o seu
source_ami_filtercorresponder a múltiplas AMIs,most_recent = truegarante que você obtenha a mais recente. Sem isso, o Packer escolhe arbitrariamente e seus builds se tornam não determinísticos. -
Timeouts de build: O Packer aguarda a conectividade SSH após lançar a instância de build. Regiões de nuvem lentas ou security groups restritivos causam timeouts. Aumente o
ssh_timeoutem relação ao padrão de 5 minutos se necessário. -
A ordem dos provisioners importa: Os provisioners executam na ordem em que aparecem no template. Um provisioner
fileque copia para/opt/app/vai falhar se o diretório ainda não existir — adicione um provisionershellantes para criá-lo. -
Permissões IAM para builds na AWS: O Packer precisa de
ec2:RunInstances,ec2:CreateImage,ec2:DescribeImagese várias outras. Use a política IAM mínima para o Packer em vez de conceder acesso de administrador completo. -
Desregistrando AMIs antigas: O Packer cria novas AMIs, mas nunca exclui as antigas. Sem uma política de limpeza, você acumula centenas de AMIs não utilizadas. Use uma lifecycle policy ou um script agendado para desregistrar imagens com mais de N dias.
-
Espaço em disco durante builds: As instâncias de build temporárias usam o tamanho padrão do volume raiz. Se o provisionamento instalar muitos pacotes, o disco pode encher. Adicione
launch_block_device_mappingspara aumentar o volume raiz.
Solução de Problemas
| Problema | Causa | Solução |
|---|---|---|
| ”Timeout waiting for SSH” | Security group bloqueando SSH ou instância lenta para iniciar | Verifique se o SG permite a porta 22 do IP do builder; aumente o ssh_timeout |
| ”AccessDenied” durante criação de AMI | Política IAM sem ec2:CreateImage | Adicione as permissões EC2 e EBS necessárias à role IAM |
| Scripts do provisioner falham | Script executa antes da atualização de pacotes | Adicione apt-get update como primeiro passo; use DEBIAN_FRONTEND=noninteractive |
| Build bem-sucedido, mas AMI não aparece | Região ou conta errada | Verifique region no bloco source; use aws ec2 describe-images para confirmar |
| Build do Packer lento | Sem builds paralelos configurados | Use -parallel-builds=N ou blocos source separados para paralelismo |
Resumo
- O Packer automatiza a criação de imagens de máquina a partir de código, eliminando a configuração manual de servidores e garantindo builds reproduzíveis
- Templates HCL definem sources (onde construir), provisioners (o que instalar) e post-processors (o que fazer com o resultado)
- Builds multi-plataforma produzem imagens idênticas para AWS, Docker e VMware a partir de um único template
- O provisioner Ansible integra o gerenciamento de configuração existente aos builds do Packer para setups complexos
- A integração com CI/CD permite builds automáticos de imagens a cada mudança de infraestrutura, criando um pipeline de deploy imutável
- Use em conjunto com o Terraform para um fluxo completo — o Packer constrói a imagem, o Terraform a implanta