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ísticaPackerDockerfileAWS Image BuilderAnsible (imágenes)
MultiplataformaSí (cualquier nube + local)Solo DockerSolo AWSSí (con plugins)
Lenguaje de configuraciónHCLSintaxis DockerfileJSON/YAMLYAML
Caché por capasNo (reconstrucción completa)Sí (capas)ParcialNo
Velocidad de construcciónMinutosSegundos-minutosMinutosMinutos
Soporte de provisionersShell, Ansible, Chef, PuppetComandos RUNSSM/AWSTOENativo
Integración CI/CDExcelenteExcelenteSolo AWSBuena
Salida inmutableSí (snapshot)Sí (imagen)Sí (AMI)Depende
Curva de aprendizajeMediaBajaMediaMedia

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_filter coincide con varias AMIs, most_recent = true garantiza 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_timeout desde 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 file que copia a /opt/app/ fallará si el directorio no existe todavía — añade primero un provisioner shell para crearlo.

  • Permisos IAM para construcciones en AWS: Packer necesita ec2:RunInstances, ec2:CreateImage, ec2:DescribeImages y 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_mappings para aumentar el volumen raíz.

Solución de Problemas

ProblemaCausaSolución
”Timeout waiting for SSH”El security group bloquea SSH o la instancia tarda en arrancarVerifica que el SG permita el puerto 22 desde la IP del builder; aumenta ssh_timeout
”AccessDenied” al crear la AMIPolítica IAM sin permiso ec2:CreateImageAgrega los permisos EC2 y EBS necesarios al rol IAM
Los scripts del provisioner fallanEl script se ejecuta antes de que los paquetes se actualicenAñade apt-get update como primer paso; usa DEBIAN_FRONTEND=noninteractive
La construcción tiene éxito pero falta la AMIRegión o cuenta incorrectaVerifica region en el bloque source; usa aws ec2 describe-images para confirmar
La construcción de Packer es lentaNo hay construcciones paralelas configuradasUsa -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

Artículos Relacionados