
Ansible et Incus se rejoignent sur deux usages qu'il faut bien distinguer : configurer l'intérieur d'instances déjà là (le connection plugin community.general.incus, qui passe par incus exec sans SSH), et créer les instances elles-mêmes (le provisioning). Ce guide déroule les deux, avec un point d'honnêteté important : il n'existe pas de module Ansible natif dédié à Incus, on provisionne via lxd_container. Tout est testé sur Incus 7.0 avec Ansible core 2.19 et community.general 11.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- La différence entre connection plugin et provisioning.
- Gérer une instance existante avec
community.general.incus(sans SSH). - Créer une instance Incus via
community.general.lxd_container. - L'état réel des modules Ansible pour Incus.
Prérequis
Section intitulée « Prérequis »- Ansible installé avec la collection
community.general(fournie avec le paquetansiblecomplet, sinonansible-galaxy collection install community.general). - Le client
incussur la machine qui exécute Ansible : les deux approches passent par lui (incus exec, socket local). - Des bases d'Incus : voir Premiers pas avec Incus.
Deux usages à ne pas confondre
Section intitulée « Deux usages à ne pas confondre »Avant de coder, il faut choisir le bon outil selon le besoin. Le tableau ci-dessous résume la répartition, qui structure tout le reste du guide.
| Besoin | Outil | Comment |
|---|---|---|
| Configurer l'intérieur d'une instance existante | Connection plugin community.general.incus | Ansible fait incus exec, pas de SSH |
| Créer / supprimer une instance | Module community.general.lxd_container | Via l'API, socket Incus explicite |
| Construire une image | Packer + Ansible | Voir le guide dédié |
Gérer une instance existante (connection plugin)
Section intitulée « Gérer une instance existante (connection plugin) »Le plugin community.general.incus traite une instance comme une machine distante, mais sans SSH : chaque tâche est exécutée via incus exec. C'est idéal pour appliquer une configuration à un conteneur déjà lancé.
L'inventaire déclare la connexion et le nom de l'instance côté Incus.
all: hosts: tf-web: ansible_connection: community.general.incus ansible_incus_remote: local ansible_incus_project: default ansible_incus_host: tf-web ansible_user: rootLe playbook installe d'abord Python si besoin (via raw, qui ne dépend pas de Python), puis applique des tâches normales.
- name: Configurer une instance existante via incus hosts: tf-web gather_facts: false tasks: - name: S'assurer que python3 est présent ansible.builtin.raw: command -v python3 || (apt-get update -qq && apt-get install -y -qq python3) changed_when: false
- name: Déposer un fichier témoin ansible.builtin.copy: content: "géré par ansible via le connection plugin incus\n" dest: /root/ansible-marker.txt mode: "0644"L'exécution passe par incus exec et non par le réseau : aucune clé SSH, aucun port ouvert dans l'instance.
PLAY [Configurer une instance existante via incus] *****TASK [S'assurer que python3 est présent] ***************TASK [Déposer un fichier témoin] ***********************tf-web : ok=3 changed=2 unreachable=0 failed=0Provisionner une instance (lxd_container)
Section intitulée « Provisionner une instance (lxd_container) »Pour créer une instance, on utilise le module community.general.lxd_container. Ce module cible LXD par défaut : pour viser Incus, il faut pointer explicitement son socket avec url: unix:/var/lib/incus/unix.socket.
- name: Provisionner une instance Incus hosts: localhost connection: local gather_facts: false tasks: - name: Créer et démarrer ans-web sur Incus community.general.lxd_container: name: ans-web url: unix:/var/lib/incus/unix.socket state: started source: type: image mode: pull server: https://images.linuxcontainers.org protocol: simplestreams alias: debian/13 profiles: ["default"] wait_for_ipv4_addresses: true timeout: 150Le module est idempotent : un second passage ne recrée rien. L'instance apparaît côté Incus, ici placée sur node2 du cluster.
localhost : ok=2 changed=1 unreachable=0 failed=0
+---------+---------+-----------+----------+| NAME | STATE | TYPE | LOCATION |+---------+---------+-----------+----------+| ans-web | RUNNING | CONTAINER | node2 |+---------+---------+-----------+----------+À retenir
Section intitulée « À retenir »- Deux usages distincts : configurer l'intérieur (connection plugin) vs créer (provisioning).
community.general.incusexécute les tâches viaincus exec, sans SSH.- Une image
images:minimale exige d'installer Python enrawavant les modules. - On provisionne avec
lxd_container+url: unix:/var/lib/incus/unix.socket. - Pas de module Incus natif officiel :
lxd_container, ou la CLI/API en direct.
FAQ : questions fréquentes sur Ansible et Incus
Section intitulée « FAQ : questions fréquentes sur Ansible et Incus »Le connection plugin community.general.incus
Le plugin traite l'instance comme une machine distante mais passe parincus exec, pas par SSH.all:
hosts:
tf-web:
ansible_connection: community.general.incus
ansible_incus_remote: local
ansible_incus_project: default
ansible_incus_host: tf-web
ansible_user: root
Aucune clé SSH, aucun port ouvert dans l'instance. Les tâches s'exécutent directement dans le conteneur.Pas de module natif officiel
Il n'existe pas de moduleincus_container ou incus_instance officiel dans community.general. Le support Incus passe par lxd_container (endpoint API unifié /1.0/instances) avec le url surchargé :community.general.lxd_container:
name: ans-web
url: unix:/var/lib/incus/unix.socket
state: started
Des collections tierces proposent des modules natifs, mais non officiels. Pour le réseau ou les profils, piloter la CLI (ansible.builtin.command) ou l'API (ansible.builtin.uri).Provisionner avec lxd_container
community.general.lxd_container:
name: ans-web
url: unix:/var/lib/incus/unix.socket
state: started
source:
type: image
mode: pull
server: https://images.linuxcontainers.org
protocol: simplestreams
alias: debian/13
profiles: ["default"]
wait_for_ipv4_addresses: true
Le module est idempotent : un second passage ne recrée rien. L'instance apparaît côté Incus, placée automatiquement sur un nœud du cluster.Installer Python en raw d'abord
Les imagesimages: sont minimales et n'ont pas toujours Python, dont les modules Ansible ont besoin. La parade : une première tâche en raw (exécutée par /bin/sh, sans Python) :- name: S'assurer que python3 est présent
ansible.builtin.raw: command -v python3 || (apt-get update -qq && apt-get install -y -qq python3)
changed_when: false
Sans cela, les modules copy ou command échouent sur un interpréteur introuvable.