Atelier
Packer
Master Expert Technologie de l'information EPITECH 2020.
Co-fondateur et CTO d'une startup dans l'Edtech 2019 - fin 2022. (+3 ans)
Formation PSPO-1 Agile Scrum 2022.
Co-fondateur et CTO d'une startup dans la Deeptech fin 2022 - aujourd'hui.
Valentin MONTAGNE

1
Découverte de Packer
3
Packer et AWS
2
Packer et Docker
Déroulement du cours
Chaque séance débutera par la présentation d'un concept et de l'intérêt d'utilisation de celui-ci.
1
Théorie
Après la théorie, nous verrons alors la pratique en réalisant des exercices sur un repository gitlab.
2
Pratique
Nous verrons ensemble la correction des travaux pratiques. N'hésitez pas à poser vos questions.
3
Correction
Déroulement des journées
Rendu TP et exercices
Pour faciliter le rendu final des TPs et exercices, vous allez créer un dépôt sur Github avec le nom Packer en publique et le cloner sur votre machine.
Si vous préférez le garder en privé, vous devez m'ajouter avec les droits pour voir votre dépôt avec le nom d'utilisateur : ValentinMontagne
Découverte de Packer
1.
Qu'est-ce que Packer ?
Crée des images machines multi-plateformes à partir d'une configuration comme AWS AMI, VMware, VirtualBox, etc.
X
X



Léger, rapide et compatible avec tous les systèmes d’exploitation majeurs, il est en complément avec les outils de configuration comme Chef et Puppet.
Une image machine est un fichier statique contenant un système d’exploitation pré-configuré et des logiciels installés. Elle sert à lancer rapidement des machines identiques.
Pourquoi utiliser Packer ?
Les images machines pré-bâties étaient peu utilisées, car leur création manuelle était longue, complexe et difficile à automatiser.



Packer automatise totalement la création d’images machines, quel que soit le type ou la plateforme, rendant le processus plus simple et reproductible.
Les serveurs sont prêts en quelques secondes, totalement configurés. Cela accélère la production et le développement, où les VM locales n’ont plus besoin d’un provisioning lent à chaque lancement.
Pourquoi utiliser Packer ? - 2
Packer génère des images identiques pour plusieurs plateformes : vous pouvez par exemple exécuter la production sur AWS, la préprod sur OpenStack, et le développement sur VirtualBox.



Comme toute la configuration est faite à la construction de l’image, les erreurs apparaissent immédiatement et non à l’exécution.
Ces images peuvent ensuite être testées rapidement (smoke tests) pour garantir que toutes les futures instances fonctionnent correctement.
Cas d'utilisations
Dans une CD : à chaque modification des scripts d’infrastructure (Chef, Puppet…), il génère des images pour plusieurs plateformes. Elles peuvent être vérifiées avant même leur déploiement.
Dans un env Dev/Prod : les mêmes templates permettent de créer à la fois une image pour AWS (prod) et une VM pour VMware/Vagrant.
Pour les outils clés en main ou les démos : permet de générer des images pour toutes les plateformes avec un outil déjà pré-configuré prêt à l'emploi.
Les éléments importants dans Packer
Découvrons les éléments spécifiques à Packer comme :
- Artifact : le résultat final d’un Build d’image comme un ID pour AMI AWS ou un dossier pour VMWare.
- Build : est une tâche unique qui crée un artifact pour une seule plateforme (AWS, VMware, VirtualBox, etc.).
- Builder : composant qui exécute le Build en lisant la configuration fournie pour une sortie spécifique (amazon-ebs)
- Data Source : permet de récupérer des données depuis l’extérieur (cloud, API…) pour les réutiliser dans un template.
Les éléments importants dans Packer - 2
- Post-Processor : modifie, transforme ou déplace l’artifact généré pour créer un nouvel artifact après un Builder.
- Provisioner : installent et configurent les logiciels à l’intérieur d’une machine en cours de création, avant qu’elle ne devienne un artifact figé.
- Template : des fichiers en HCL ou JSON qui définissent un ou plusieurs builds en configurant les différents composants de Packer (builders, provisioners, post-processors, etc.).
Comment créer une template ?
Packer utilise lui aussi le HCL comme Terraform. (Attention JSON est déprécié)
On retrouve alors les mêmes éléments dans le fichier de configuration :
-
Blocs : Ce sont des conteneurs de configuration. Chaque bloc a un type (ex.
source
,build
), peut avoir des étiquettes (labels), et contient un corps avec des arguments et éventuellement d'autres blocs imbriqués. -
Arguments : Ils attribuent une valeur à un nom (ex.
region = "eu-west-1"
). - Expressions : Elles représentent une valeur (littérale ou calculée).
Exemple de la syntaxe
Block - Source
Le block source
définit où et comment Packer va créer l'image de base pour le build.
source "amazon-ebs" "web_server" {
region = "eu-west-1"
instance_type = "t3.micro"
ssh_username = "ubuntu"
ami_name = "mon-image-{{timestamp}}"
source_ami_filter {
filters = {
name = "ubuntu/images/hvm-ssd/ubuntu-22.04-*"
}
owners = ["099720109477"]
most_recent = true
}
}
# Utilisation
build {
sources = ["source.amazon-ebs.web_server"]
provisioner "shell" {
inline = ["echo 'Hello World'"]
}
}
Builders
Les builders sont les composants de Packer qui savent comment créer des images pour une plateforme spécifique. Ce sont les "moteurs" qui transforment une image de base en image personnalisée.
Comme les providers dans Terraform, il y a un grand nombre de builders à utiliser pour intégrer des outils ou des types d'image machine comme AWS, Docker ou même Ansible :
Builders - Fonctionnement
Un builder fonctionne de la manière suivante :
- Lance une instance temporaire (EC2, conteneur, VM...)
- Se connecte via SSH/WinRM
- Exécute les provisioners
- Capture l'état final en image
- Nettoie les ressources temporaires
Les builders sont donc les adaptateurs qui permettent à Packer de parler le "langage" de chaque cloud ou plateforme de virtualisation.
Builders - Les plus connus
Builder | Plateforme | Sortie |
---|---|---|
amazon-ebs |
AWS | AMI |
docker |
Docker | Image Docker |
virtualbox-iso |
VirtualBox | VM/OVA |
vmware-iso |
VMware | VMDK |
azure-arm |
Azure | Image managée |
googlecompute | GCP | Image GCE |
Block - Build
Le block build
orchestre le processus de création d'image. Il définit quoi faire et dans quel ordre pour transformer votre image de base en image finale.
Le block build
est donc le chef d'orchestre qui coordonne toutes les étapes pour créer votre image personnalisée.
build {
name = "nom_du_build"
sources = ["source.type.nom"]
# Provisioners (étapes de configuration)
provisioner "shell" {
inline = ["commandes..."]
}
# Post-processors (actions après build)
post-processor "manifest" {
output = "manifest.json"
}
}
Block - Build
Fonctionnement du Build :
- Démarre les sources (instances temporaires)
- Exécute les provisioners dans l'ordre
- Capture l'image finale
- Lance les post-processors
- Nettoie les ressources temporaires
Points clés :
- Un build = Un pipeline complet
- Ordre séquentiel : Provisioners exécutés dans l'ordre déclaré
- Multi-sources : Peut utiliser plusieurs sources simultanément
- Nommage : Permet d'identifier et filtrer les builds
- Gestion d'erreurs : Arrêt en cas d'échec d'un provisioner
Block - Build - Composants
1. Sources - le point de départ
sources = [
"source.amazon-ebs.web",
"source.docker.web"
]
2. Provisioners - Configuration
provisioner "shell" {
script = "./install.sh"
}
provisioner "file" {
source = "./app/"
destination = "/opt/app/"
}
3. Post-processors - Actions finales
post-processor "docker-tag" {
repository = "mon-app"
tags = ["latest", "v1.0"]
}
Block - Build - Exemple
build {
name = "web-server"
sources = ["source.amazon-ebs.ubuntu"]
# Installation
provisioner "shell" {
inline = [
"sudo apt update",
"sudo apt install -y nginx"
]
}
# Configuration
provisioner "file" {
source = "./nginx.conf"
destination = "/tmp/nginx.conf"
}
# Finalisation
provisioner "shell" {
inline = ["sudo mv /tmp/nginx.conf /etc/nginx/"]
}
}
Exemple d'une Template entière pour une image AWS
# Variables
variable "aws_region" {
type = string
default = "eu-west-1"
description = "Région AWS pour le build"
}
variable "instance_type" {
type = string
default = "t3.micro"
description = "Type d'instance EC2 pour le build"
}
variable "ssh_username" {
type = string
default = "ubuntu"
description = "Nom d'utilisateur SSH"
}
variable "ami_name_prefix" {
type = string
default = "nginx-static-web"
description = "Préfixe du nom de l'AMI"
}
# Configuration des sources locales
locals {
timestamp = regex_replace(timestamp(), "[- TZ:]", "")
ami_name = "${var.ami_name_prefix}-${local.timestamp}"
}
# Source AMI
source "amazon-ebs" "nginx_server" {
region = var.aws_region
instance_type = var.instance_type
ssh_username = var.ssh_username
ami_name = local.ami_name
ami_description = "AMI Ubuntu 22.04 avec NGINX pour contenu web statique - Built with Packer"
source_ami_filter {
filters = {
name = "ubuntu/images/hvm-ssd/ubuntu-22.04-amd64-server-*"
root-device-type = "ebs"
virtualization-type = "hvm"
}
owners = ["099720109477"] # Canonical
most_recent = true
}
# Configuration du stockage
ebs_optimized = true
# Tags pour l'AMI
tags = {
Name = "nginx-static-web"
Environment = "production"
OS = "Ubuntu 22.04"
Application = "NGINX"
BuildDate = timestamp()
BuildTool = "Packer"
}
# Tags pour l'instance de build
run_tags = {
Name = "packer-nginx-build"
}
}
# Build
build {
name = "nginx-static-web"
sources = ["source.amazon-ebs.nginx_server"]
# Mise à jour du système
provisioner "shell" {
inline = [
"echo 'Mise à jour du système...'",
"sudo apt-get update",
"sudo apt-get upgrade -y",
"sudo apt-get install -y curl wget unzip"
]
}
# Installation et configuration de NGINX
provisioner "shell" {
inline = [
"echo 'Installation de NGINX...'",
"sudo apt-get install -y nginx",
"sudo systemctl enable nginx",
"echo 'NGINX installé et activé'"
]
}
# Copie du contenu web statique
provisioner "file" {
source = "./web-content/"
destination = "/tmp/web-content/"
}
# Configuration du site web
provisioner "shell" {
inline = [
"echo 'Configuration du contenu web...'",
"sudo rm -rf /var/www/html/*",
"sudo cp -r /tmp/web-content/* /var/www/html/",
"sudo chown -R www-data:www-data /var/www/html",
"sudo chmod -R 755 /var/www/html"
]
}
# Configuration NGINX personnalisée
provisioner "file" {
content = <<-EOF
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/html;
index index.html index.htm;
server_name _;
# Gestion des fichiers statiques
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Configuration pour SPA (Single Page Application)
location / {
try_files $uri $uri/ /index.html;
}
# Sécurité - masquer la version de NGINX
server_tokens off;
# Headers de sécurité
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
}
EOF
destination = "/tmp/nginx-site.conf"
}
# Application de la configuration NGINX
provisioner "shell" {
inline = [
"echo 'Application de la configuration NGINX...'",
"sudo cp /tmp/nginx-site.conf /etc/nginx/sites-available/default",
"sudo nginx -t",
"sudo systemctl reload nginx",
"sudo systemctl status nginx"
]
}
# Nettoyage et optimisation
provisioner "shell" {
inline = [
"echo 'Nettoyage du système...'",
"sudo apt-get autoremove -y",
"sudo apt-get autoclean",
"sudo rm -rf /tmp/*",
"sudo rm -rf /var/tmp/*",
"history -c",
"echo 'Build terminé avec succès!'"
]
}
# Validation finale
provisioner "shell" {
inline = [
"echo 'Validation de l'installation...'",
"nginx -v",
"sudo systemctl is-active nginx",
"curl -I http://localhost || echo 'Test HTTP échoué'",
"echo 'Validation terminée'"
]
}
}
# Post-processor pour manifest
build {
sources = ["source.amazon-ebs.nginx_server"]
post-processor "manifest" {
output = "manifest.json"
strip_path = true
custom_data = {
build_time = timestamp()
nginx_version = "latest"
}
}
}
Le CLI
Packer est utilisable via un CLI, voici les commandes principales : init, plugins, validate, fmt, inspect, build, console.
Avec plusieurs options globales :
Option | Description | Exemple |
---|---|---|
-var |
Variable inline | -var="region=us-east-1" |
-var-file |
Fichier de variables | -var-file="prod.pkrvars.hcl" |
-only |
Sources spécifiques | -only="source.docker.web" |
-except |
Exclure des sources | -except="source.vmware.*" |
-parallel-builds |
Limite parallélisme | -parallel-builds=3 |
Le CLI - init
La commande packer init
installe automatiquement les plugins requis par votre configuration Packer, similaire à terraform init
.
packer init . # Initialise le répertoire courant
packer init template.pkr.hcl # Initialise pour un fichier spécifique
packer init -upgrade . # Met à jour les plugins existants
packer {
required_plugins {
docker = {
source = "github.com/hashicorp/docker"
version = "~> 1.0"
}
amazon = {
source = "github.com/hashicorp/amazon"
version = ">= 1.2.0"
}
}
}
Récupère les informations des plugins à installer dans le block packer
.
Le CLI - plugins
La commande packer plugins
permet de gérer les plugins Packer : installation, mise à jour, listing et diagnostic.
packer plugins install github.com/hashicorp/docker
packer plugins install github.com/hashicorp/amazon@v1.2.8
packer plugins install --path ./custom-plugin
packer plugins remove github.com/hashicorp/docker
packer plugins remove github.com/hashicorp/docker@1.2.0
$ packer plugins installed
┌──────────────────────────────┬─────────┬──────────────┐
│ Plugin │ Version │ API Version │
├──────────────────────────────┼─────────┼──────────────┤
│ github.com/hashicorp/amazon │ v1.2.8 │ x5.0, x5.1 │
│ github.com/hashicorp/docker │ v1.0.9 │ x5.0, x5.1 │
│ github.com/hashicorp/vsphere │ v1.2.1 │ x5.0, x5.1 │
└──────────────────────────────┴─────────┴──────────────┘
Le CLI - validate
Valide la configuration actuelle en vérifiant tous les fichiers Packer.
Cela permet de facilement corriger des erreurs avant de lancer le build, facilement ajoutable dans une pipeline CI ou git hooks.
packer validate template.pkr.hcl # Validation syntaxe + logique
packer validate -var-file="vars.pkrvars.hcl" . # Avec variables
packer validate -syntax-only template.pkr.hcl # Syntaxe uniquement
Le CLI - fmt
Formate le code de tous les fichiers de configuration Packer automatiquement.
Cela permet de facilement corriger des erreurs de mise en forme avant de lancer le build, facilement ajoutable dans une pipeline CI ou git hooks.
packer fmt template.pkr.hcl # Format un fichier
packer fmt . # Format tous les .pkr.hcl
packer fmt -diff . # Affiche les différences
packer fmt -write=false . # Mode dry-run
Le CLI - inspect
Récupère toutes les informations des différents fichiers de configuration pour afficher proprement toutes les informations sur les variables disponibles, les builds, etc.
Cela permet de facilement comprendre ce qu'il est possible de faire avec ce projet Packer et de le configurer.
packer inspect .
Packer Inspect: HCL2 mode
> input-variables:
var.docker_image: "ubuntu:lunar"
> local-variables:
> builds:
> learn-packer:
sources:
docker.ubuntu
docker.ubuntu-focal
provisioners:
shell
shell
file
post-processors:
0:
docker-tag
1:
docker-tag
2:
manifest
Le CLI - build
Construis les images automatiquement en utilisant les fichiers de configuration.
packer build template.pkr.hcl # Build basique
packer build -var="region=eu-west-1" template.pkr.hcl # Avec variables
packer build -var-file="prod.pkrvars.hcl" . # Avec fichier de variables
packer build -only="source.docker.web" . # Build sélectif
packer build -parallel-builds=2 . # Builds parallèles limités
Le CLI - console
Lance une console interactive avec toute la configuration pour pouvoir vérifier des expressions HCL comme la valeur d'une variable comme var.region
.
packer console . # Test d'expressions HCL
# Dans la console :
# > var.region
# > local.timestamp
Des questions ?
Packer et Docker
2.
TP - Débuter avec Docker
Tutoriel officiel
Packer possède déjà plusieurs tutoriels officiels pour apprendre à utiliser l'outil, nous allons utiliser en premier lieu celui de Docker :
https://developer.hashicorp.com/packer/tutorials/docker-get-started
Le tutoriel fait office de TP guidé pour avoir la base nécessaire pour réaliser les exercices suivants, il faut réaliser le tutoriel jusqu'aux post-processors inclus.
Exercice 1 : Variables
Ajoutez des variables à la place des valeurs codées en dur suivantes :
-
Le nom de l’image ubuntu-focal
-
Le contenu du fichier example.txt
-
Les tags des images
Vous devez :
-
Déclarer chaque variable dans un fichier
variables.pkr.hcl
-
Fournir des valeurs par défaut
-
Déplacer celles déjà présentes.
Appelez-moi pour que l'on puisse valider ensemble.
Exercice 2 : Outputs
Ajoutez un Post-Processor pour générer automatiquement un fichier manifest.json qui liste les Artifacts créés durant le build.
N'hésitez pas à regarder la documentation des Post-Processors :
https://developer.hashicorp.com/packer/docs/post-processors/manifest
Appelez-moi pour que l'on puisse valider ensemble.
Exercice 3 : Provisioner File
Ajoutez un Provisioner pour ajouter automatiquement un fichier welcome.txt dans l'image générée. Le fichier doit être créé localement puis copié dans l'image.
Objectifs :
- Ajouter un fichier
welcome.txt
contenant "Bienvenue dans mon image Docker personnalisée !" dans votre dossier. - Placer ce fichier dans
/home/
de l'image finale. - Vérifier que le fichier est présent en listant le contenu.
Appelez-moi pour que l'on puisse valider ensemble.
Exercice 4 : Créer une autre image
- Créer une configuration Packer qui build 2 images en parallèle : Une image Ubuntu 22.04 et une image Alpine Linux 3.19.
- Chaque image doit contenir : Un fichier
system-info.txt
avec les informations du système, les outils de base installés (curl
,wget
), un scriptshow-info.sh
qui affiche les informations système. - Tagger les images avec des noms distincts :
multi-os-ubuntu:latest,
multi-os-alpine:latest
Appelez-moi pour que l'on puisse valider ensemble.
Exercice 5 : Créer une image d'une application
Utilisez un projet d'exemple pour créer une image prête à l'emploi :
https://gitlab.com/vm-marvelab/ci-cd
Le projet de base est une API très simple en NodeJS, n'hésitez pas à lire le README pour comprendre comment fonctionne la route /auth.
Utilisez la commande pour installer les dépendances du projet :
npm install
Ensuite utilisez la commande pour lancer l'API :
npm start
Appelez-moi pour que l'on puisse valider ensemble.
Packer et AWS
3.
TP - Débuter avec AWS
Tutoriel officiel
Packer possède déjà plusieurs tutoriels officiels pour apprendre à utiliser l'outil, nous allons utiliser celui d'AWS :
https://developer.hashicorp.com/packer/tutorials/aws-get-started
Comme pour Terraform, nous avons accès à un Lab AWS pour réaliser le TP et les exercices. Attention, utilisez la même technique qu'avec Terraform pour vous identifier, avec un fichier credentials dans le dossier .aws à la racine de votre Utilisateur. Utilisez la région us-east-1. (Documentation)
Le tutoriel fait office de TP guidé pour avoir la base nécessaire pour réaliser les exercices suivants, il faut réaliser le tutoriel jusqu'aux post-processors inclus.
Exercice 1 : Installer des outils
Ajoutez des outils à notre image AMI généré pour AWS :
-
Htop, pour améliorer le monitoring
-
Git, pour ajouter des dépôts de code
-
Jq, pour formater du JSON depuis le terminal
Vérifiez ensuite en vous connectant sur votre instance EC2 en SSH que vous puissiez lancer ces différents outils.
Appelez-moi pour que l'on puisse valider ensemble.
Exercice 2 : Variables et environnements
Ajoutez une variable "node_version" :
-
La variable doit être typé.
-
La variable doit être validé pour vérifier qu'elle respecte le format x.y.z.
Ensuite, créez une variable "env" qui peut avoir les valeurs : dev
, staging
et production
et n'utilisez node_version pour Node seulement si le build est dev
ou staging
sinon il faut utiliser la version LTS en production.
Utilisez l'outil nvm pour changer facilement de version. (Documentation)
Appelez-moi pour que l'on puisse valider ensemble.
Exercice 3 : Déployer sur AWS
Créez une image machine AMI sur AWS via Packer qui doit être un serveur ubuntu utilisant Nginx pour délivrer du contenu HTML statique sur le port 80.
Ensuite, avec ce que vous avez appris sur Terraform, déployez automatiquement une instance EC2 sur le Lab AWS avec votre AMI construit avec Packer.
Appelez-moi pour que l'on puisse valider ensemble.
Exercice 4 : Healthcheck
Ajoutez dans le build de votre image AMI un test permettant de vérifier la configuration du nginx, son status et de vérifier via un healthcheck une requête sur le port 80 pour vérifier son fonctionnement directement dans le build.
Appelez-moi pour que l'on puisse valider ensemble.
Exercice 5 : Déployer sur AWS et Docker
Pour simuler plusieurs environnement entre développement et production, créez la même image machine en format AMI sur AWS et format Docker via Packer qui doit être un serveur ubuntu utilisant Nginx pour délivrer du contenu HTML statique sur le port 80.
Vérifiez que les différentes plateformes fonctionnent en lançant en local un container Docker qui utilise votre image et déployez via Terraform l'instance EC2.
Appelez-moi pour que l'on puisse valider ensemble.
Exercice 6 : Déployer sur AWS et Docker une application
Récupérez un projet que vous avez déjà réalisé et réalisez une image Docker et AMI de ce projet avec Packer.
Déployez l'image Docker et les images nécessaires pour votre projet en utilisant Terraform sur le compte AWS fournit pour cet atelier.
(Si vous n'avez pas de projet d'application, vous êtes libre de choisir une technologie ou outil déjà existant comme un Wordpress par exemple)
Appelez-moi pour que l'on puisse valider ensemble.
Exercice 7 Bonus : Mise en place d'une CI / CD
Mettez en place une CI / CD sur Gitlab CI ou Github Actions pour réaliser l'exercice précédent mais de manière automatisé en lançant une pipeline qui doit :
- Vérifier, valider, tester le code du projet
- Vérifier et valider le format et la configuration Packer.
- Vérifier et valider le format et la configuration Terraform.
- Lancer les builds ou plans.
- Lancer le déploiement.
Appelez-moi pour que l'on puisse valider ensemble.
4.
N'hésitez pas à me donner votre avis.
Merci!
Packer
By Valentin MONTAGNE
Packer
- 56