
Construire des images Incus à la main ne passe pas à l'échelle. Ce guide industrialise cette construction par deux voies : Packer avec son builder Incus, et Ansible avec le connection plugin, pour produire des images reproductibles et publiables. On y voit un template Packer complet, le playbook Ansible équivalent, et la publication de l'image dans Incus. Les commandes sont valables sur Incus 7.0.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Construire une image avec un template Packer (builder Incus).
- Faire la même chose avec un playbook Ansible.
- Publier l'instance configurée en image réutilisable.
- Choisir entre les deux approches selon le contexte.
Création d’une image personnalisée avec Packer
Section intitulée « Création d’une image personnalisée avec Packer »Dans cette section, je vais vous guider à travers le processus de création d’une image personnalisée avec Packer en utilisant le builder Incus. Ce builder permet de construire des images de conteneurs compatibles avec l’environnement Incus tout en offrant les avantages d’automatisation et de reproductibilité que Packer fournit.
Installation des prérequis
Section intitulée « Installation des prérequis »Avant de commencer, il est nécessaire d'installer Packer. Il est disponible sur le site officiel et peut être installé via des gestionnaires de paquets comme apt sur Linux, brew sur macOS, ou via un binaire sur Windows. Plus d'infos ici
Ensuite, assurez-vous qu'Incus est correctement installé et configuré dans votre environnement. Le builder Packer pour Incus a besoin qu'Incus soit accessible pour générer les images de conteneurs. Voir l'installation d'Incus au besoin.
Création du fichier de configuration Packer
Section intitulée « Création du fichier de configuration Packer »La création d’une image avec Packer repose sur un template (modèle) au format JSON ou HCL qui définit comment l’image sera construite. Voici un exemple de fichier HCL simple pour une image Incus :
packer { required_plugins { incus = { version = ">= 1.0.0" source = "github.com/bketelsen/incus" } }}
source "incus" "trixie" { image = "images:debian/13" output_image = "debian-ansible" reuse = true}
build { sources = ["incus.trixie"] provisioner "shell" { scripts = [ "scripts/debian/init.sh", ] }}Dans cet exemple, le builder Incus utilise une image de base Debian 13 pour créer une nouvelle image. Le bloc provisioner exécute des commandes qui configurent l'image pour l'usage avec Ansible.
Le script bash :
apt updateapt install -y openssh-server python3 sudouseradd -m -s /bin/bash ansiblemkdir -p /home/ansible/.sshecho 'ssh-ed25519 xxxxxxxxxxxx' > /home/ansible/.ssh/authorized_keyschown -R ansible:ansible /home/ansible/.sshchmod 600 /home/ansible/.ssh/authorized_keysecho 'ansible ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/ansiblePASSWD=$(date | md5sum | cut -c1-8)echo "ansible:$PASSWD" | chpasswdExécution du build avec Packer
Section intitulée « Exécution du build avec Packer »Pour lancer la création de l’image, il suffit d’exécuter la commande suivante dans le terminal, à partir du répertoire où se trouve le fichier de configuration HCL :
packer build debian-incus.pkr.hclPacker va alors lire le template, utiliser le builder incus pour télécharger l'image de base définie, exécuter le script de provisionnement pour configurer l’image, puis la rendre disponible localement.
Vérification de l'image générée
Section intitulée « Vérification de l'image générée »Une fois l’image créée, vous la retrouvez dans Incus en vérifiant la liste des images disponibles :
incus image list debian-ansible
+----------------+--------------+--------+--------------------------------------+--------------+-----------+-----------+----------------------+| ALIAS | FINGERPRINT | PUBLIC | DESCRIPTION | ARCHITECTURE | TYPE | SIZE | UPLOAD DATE |+----------------+--------------+--------+--------------------------------------+--------------+-----------+-----------+----------------------+| debian-ansible | 0fb77aa067dc | no | Debian trixie amd64 (20260630_05:24) | x86_64 | CONTAINER | 184.26MiB | 2026/07/01 07:59 UTC |+----------------+--------------+--------+--------------------------------------+--------------+-----------+-----------+----------------------+Options supplémentaires du builder Incus
Section intitulée « Options supplémentaires du builder Incus »En plus des options vues ci-dessus, le builder Incus offre plusieurs paramètres optionnels pour ajuster la création d'images.
reuse: Permet de réutiliser un alias d’image existant.publish_remote_name: Publie l’image sur un remote spécifique d'Incus.init_sleep: Définit le délai (en secondes) entre le lancement et le provisionnement.virtual_machine: Crée une image de machine virtuelle plutôt qu’une image de conteneur.
Ces options apportent plus de flexibilité pour des scénarios avancés. Plus d'infos ici.
Point d'attention terrain : coupler le provisioner Ansible de Packer à la connexion Incus reste fragile. Packer crée et démarre bien le conteneur, mais le provisionnement Ansible via le plugin Incus ne s'enchaîne pas toujours correctement. Quand ce couplage pose problème, une approche 100 % Ansible est plus robuste et se passe entièrement de Packer.
Création d'une image avec Ansible
Section intitulée « Création d'une image avec Ansible »On peut utiliser Ansible avec le plugin de connexion Incus pour automatiser la création et la configuration d’images directement sur des conteneurs, sans passer par Packer. Ce plugin permet à Ansible de traiter les conteneurs Incus comme des machines distantes, facilitant ainsi l’exécution des rôles et playbooks. Le fonctionnement du connection plugin est détaillé dans le guide Gérer Incus avec Ansible.
Avant, vous devez installer la collection community.general :
ansible-galaxy collection install community.generalVoici le playbook faisant les mêmes opérations que celles avec Packer.
---- name: Create instance hosts: localhost connection: local tasks: - name: Create instance ansible.builtin.shell: cmd: incus launch images:debian/13 debian-ansible creates: debian-ansible.ok - name: Create instance ansible.builtin.shell: cmd: incus start debian-ansible - name: Create flag ansible.builtin.file: path: debian-ansible.ok state: touch- name: Run command in container hosts: debian-ansible connection: community.general.incus gather_facts: false vars: pwd: "{{ lookup('password', '/dev/null length=15 chars=ascii_letters') }}" tasks: - name: Install packages ansible.builtin.raw: apt install -y python3 args: executable: /usr/bin/bash - name: Create user ansible.builtin.user: name: ansible shell: /usr/bin/bash password: "{{ pwd }}" state: present create_home: true home: /home/ansible - name: Copy SSH Key ansible.posix.authorized_key: user: ansible state: present key: "{{ lookup('file', item) }}" with_fileglob: - ~/.ssh/id_ed25519.pub - name: Add user to sudoers community.general.sudoers: user: ansible name: ansible nopassword: true commands: ALL state: present- name: Create instance hosts: localhost connection: local tasks: - name: Stop instance ansible.builtin.shell: cmd: incus stop debian-ansible removes: debian-ansible.ok - name: Create Image ansible.builtin.shell: cmd: incus publish --alias debian_ansible debian-ansible --reuse removes: debian-ansible.ok - name: Delete flag ansible.builtin.file: path: debian-ansible.ok state: absentCe code Ansible est divisé en plusieurs étapes :
-
Création d'une instance : Le code lance une instance Debian 13 avec Incus et crée un fichier de flag pour marquer la création réussie de l'instance. L'instance est ensuite démarrée.
-
Exécution de commandes dans le conteneur : Ansible se connecte à l'instance via Incus et exécute plusieurs tâches : installer Python3, créer un utilisateur ansible avec un mot de passe aléatoire, copier une clé SSH et ajouter l’utilisateur aux sudoers.
-
Création de l’image : Une fois les configurations effectuées, l’instance est arrêtée et publiée en tant qu’image nommée debian_ansible dans Incus. Le fichier de flag est supprimé.
La commande reste habituelle car j'ai mis les paramètres dans le playbook :
ansible-playbook incus.yml -i debian-ansible,L'inventaire peut aussi être peuplé dynamiquement par le plugin d'inventaire
community.general.incus, plutôt que passé en ligne de commande. Cette
construction d'image s'intègre ensuite naturellement dans un pipeline CI/CD
pour publier chaque nouvelle image automatiquement.
À retenir
Section intitulée « À retenir »- Deux voies pour industrialiser : le builder Packer Incus, ou un playbook Ansible de bout en bout.
- Le couplage Packer + provisioner Ansible reste fragile ; l'approche tout-Ansible est plus robuste.
- Le playbook lance une instance, la configure via le connection plugin, puis la publie en image.
incus publish --aliastransforme une instance arrêtée en image réutilisable.- L'image publiée apparaît dans
incus image listavec son fingerprint, sa taille et sa date.
FAQ : questions fréquentes sur l'automatisation des images Incus
Section intitulée « FAQ : questions fréquentes sur l'automatisation des images Incus »Deux voies pour industrialiser
Deux approches produisent des images reproductibles :- Packer avec son builder Incus : un template HCL décrit l'image de base et des provisioners la configurent.
- Ansible de bout en bout via le connection plugin Incus : un playbook lance, configure et publie l'instance.
incus publish
Une fois l'instance configurée et arrêtée, on la transforme en image :incus stop mon-instance
incus publish --alias mon-image mon-instance --reuse
L'option --alias nomme l'image et --reuse écrase un alias existant. L'image apparaît alors dans incus image list avec son fingerprint, sa taille et sa date, prête à servir de base à de nouvelles instances.Le connection plugin Incus
Ansible pilote un conteneur Incus sans SSH grâce au connection plugincommunity.general.incus, qui traite le conteneur comme une machine distante.On installe d'abord la collection :ansible-galaxy collection install community.general
Puis le play qui vise le conteneur déclare :connection: community.general.incus
Le détail du plugin est couvert dans le guide Gérer Incus avec Ansible.Un flux unique, plus fiable
Le couplage Packer + provisioner Ansible via le plugin Incus s'enchaîne mal : Packer crée et démarre bien le conteneur, mais le provisionnement Ansible ne se déclenche pas toujours correctement.Une approche 100 % Ansible évite ce point de rupture :- un seul outil lance l'instance, la configure et la publie ;
- le flux s'intègre naturellement dans un pipeline CI/CD ;
- l'inventaire peut être peuplé par le plugin
community.general.incus.