Packer es una herramienta open-source de HashiCorp que automatiza la creación de imágenes de máquina para múltiples plataformas desde una única plantilla. En lugar de configurar manualmente un servidor, tomar un snapshot y esperar haber documentado cada paso, Packer codifica todo el proceso. Escribes una plantilla, ejecutas packer build, y obtienes imágenes idénticas para AWS, Azure, Docker y VMware — todo desde una sola definición.
Esta guía cubre la instalación de Packer, la sintaxis de plantillas HCL, builders, provisioners, construcciones multiplataforma e integración de Packer en pipelines CI/CD para entrega automatizada de imágenes.
Requisitos Previos
- Packer instalado (v1.9+)
- Una cuenta en al menos una plataforma destino (AWS, Azure, Docker o VirtualBox)
- AWS CLI configurado (si vas a construir AMIs)
- Conocimientos básicos de imágenes de máquina y aprovisionamiento de servidores
- Familiaridad con la sintaxis HCL (similar a Terraform)
Instalación de Packer
Instala desde el repositorio de HashiCorp para recibir actualizaciones 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 la instalación
packer version
Tu Primera Plantilla Packer
Packer utiliza plantillas en HCL (HashiCorp Configuration Language). Aquí tienes un ejemplo mínimo que construye una imagen 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"]
}
}
Para construirla:
# Inicializar los plugins
packer init docker-nginx.pkr.hcl
# Validar la plantilla
packer validate docker-nginx.pkr.hcl
# Construir la imagen
packer build docker-nginx.pkr.hcl
Construcción de AWS AMIs con Packer
El caso de uso más común de Packer es construir 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"
]
}
}
# Construir con variables personalizadas
packer build -var "aws_region=eu-west-1" -var "app_version=2.1.0" aws-webserver.pkr.hcl
Tipos de Provisioners
Packer soporta múltiples provisioners que se ejecutan dentro de la instancia temporal de construcción:
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 File
provisioner "file" {
source = "app/dist/"
destination = "/opt/app/"
}
Escenario real: Tu empresa opera 50 instancias EC2 detrás de un balanceador de carga. Cada vez que despliegas, construyes una nueva AMI con Packer que contiene el código de aplicación más reciente, la configuración de Nginx y los parches de seguridad. Terraform realiza entonces una actualización gradual: lanza instancias nuevas con la AMI fresca y drena las antiguas. Si la nueva imagen presenta problemas, vuelves a la AMI anterior en cuestión de minutos. Sin SSH a servidores, sin configuration drift, sin servidores snowflake.
Construcciones Multiplataforma
Construye imágenes para múltiples plataformas desde una sola plantilla:
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"
# ... configuración adicional de VirtualBox
}
build {
sources = [
"source.amazon-ebs.aws",
"source.docker.container",
]
provisioner "shell" {
inline = [
"sudo apt-get update",
"sudo apt-get install -y nginx",
]
}
}
Ejecuta packer build . y Packer construye ambas imágenes en paralelo.
Packer vs Alternativas
| Característica | Packer | Dockerfile | AWS Image Builder | Ansible (imágenes) |
|---|---|---|---|---|
| Multiplataforma | Sí (cualquier nube + local) | Solo Docker | Solo AWS | Sí (con plugins) |
| Lenguaje de configuración | HCL | Sintaxis Dockerfile | JSON/YAML | YAML |
| Caché por capas | No (reconstrucción completa) | Sí (capas) | Parcial | No |
| Velocidad de construcción | Minutos | Segundos-minutos | Minutos | Minutos |
| Soporte de provisioners | Shell, Ansible, Chef, Puppet | Comandos RUN | SSM/AWSTOE | Nativo |
| Integración CI/CD | Excelente | Excelente | Solo AWS | Buena |
| Salida inmutable | Sí (snapshot) | Sí (imagen) | Sí (AMI) | Depende |
| Curva de aprendizaje | Media | Baja | Media | Media |
Cuándo elegir Packer: Entornos multicloud, despliegues basados en VM, pipelines de imágenes golden, o cuando necesitas la misma imagen en AWS y VMware de forma simultánea.
Errores Comunes y Casos Especiales
-
Filtros de AMI de origen desactualizados: Si tu
source_ami_filtercoincide con varias AMIs,most_recent = truegarantiza que obtengas la más reciente. Sin esta opción, Packer elige arbitrariamente y tus construcciones se vuelven no deterministas. -
Timeouts en la construcción: Packer espera conectividad SSH después de lanzar la instancia de construcción. Las regiones de nube lentas o los security groups restrictivos causan timeouts. Aumenta
ssh_timeoutdesde el valor predeterminado de 5 minutos si es necesario. -
El orden de los provisioners importa: Los provisioners se ejecutan en el orden en que aparecen en la plantilla. Un provisioner
fileque copia a/opt/app/fallará si el directorio no existe todavía — añade primero un provisionershellpara crearlo. -
Permisos IAM para construcciones en AWS: Packer necesita
ec2:RunInstances,ec2:CreateImage,ec2:DescribeImagesy varios más. Usa la política IAM mínima de Packer en lugar de otorgarle acceso de administrador completo. -
Desregistro de AMIs antiguas: Packer crea nuevas AMIs pero nunca elimina las antiguas. Sin limpieza, acumularás cientos de AMIs sin usar. Utiliza una lifecycle policy o un script programado para desregistrar imágenes más antiguas que N días.
-
Espacio en disco durante las construcciones: Las instancias temporales de construcción usan el tamaño de volumen raíz predeterminado. Si tu aprovisionamiento instala muchos paquetes, el disco se llena. Agrega
launch_block_device_mappingspara aumentar el volumen raíz.
Solución de Problemas
| Problema | Causa | Solución |
|---|---|---|
| ”Timeout waiting for SSH” | El security group bloquea SSH o la instancia tarda en arrancar | Verifica que el SG permita el puerto 22 desde la IP del builder; aumenta ssh_timeout |
| ”AccessDenied” al crear la AMI | Política IAM sin permiso ec2:CreateImage | Agrega los permisos EC2 y EBS necesarios al rol IAM |
| Los scripts del provisioner fallan | El script se ejecuta antes de que los paquetes se actualicen | Añade apt-get update como primer paso; usa DEBIAN_FRONTEND=noninteractive |
| La construcción tiene éxito pero falta la AMI | Región o cuenta incorrecta | Verifica region en el bloque source; usa aws ec2 describe-images para confirmar |
| La construcción de Packer es lenta | No hay construcciones paralelas configuradas | Usa -parallel-builds=N o bloques source separados para paralelismo |
Resumen
- Packer automatiza la creación de imágenes de máquina desde código, eliminando la configuración manual de servidores y garantizando construcciones reproducibles
- Las plantillas HCL definen sources (dónde construir), provisioners (qué instalar) y post-processors (qué hacer con la salida)
- Las construcciones multiplataforma producen imágenes idénticas para AWS, Docker y VMware desde una sola plantilla
- El provisioner Ansible integra la gestión de configuración existente en las construcciones de Packer para configuraciones complejas
- La integración CI/CD permite construcciones automáticas de imágenes en cada cambio de infraestructura, creando un pipeline de despliegue inmutable
- Úsalo junto a Terraform para un flujo completo — Packer construye la imagen, Terraform la despliega