Packer ist ein Open-Source-Tool von HashiCorp, das die Erstellung von Machine Images für mehrere Plattformen aus einem einzigen Quell-Template automatisiert. Anstatt einen Server manuell zu konfigurieren, einen Snapshot zu erstellen und zu hoffen, dass man jeden Schritt dokumentiert hat, codiert Packer den gesamten Prozess. Man schreibt ein Template, führt packer build aus und erhält identische Images für AWS, Azure, Docker und VMware — alles aus einer einzigen Definition.
Dieser Leitfaden behandelt die Installation von Packer, die HCL-Template-Syntax, Builder, Provisioner, Multi-Plattform-Builds und die Integration von Packer in CI/CD-Pipelines für automatisierte Image-Auslieferung.
Voraussetzungen
- Packer installiert (v1.9+)
- Ein Konto bei mindestens einer Zielplattform (AWS, Azure, Docker oder VirtualBox)
- AWS CLI konfiguriert (beim Bauen von AMIs)
- Grundlegendes Verständnis von Machine Images und Server-Provisionierung
- Vertrautheit mit der HCL-Syntax (ähnlich wie Terraform)
Packer installieren
Installation aus dem HashiCorp-Repository für automatische Updates:
# 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
# Installation überprüfen
packer version
Das erste Packer-Template
Packer verwendet HCL (HashiCorp Configuration Language) als Template-Sprache. Hier ein minimales Beispiel, das ein Docker-Image baut:
# 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"]
}
}
Build starten:
# Plugins initialisieren
packer init docker-nginx.pkr.hcl
# Template validieren
packer validate docker-nginx.pkr.hcl
# Image bauen
packer build docker-nginx.pkr.hcl
AWS AMIs mit Packer bauen
Der häufigste Anwendungsfall für Packer ist das Erstellen von 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 mit variablen Überschreibungen
packer build -var "aws_region=eu-west-1" -var "app_version=2.1.0" aws-webserver.pkr.hcl
Provisioner-Typen
Packer unterstützt mehrere Provisioner, die innerhalb der temporären Build-Instanz ausgeführt werden:
Shell-Provisioner
provisioner "shell" {
scripts = [
"scripts/base-setup.sh",
"scripts/install-app.sh",
"scripts/harden.sh"
]
environment_vars = [
"APP_ENV=production",
"DEBIAN_FRONTEND=noninteractive"
]
}
Ansible-Provisioner
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"
]
}
File-Provisioner
provisioner "file" {
source = "app/dist/"
destination = "/opt/app/"
}
Praxisbeispiel: Das Unternehmen betreibt 50 EC2-Instanzen hinter einem Load Balancer. Bei jedem Deployment wird mit Packer ein neues AMI gebaut, das den aktuellen Anwendungscode, die Nginx-Konfiguration und Sicherheits-Patches enthält. Terraform führt anschließend ein Rolling Update durch — neue Instanzen mit dem frischen AMI werden gestartet, alte werden abgebaut. Falls das neue Image Probleme hat, ist ein Rollback auf das vorherige AMI in Minuten erledigt. Kein manuelles SSH auf Server, kein Configuration Drift, keine Snowflake-Server.
Multi-Plattform-Builds
Images für mehrere Plattformen aus einem einzigen Template bauen:
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"
# ... weitere VirtualBox-Konfiguration
}
build {
sources = [
"source.amazon-ebs.aws",
"source.docker.container",
]
provisioner "shell" {
inline = [
"sudo apt-get update",
"sudo apt-get install -y nginx",
]
}
}
Mit packer build . baut Packer beide Images parallel.
Packer im Vergleich zu Alternativen
| Merkmal | Packer | Dockerfile | AWS Image Builder | Ansible (Images) |
|---|---|---|---|---|
| Multi-Plattform | Ja (jede Cloud + lokal) | Nur Docker | Nur AWS | Ja (mit Plugins) |
| Konfigurationssprache | HCL | Dockerfile-Syntax | JSON/YAML | YAML |
| Layer-Caching | Nein (vollständiger Rebuild) | Ja (Layer) | Teilweise | Nein |
| Build-Geschwindigkeit | Minuten | Sekunden–Minuten | Minuten | Minuten |
| Provisioner-Unterstützung | Shell, Ansible, Chef, Puppet | RUN-Befehle | SSM/AWSTOE | Nativ |
| CI/CD-Integration | Ausgezeichnet | Ausgezeichnet | Nur AWS | Gut |
| Unveränderliche Ausgabe | Ja (Snapshot) | Ja (Image) | Ja (AMI) | Abhängig |
| Lernkurve | Mittel | Niedrig | Mittel | Mittel |
Wann Packer die richtige Wahl ist: Multi-Cloud-Umgebungen, VM-basierte Deployments, Golden-Image-Pipelines oder wenn dasselbe Image gleichzeitig auf AWS und VMware benötigt wird.
Fallstricke und Sonderfälle
-
Veraltete Source-AMI-Filter: Wenn
source_ami_filtermehrere AMIs findet, stelltmost_recent = truesicher, dass das neueste verwendet wird. Ohne diese Option wählt Packer willkürlich aus und die Builds werden nicht deterministisch. -
Build-Timeouts: Packer wartet nach dem Start der Build-Instanz auf SSH-Verbindbarkeit. Langsame Cloud-Regionen oder restriktive Security Groups verursachen Timeouts. Bei Bedarf
ssh_timeoutüber den Standardwert von 5 Minuten erhöhen. -
Reihenfolge der Provisioner ist entscheidend: Provisioner werden in der Reihenfolge ausgeführt, in der sie im Template erscheinen. Ein
file-Provisioner, der nach/opt/app/kopiert, schlägt fehl, wenn das Verzeichnis noch nicht existiert — vorher einenshell-Provisioner hinzufügen, der es anlegt. -
IAM-Berechtigungen für AWS-Builds: Packer benötigt
ec2:RunInstances,ec2:CreateImage,ec2:DescribeImagesund weitere Rechte. Die minimale Packer-IAM-Policy verwenden, anstatt vollen Admin-Zugriff zu vergeben. -
Alte AMIs aufräumen: Packer erstellt neue AMIs, löscht aber keine alten. Ohne Bereinigung sammeln sich hunderte ungenutzter AMIs an. Eine Lifecycle-Policy oder ein geplantes Skript einrichten, um Images älter als N Tage zu deregistrieren.
-
Speicherplatz während des Builds: Temporäre Build-Instanzen verwenden die Standard-Root-Volume-Größe. Wenn die Provisionierung viele Pakete installiert, kann der Speicher voll werden.
launch_block_device_mappingsverwenden, um das Root-Volume zu vergrößern.
Fehlerbehebung
| Problem | Ursache | Lösung |
|---|---|---|
| ”Timeout waiting for SSH” | Security Group blockiert SSH oder Instanz braucht lange zum Booten | Prüfen, ob SG Port 22 vom Builder erlaubt; ssh_timeout erhöhen |
| ”AccessDenied” bei AMI-Erstellung | IAM-Policy fehlt ec2:CreateImage | Erforderliche EC2- und EBS-Berechtigungen zur IAM-Rolle hinzufügen |
| Provisioner-Skripte schlagen fehl | Skript läuft vor dem Paket-Update | apt-get update als ersten Schritt hinzufügen; DEBIAN_FRONTEND=noninteractive verwenden |
| Build erfolgreich, aber AMI fehlt | Falsche Region oder falsches Konto | region im Source-Block prüfen; aws ec2 describe-images zur Verifizierung nutzen |
| Packer-Build ist langsam | Keine parallelen Builds konfiguriert | -parallel-builds=N oder separate Source-Blöcke für Parallelität verwenden |
Zusammenfassung
- Packer automatisiert die Erstellung von Machine Images aus Code und eliminiert manuelle Serverkonfiguration bei gleichzeitig reproduzierbaren Builds
- HCL-Templates definieren Sources (wo gebaut wird), Provisioner (was installiert wird) und Post-Processors (was mit der Ausgabe geschieht)
- Multi-Plattform-Builds erzeugen identische Images für AWS, Docker und VMware aus einem einzigen Template
- Ansible-Provisioner integriert vorhandenes Configuration Management für komplexe Setups in Packer-Builds
- CI/CD-Integration ermöglicht automatische Image-Builds bei jeder Infrastrukturänderung und schafft so eine unveränderliche Deployment-Pipeline
- Kombination mit Terraform ergibt einen vollständigen Workflow — Packer baut das Image, Terraform deployt es