
Ce guide vous explique les concepts fondamentaux de Packer pour que vous puissiez créer vos premières images machine reproductibles. Vous comprendrez comment Packer automatise la création d'images identiques pour le cloud, les VMs locales ou les conteneurs, le tout à partir d'un simple fichier de configuration.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Ce qu'est Packer et pourquoi l'utiliser
- Les trois composants clés : builders, provisioners, post-processors
- Le workflow complet : init → validate → build
- Quand choisir Packer plutôt qu'une autre approche
Prérequis : aucun. Ce guide est une introduction aux concepts.
Qu'est-ce que Packer ?
Section intitulée « Qu'est-ce que Packer ? »Packer est un outil open source créé par HashiCorp qui automatise la création d'images machine. Une image machine, c'est une "photo" d'un système d'exploitation configuré et prêt à l'emploi, pensez-y comme un moule pour créer des VMs ou des conteneurs identiques.
Pour faire une analogie simple : si votre infrastructure était une cuisine, Packer serait la recette écrite qui permet de reproduire exactement le même plat à chaque fois, peu importe qui cuisine et dans quelle cuisine.
| Aspect | Sans Packer | Avec Packer |
|---|---|---|
| Création d'image | Installation manuelle, clics dans l'interface | Une commande : packer build |
| Reproductibilité | "Ça marchait la dernière fois..." | Image identique à chaque build |
| Documentation | Notes personnelles, wiki obsolète | Le template HCL EST la documentation |
| Multi-plateforme | Refaire le travail pour chaque cible | Un template, plusieurs images |
| Versioning | Difficile à tracer | Template versionné avec Git |
Pourquoi utiliser Packer ?
Section intitulée « Pourquoi utiliser Packer ? »Imaginez que vous devez déployer une application sur 50 serveurs. Sans Packer, vous avez deux options :
- Configurer chaque serveur manuellement, long, source d'erreurs, impossible à reproduire
- Utiliser un outil de configuration à chaque démarrage, lent, dépendant du réseau
Avec Packer, vous créez une seule fois une image "golden" qui contient tout : système d'exploitation, dépendances, configuration de sécurité. Ensuite, vous déployez cette image sur vos 50 serveurs en quelques minutes.
Les bénéfices concrets
Section intitulée « Les bénéfices concrets »- Déploiement rapide : une VM prête en secondes au lieu de minutes de configuration
- Cohérence : tous les serveurs sont identiques, pas de "configuration drift"
- Sécurité : les correctifs sont intégrés dans l'image, pas appliqués après coup
- Audit : le template décrit exactement ce qui est installé
- Multi-cloud : une même configuration pour AWS, Azure, GCP, on-premise
Architecture de Packer
Section intitulée « Architecture de Packer »Packer fonctionne avec trois types de composants qui s'exécutent dans un ordre précis. Comprendre cette architecture est essentiel pour écrire des templates efficaces.
Les Builders : créer la machine de base
Section intitulée « Les Builders : créer la machine de base »Le builder est responsable de créer une machine temporaire et de produire une image à partir de celle-ci. Chaque builder est spécifique à une plateforme :
| Builder | Plateforme | Usage typique |
|---|---|---|
amazon-ebs | AWS | AMI pour EC2 |
azure-arm | Azure | Images managées |
googlecompute | GCP | Images Compute Engine |
qemu | KVM/libvirt | Images locales Linux |
proxmox-iso | Proxmox | Templates VM |
docker | Docker | Images conteneur |
virtualbox-iso | VirtualBox | Images de dev |
Packer supporte plus de 52 builders via son système de plugins. Les builders officiels maintenu par HashiCorp sont téléchargés depuis releases.hashicorp.com.
Les Provisioners : configurer l'image
Section intitulée « Les Provisioners : configurer l'image »Les provisioners s'exécutent après que le builder a créé la machine temporaire. Ils configurent le système : installer des paquets, copier des fichiers, exécuter des scripts.
| Provisioner | Description | Cas d'usage |
|---|---|---|
shell | Exécute des commandes shell | Scripts bash simples |
ansible | Exécute des playbooks Ansible | Configuration complexe |
file | Copie des fichiers vers l'image | Fichiers de config |
powershell | Scripts PowerShell | Images Windows |
chef / puppet | Outils de configuration | Écosystèmes existants |
L'ordre des provisioners dans le template détermine leur ordre d'exécution. Packer les exécute séquentiellement.
Les Post-Processors : finaliser l'artefact
Section intitulée « Les Post-Processors : finaliser l'artefact »Les post-processors s'exécutent après la création de l'image pour effectuer des actions supplémentaires :
| Post-Processor | Action |
|---|---|
manifest | Génère un fichier JSON avec les métadonnées du build |
compress | Compresse l'image en archive |
docker-push | Pousse l'image vers Docker Hub ou un registry |
checksum | Calcule les checksums (sha256, md5) |
vagrant | Convertit en box Vagrant |
Le workflow Packer
Section intitulée « Le workflow Packer »Packer suit un workflow en trois étapes que vous utiliserez systématiquement :
-
packer init, Télécharge les plugins requisCette commande lit le bloc
required_pluginsde votre template et télécharge les plugins nécessaires. À exécuter une seule fois par projet (ou quand vous ajoutez un nouveau plugin).Fenêtre de terminal packer init mon-template.pkr.hcl -
packer validate, Vérifie la syntaxe du templateValide que le template HCL est syntaxiquement correct et que toutes les références sont valides. Cette commande ne crée rien, elle vérifie simplement.
Fenêtre de terminal packer validate mon-template.pkr.hcl -
packer build, Construit l'imageExécute le builder, les provisioners et les post-processors pour créer l'image finale.
Fenêtre de terminal packer build mon-template.pkr.hcl
Ce qui se passe pendant un build
Section intitulée « Ce qui se passe pendant un build »Quand vous lancez packer build, voici ce qui se passe en coulisses :
- Création : le builder démarre une machine temporaire (VM, conteneur...)
- Connexion : Packer se connecte via SSH ou WinRM
- Provisionnement : les provisioners configurent la machine
- Capture : le builder crée une image à partir de la machine
- Nettoyage : la machine temporaire est détruite
- Post-traitement : les post-processors s'exécutent sur l'image
Structure d'un template Packer
Section intitulée « Structure d'un template Packer »Un template Packer en HCL (HashiCorp Configuration Language) se compose de plusieurs blocs :
# 1. Bloc packer : version et plugins requispacker { required_version = ">= 1.15.0"
required_plugins { docker = { version = ">= 1.1.0" source = "github.com/hashicorp/docker" } }}
# 2. Variables : rendent le template configurablevariable "image_name" { type = string default = "mon-app" description = "Nom de l'image finale"}
# 3. Source : définit le builder et sa configurationsource "docker" "ubuntu" { image = "ubuntu:22.04" commit = true}
# 4. Build : assemble sources, provisioners et post-processorsbuild { sources = ["source.docker.ubuntu"]
provisioner "shell" { inline = ["apt-get update", "apt-get install -y curl"] }}Comparaison avec d'autres approches
Section intitulée « Comparaison avec d'autres approches »Packer vs Configuration Management (Ansible, Chef, Puppet)
Section intitulée « Packer vs Configuration Management (Ansible, Chef, Puppet) »| Aspect | Packer | Ansible/Chef/Puppet |
|---|---|---|
| Quand | Avant le déploiement (build time) | Pendant/après le déploiement (run time) |
| Résultat | Image figée | Configuration dynamique |
| Temps de démarrage | Instantané | Dépend de la complexité |
| Dépendances réseau | Non | Oui (repos, registries) |
En pratique : utilisez les deux ensemble. Packer avec Ansible en provisioner pour créer des images, puis Ansible pour les mises à jour légères post-déploiement.
Packer vs Dockerfile
Section intitulée « Packer vs Dockerfile »| Aspect | Packer | Dockerfile |
|---|---|---|
| Scope | VMs + conteneurs | Conteneurs uniquement |
| Multi-plateforme | Oui (AWS, Azure, QEMU...) | Non |
| Provisioners | Shell, Ansible, Chef... | Shell uniquement |
| Écosystème | Intégration Terraform/Vault | Écosystème Docker |
En pratique : pour des conteneurs simples, Dockerfile suffit. Pour des VMs ou des images multi-plateformes, utilisez Packer.
Cas d'usage typiques
Section intitulée « Cas d'usage typiques »Golden Images pour le cloud
Section intitulée « Golden Images pour le cloud »Créez une AMI AWS pré-configurée avec vos outils de monitoring, agents de sécurité et configurations réseau. Chaque nouvelle instance démarre avec tout ce qu'il faut.
Templates pour homelab
Section intitulée « Templates pour homelab »Automatisez la création de templates Proxmox ou VMware pour votre infrastructure personnelle. Un seul template pour créer des VMs identiques.
Images Docker standardisées
Section intitulée « Images Docker standardisées »Créez des images de base avec vos standards d'entreprise : outils de debug, certificats, configuration réseau.
Environnements de développement
Section intitulée « Environnements de développement »Produisez des boxes Vagrant cohérentes pour que tous les développeurs travaillent dans le même environnement.
Pièges courants
Section intitulée « Pièges courants »À retenir
Section intitulée « À retenir »- Packer automatise la création d'images machine reproductibles (VMs, conteneurs)
- Builders créent la machine temporaire (AWS, Docker, QEMU, Proxmox...)
- Provisioners configurent l'image (Shell, Ansible, File...)
- Post-processors finalisent l'artefact (compress, push, manifest...)
- Workflow :
packer init→packer validate→packer build - HCL2 est le format de template recommandé depuis v1.7.0
- Golden images = images de référence pré-configurées et validées
FAQ : questions fréquentes
Section intitulée « FAQ : questions fréquentes »Ce que Packer fait
| Fonction | Exemple |
|---|---|
| Création d'images | AMI AWS, images Docker, VM Azure |
| Multi-plateforme | 1 template → plusieurs images |
| Automatisation | Build reproductible sans intervention |
| Golden images | Image de base standardisée |
Analogie simple
Packer, c'est comme un moule à gâteau : vous définissez la recette une fois, et vous pouvez produire des gâteaux identiques à la demande, pour différents fours (AWS, Docker, Azure...).Exemple rapide
source "docker" "ubuntu" {
image = "ubuntu:24.04"
commit = true
}
build {
sources = ["source.docker.ubuntu"]
provisioner "shell" {
inline = ["apt-get update && apt-get install -y curl"]
}
}
Comparaison
| Critère | Packer | Dockerfile |
|---|---|---|
| Cible | Multi-plateforme | Docker uniquement |
| Format | HCL2 | DSL spécifique |
| Provisioners | Shell, Ansible, Chef, Puppet | RUN uniquement |
| Sortie | AMI, VMDK, OCI, Docker... | Image Docker |
| Écosystème | HashiCorp | Docker/OCI |
| Cas d'usage | Golden images multi-cloud | Conteneurs applicatifs |
Quand utiliser quoi ?
- Dockerfile : applications conteneurisées, développement local
- Packer : golden images multi-cloud, immutable infrastructure
- Les deux : Packer peut utiliser Docker comme builder de test
Exemple identique
# Dockerfile
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y curl
# Packer HCL2
source "docker" "ubuntu" {
image = "ubuntu:24.04"
commit = true
}
build {
sources = ["source.docker.ubuntu"]
provisioner "shell" {
inline = ["apt-get update && apt-get install -y curl"]
}
}
Linux (recommandé : asdf)
# Avec asdf (gestion de versions)
asdf plugin add packer
asdf install packer latest
asdf set --home packer latest
# Ou téléchargement direct
wget https://releases.hashicorp.com/packer/1.15.0/packer_1.15.0_linux_amd64.zip
unzip packer_1.15.0_linux_amd64.zip
sudo mv packer /usr/local/bin/
macOS
# Homebrew
brew install packer
Windows
# Chocolatey
choco install packer
# Ou Scoop
scoop install packer
Vérification
packer --version
# Packer v1.15.0
.pkr.hcl qui définit comment créer une image.Blocs principaux
| Bloc | Rôle | Obligatoire |
|---|---|---|
packer {} |
Configuration, plugins requis | Optionnel |
source |
Définition du builder | Oui |
build |
Orchestration du build | Oui |
variable |
Paramètres d'entrée | Optionnel |
locals |
Valeurs calculées | Optionnel |
Exemple minimal
packer {
required_plugins {
docker = {
version = ">= 1.0.0"
source = "github.com/hashicorp/docker"
}
}
}
source "docker" "ubuntu" {
image = "ubuntu:24.04"
commit = true
}
build {
sources = ["source.docker.ubuntu"]
}
HCL2 vs JSON
| Aspect | HCL2 | JSON (legacy) |
|---|---|---|
| Lisibilité | Excellente | Difficile |
| Commentaires | # ou // |
Non supportés |
| Fonctions | Built-in | Limitées |
| Statut | Recommandé | Déprécié |
Workflow de validation
# 1. Télécharger les plugins requis
packer init .
# 2. Vérifier le formatage
packer fmt -check .
# 3. Valider la syntaxe et la cohérence
packer validate .
# Optionnel : avec des variables
packer validate -var "image_tag=latest" .
Ce que valide Packer
| Commande | Vérifie |
|---|---|
packer init |
Plugins disponibles et téléchargés |
packer fmt -check |
Formatage HCL conforme |
packer validate |
Syntaxe, références, cohérence |
En CI/CD
# Échouer au premier problème
packer init . && packer fmt -check . && packer validate .
Exemple de sortie
$ packer validate .
The configuration is valid.
$ packer validate broken.pkr.hcl
Error: Unknown source type "docker.ubuntu"
Builders principaux
| Builder | Plateforme | Sortie |
|---|---|---|
| docker | Docker Engine | Image OCI |
| amazon-ebs | AWS | AMI |
| azure-arm | Azure | Managed Image |
| googlecompute | GCP | Compute Image |
| qemu | KVM/Proxmox | QCOW2 |
| vmware-iso | VMware | VMDK |
| virtualbox-iso | VirtualBox | OVA |
| lxc / lxd | Conteneurs Linux | Image LXC/LXD |
| null | Test | Aucune (dry-run) |
Installation des plugins
packer {
required_plugins {
docker = {
version = ">= 1.0.0"
source = "github.com/hashicorp/docker"
}
amazon = {
version = ">= 1.0.0"
source = "github.com/hashicorp/amazon"
}
}
}
Multi-plateforme
Un même template peut cibler plusieurs builders :build {
sources = [
"source.docker.ubuntu",
"source.amazon-ebs.ubuntu"
]
}
Déclaration
variable "image_tag" {
type = string
default = "latest"
description = "Tag de l'image Docker"
}
variable "packages" {
type = list(string)
default = ["curl", "wget", "vim"]
}
Utilisation
source "docker" "app" {
image = "ubuntu:${var.image_tag}"
commit = true
}
Fournir des valeurs
| Méthode | Exemple |
|---|---|
| CLI | packer build -var "image_tag=1.0" . |
| Fichier | packer build -var-file=prod.pkrvars.hcl . |
| Environnement | export PKR_VAR_image_tag=1.0 |
Locals (valeurs calculées)
locals {
timestamp = formatdate("YYYYMMDDhhmmss", timestamp())
image_name = "app-${var.image_tag}-${local.timestamp}"
}
Provisioners principaux
| Provisioner | Usage |
|---|---|
| shell | Commandes bash/sh, scripts |
| file | Copie de fichiers vers l'image |
| ansible | Exécution de playbooks |
| shell-local | Commandes sur la machine hôte |
Exemple
build {
sources = ["source.docker.ubuntu"]
provisioner "file" {
source = "config/app.conf"
destination = "/etc/app/app.conf"
}
provisioner "shell" {
inline = [
"apt-get update",
"apt-get install -y nginx"
]
}
provisioner "ansible" {
playbook_file = "playbooks/configure.yml"
}
}
Ordre d'exécution
Les provisioners s'exécutent dans l'ordre de déclaration :file→ copie les fichiersshell→ installe les paquetsansible→ configure l'application
Logs détaillés
# Activer tous les logs
export PACKER_LOG=1
packer build .
# Ou en une ligne
PACKER_LOG=1 packer build .
Mode interactif
# Pause entre chaque étape
packer build -debug .
# Pause configurable
PACKER_LOG=1 PACKER_LOG_PATH=packer.log packer build -debug .
Gestion des erreurs
# Demander quoi faire en cas d'erreur
packer build -on-error=ask .
# Options : abort, retry, cleanup
Problèmes courants
| Symptôme | Cause probable |
|---|---|
| Timeout SSH | Firewall, clé SSH incorrecte |
| Command not found | Chemin non dans PATH |
| Permission denied | Utilisateur non root, sudo requis |
| Plugin not found | packer init . pas exécuté |
| Variable undefined | Variable déclarée mais non valorisée |
Post-processors principaux
| Post-processor | Action |
|---|---|
| compress | Archive .tar.gz de l'image |
| manifest | Fichier JSON avec métadonnées |
| checksum | Hash SHA256 pour intégrité |
| docker-import | Import dans Docker Engine |
| docker-tag | Ajout de tags à l'image |
| docker-push | Push vers registry |
Exemple simple
build {
sources = ["source.docker.ubuntu"]
post-processor "manifest" {
output = "manifest.json"
}
}
Chaînage de post-processors
post-processors {
post-processor "docker-import" {
repository = "myapp"
tag = "latest"
}
post-processor "docker-push" {
login = true
login_server = "registry.example.com"
login_username = var.registry_user
login_password = var.registry_pass
}
}
Le chaînage garantit que chaque étape utilise le résultat de la précédente.GitHub Actions
name: Build Image
on: [push]
jobs:
packer:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Packer
uses: hashicorp/setup-packer@v3
with:
version: "1.15.0"
- name: Init
run: packer init .
- name: Validate
run: packer fmt -check . && packer validate .
- name: Build
run: packer build .
env:
PKR_VAR_image_tag: ${{ github.sha }}
GitLab CI/CD
packer-build:
image: hashicorp/packer:1.15.0
script:
- packer init .
- packer fmt -check .
- packer validate .
- packer build .
variables:
PKR_VAR_image_tag: $CI_COMMIT_SHORT_SHA
cache:
paths:
- .packer.d/
Bonnes pratiques CI/CD
- Cacher le répertoire des plugins
- Variables d'environnement pour les secrets
- Validation avant le build
- Manifest pour traçabilité
amazon-ebs.Template minimal
packer {
required_plugins {
amazon = {
version = ">= 1.0.0"
source = "github.com/hashicorp/amazon"
}
}
}
variable "aws_region" {
default = "eu-west-3"
}
source "amazon-ebs" "ubuntu" {
region = var.aws_region
instance_type = "t3.micro"
source_ami_filter {
filters = {
name = "ubuntu/images/*ubuntu-jammy-22.04-amd64-server-*"
root-device-type = "ebs"
virtualization-type = "hvm"
}
most_recent = true
owners = ["099720109477"] # Canonical
}
ssh_username = "ubuntu"
ami_name = "my-app-{{timestamp}}"
}
build {
sources = ["source.amazon-ebs.ubuntu"]
provisioner "shell" {
inline = ["sudo apt-get update && sudo apt-get install -y nginx"]
}
}
Authentification
export AWS_ACCESS_KEY_ID="AKIAIOSFODNN7EXAMPLE"
export AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG..."
packer build .
Arborescence
projet-packer/
├── common.pkr.hcl # Plugins, config commune
├── variables.pkr.hcl # Déclarations de variables
├── locals.pkr.hcl # Valeurs calculées
├── docker.pkr.hcl # Source Docker
├── aws.pkr.hcl # Source AWS (optionnel)
├── build.pkr.hcl # Blocs build
├── dev.pkrvars.hcl # Variables dev
├── prod.pkrvars.hcl # Variables prod
├── scripts/
│ ├── setup.sh
│ └── cleanup.sh
├── config/
│ └── app.conf
└── Makefile
Makefile
.PHONY: init validate build clean
init:
packer init .
validate: init
packer fmt -check .
packer validate .
build: validate
packer build -var-file=dev.pkrvars.hcl .
build-prod: validate
packer build -var-file=prod.pkrvars.hcl .
clean:
rm -f manifest.json *.tar.gz
Utilisation
make build # Build dev
make build-prod # Build prod
Variables sensibles
variable "docker_password" {
type = string
sensitive = true # Masqué dans les logs
}
Bonnes pratiques
| Méthode | Sécurité | Usage |
|---|---|---|
| Env vars | ✅ Bonne | PKR_VAR_password=xxx packer build . |
| CI Secrets | ✅ Excellente | GitHub Secrets, GitLab CI Variables |
| Vault | ✅ Enterprise | HashiCorp Vault integration |
| CLI -var | ⚠️ Risquée | Visible dans historique shell |
| Fichier committé | ❌ Dangereuse | Jamais en production |
En CI/CD
# GitHub Actions
env:
PKR_VAR_docker_password: ${{ secrets.DOCKER_PASSWORD }}
# GitLab CI
variables:
PKR_VAR_docker_password: $DOCKER_PASSWORD
.gitignore
# Ne jamais committer
*.pkrvars.hcl
!example.pkrvars.hcl
Multi-sources
source "docker" "app" {
image = "ubuntu:24.04"
commit = true
}
source "amazon-ebs" "app" {
region = "eu-west-3"
instance_type = "t3.micro"
# ...
}
build {
sources = [
"source.docker.app",
"source.amazon-ebs.app"
]
provisioner "shell" {
inline = ["echo 'Hello from ${source.type}'"]
}
}
Contrôle du parallélisme
# Limiter à 2 builds simultanés
packer build -parallel-builds=2 .
# Un seul build à la fois
packer build -parallel-builds=1 .
Avantages
- Gain de temps : Docker et AWS se buildent simultanément
- Même configuration : provisioners partagés
- Artefacts séparés : chaque builder produit son image