Aller au contenu
English
English
Infrastructure as Code medium

ansible-pull : pattern GitOps Edge / IoT (mode pull, hors RHCE EX294)

80 min de lecture

Logo Ansible

Ansible fonctionne par défaut en mode push : un control node SSH vers les cibles. Mais il existe un mode pull : la cible récupère son playbook depuis un repo Git (avec ansible-pull) et s'exécute elle-même. Pas besoin de control node centralisé. Pas besoin d'accès SSH inverse. Pas besoin d'IP publique sur la cible.

À la fin de cette page, vous saurez quand choisir pull vs push, configurer un nœud Edge avec ansible-pull + cron + cloud-init, et comprendre les limites du mode pull (pas de centralisation des logs, incompatible AAP Tower).

  • Différence push vs pull : qui initie la connexion.
  • Lancer ansible-pull manuellement contre un repo Git.
  • Configurer une exécution périodique via cron ou systemd timer.
  • Intégrer ansible-pull dans cloud-init pour qu'un nœud se configure seul au premier démarrage.
  • Comprendre les limites : logs distribués, pas d'AAP Tower, drift indétectable.
  • Choisir push vs pull selon le cas d'usage.
  • Avoir validé le Premier playbook (mode push classique).
  • Bases Git (clone, pull, branches).
CritèreMode push (default)Mode pull (ansible-pull)
Qui initie la connexion ?Control node → cibles (SSH)Cible → repo Git (HTTPS/SSH)
CentralisationOui (control node)Non (chaque nœud autonome)
Visibilité logsCentraliséeDistribuée (sur chaque nœud)
Cas d'usage typiqueDatacenter, fleet maîtriséeEdge, IoT, NAT, bootstrap
Compatible AAP TowerOuiNon (mode pur ansible-core)
FQCN, collections, vaultOuiOui
Testé à RHCE EX294OuiNon

🔍 Observation : ansible-pull utilise les mêmes playbooks qu'ansible-playbook. La différence est juste qui exécute, pas le contenu du playbook. Permet de basculer un projet push vers pull sans réécriture.

Des nœuds isolés derrière un NAT, sans IP publique, qui ne peuvent pas être joints par SSH depuis un control node central. Ils tirent leur config depuis Git :

Fenêtre de terminal
# Sur un nœud IoT (Raspberry Pi, Jetson Nano, etc.)
ansible-pull -U https://github.com/myorg/iot-config.git pull-playbook.yml

Une nouvelle VM se configure elle-même au premier boot :

#cloud-config
packages:
- ansible-core
- git
runcmd:
- ansible-pull -U https://github.com/myorg/infra.git pull-playbook.yml

Enchaînement : Terraform ou le cloud provisionne, cloud-init lance ansible-pull, la VM est prête. Aucune intervention SSH.

Ce n'est pas de l'infrastructure immuable, et la distinction n'est pas un détail de vocabulaire. Une infrastructure immuable remplace la machine à chaque changement ; ici, un cron modifie périodiquement une machine qui reste en place. Le terme juste est convergence périodique, ou gestion de configuration en mode pull : le dépôt décrit l'état désiré, et chaque nœud s'en rapproche à intervalle régulier. La différence se paie le jour d'un incident, quand on cherche à savoir si une machine a divergé ou si elle n'a jamais convergé.

Un control node centralisé exécute tout le parc, et son parallélisme est borné par forks, la RAM et le CPU. En pull, chaque nœud s'exécute indépendamment : la charge ne se concentre plus. Le seuil où cela bascule dépend de la durée des playbooks, du réseau et du matériel du control node, il n'y a pas de nombre universel à citer.

Le repo Git est la source de vérité. Chaque nœud reflète l'état de la branche. Modification → commit → push → tous les nœuds qui pull cron synchronisent dans la fenêtre suivante.

Fenêtre de terminal
sudo dnf install -y ansible-core git
ansible-pull \
-U https://github.com/stephrobert/ansible-pull-demo.git \
-d /var/lib/ansible-pull \
pull-playbook.yml

Ce que fait ansible-pull :

  1. git clone (ou git pull si déjà clôné) le repo dans /var/lib/ansible-pull/.
  2. ansible-playbook sur pull-playbook.yml avec hosts: localhost (par défaut).
  3. Exit avec le code de retour du playbook.

Options principales :

OptionEffet
-U <git-url>URL du dépôt, obligatoire
-d <chemin>Où se fait le clone, défaut /var/lib/ansible/local
-i <inventaire>Inventaire, comme ansible-playbook
-C <ref>branche, tag ou commit à sortir
--fullClone complet au lieu du clone superficiel par défaut
--verify-commitVérifie la signature GPG du commit, et abandonne si elle échoue
--check / --diffSimulation et affichage des différences, comme en push
--only-if-changedNe joue le playbook que si le dépôt a bougé
--vault-password-file <path>Compatible Ansible Vault
-K / --ask-become-passDemande le mot de passe sudo

C'est l'erreur la plus répandue sur cette commande, et elle a une conséquence directe sur la reproductibilité d'un parc. L'aide de la CLI est sans ambiguïté :

-C, --checkout CHECKOUT
branch/tag/commit to checkout. Defaults to behavior of
repository module.

Le défaut n'est donc pas main, c'est la branche par défaut du dépôt, quelle qu'elle soit. Mesuré sur un dépôt dont la branche par défaut s'appelle principale :

Fenêtre de terminal
ansible-pull -U file:///opt/depot -d /opt/cible
git -C /opt/cible rev-parse --abbrev-ref HEAD
principale

Un dépôt qui change de branche par défaut change donc la configuration de tout un parc, sans qu'aucune ligne de cron ait bougé. C'est la raison d'épingler explicitement, et de préférence sur un commit.

---
- name: Se configurer soi-même depuis le dépôt
hosts: localhost # ← cible LA MACHINE ELLE-MÊME
connection: local # ← pas de SSH (déjà sur la cible)
become: true
gather_facts: true
tasks:
- name: Marker pull executed
ansible.builtin.copy:
dest: /var/log/ansible-pull-marker.txt
content: |
ansible-pull executed at: {{ ansible_date_time.iso8601 }}
hostname: {{ ansible_hostname }}
mode: "0644"

Ce couple est le pattern normal, pas une obligation technique. La nuance compte dès qu'on sort du cas simple : ansible-pull reste un frontend à ansible-playbook et expose -i, --limit, -e et le reste. Rien n'interdit de lui passer un inventaire cloné avec le dépôt, ni de cibler un groupe.

Ce qui est vrai, c'est que la machine est la cible : viser hosts: db1.lab depuis db1.lab sans y avoir configuré de connexion échoue, faute de SSH vers elle-même. connection: local évite précisément ce détour.

Vérifier la signature du commit avant de l'exécuter

Section intitulée « Vérifier la signature du commit avant de l'exécuter »

Un nœud en pull exécute ce que le dépôt contient, sans relecture humaine. C'est la contrepartie du modèle : quiconque obtient le droit de pousser sur la branche suivie pilote toutes les machines qui la tirent, à la prochaine fenêtre de cron. --verify-commit est la seule barrière que la CLI offre contre ce scénario.

Fenêtre de terminal
ansible-pull -U https://forge.example.lan/infra.git \
-d /var/lib/ansible-pull \
-C "$COMMIT_ATTENDU" \
--verify-commit \
pull-playbook.yml

Sur un commit non signé, la commande s'arrête avant de jouer le playbook :

"msg": "Failed to verify GPG signature of commit/tag \"c2388d2...\"",
"rc": 1,

Mesuré sur la machine du lab : aucun fichier n'est déposé, la convergence n'a pas lieu. Sur un commit signé par une clé présente dans le trousseau du nœud, le playbook s'exécute normalement.

ansible-pull clone en superficiel, et cela casse l'épinglage sur un commit ancien. C'est le défaut le plus coûteux du mode pull, parce qu'il échoue sans rien changer : la machine garde la configuration précédente et rien ne le signale au niveau du parc.

Le scénario, mesuré pas à pas. Un premier passage sur une branche laisse un clone de profondeur 1 :

Fenêtre de terminal
ansible-pull -U file:///opt/depot -d /opt/cible -C experimentale
git -C /opt/cible rev-list --count HEAD # 1
test -f /opt/cible/.git/shallow && echo superficiel

Un second passage, sur le même répertoire, vers un commit plus ancien :

"msg": "Failed to checkout c2388d2...",
"stderr": "fatal: unable to read tree (c2388d2...)\n",

Le commit visé n'est pas dans le clone, puisque celui-ci ne porte qu'une révision. Et le marqueur déposé par le passage précédent est toujours là : la machine n'a pas reculé, elle est restée où elle était.

Le libellé exact de l'erreur dépend de la version de git : unable to read tree sur git 2.47, reference is not a tree sur git 2.43. Ne bâtissez pas une alerte sur cette chaîne, mais sur le code de retour.

Fenêtre de terminal
# Repartir propre quand la reference change
rm -rf /var/lib/ansible-pull
ansible-pull -U ... -C "$COMMIT" --full pull-playbook.yml
/etc/cron.d/ansible-pull
*/30 * * * * root /usr/bin/ansible-pull \
-U https://github.com/myorg/infra.git \
-d /var/lib/ansible-pull \
pull-playbook.yml \
>> /var/log/ansible-pull.log 2>&1

Via Ansible (push initial qui configure le pull) :

- name: Configurer ansible-pull en cron
ansible.builtin.cron:
name: ansible-pull
user: root
minute: "*/30"
job: >-
/usr/bin/ansible-pull
-U https://github.com/myorg/infra.git
-d /var/lib/ansible-pull
pull-playbook.yml
>> /var/log/ansible-pull.log 2>&1

🔍 Observation : pattern bootstrap puis pull, push initial pour installer ansible-core + déposer le cron. Ensuite le nœud s'auto-configure depuis le repo. L'agent reste minimaliste (juste cron + ansible-core + git).

LimitationImpact
Pas de centralisation des logsSur chaque nœud localement (/var/log/ansible-pull.log). Agréger via journalctl + rsyslog vers Loki/ELK central.
Pas d'AAP TowerAAP/Automation Controller est strictement push. Si vous voulez le UI AAP, restez en push.
Auto-update du nœud lui-mêmeRisque si un commit casse ansible-pull lui-même → nœud bloqué dans une boucle. Tester en CI avant de merger sur main.
Drift indétectable depuis le centrePas de "PLAY RECAP" agrégé. Un nœud isolé peut diverger sans alerter. Solution : exporter le code retour cron vers un health-check (Healthchecks.io, Prometheus pushgateway).
Sortie non consultéeCron tourne en arrière-plan : --check et --diff existent bien en mode pull, mais personne ne lit leur sortie. Les réserver à un lancement manuel, et router la sortie du cron vers un journal.

Choisir push (ansible-playbook classique) quand :

  • Datacenter classique avec control node maîtrisé.
  • Parc dont un control node maîtrisé reste capable d'absorber la charge.
  • Vous voulez utiliser AAP / Automation Controller.
  • Logs centralisés via le control node.
  • Workflow "lancer un déploiement maintenant sur toutes les cibles".

Choisir pull (ansible-pull) quand :

  • Nœuds Edge/IoT derrière NAT, sans IP publique.
  • Bootstrap au premier démarrage, sans control node joignable.
  • Parc où le control node devient un goulot, sans qu'un seuil universel existe.
  • Pattern GitOps strict (repo Git = source unique de vérité).
  • Pas de control node centralisé envisageable.

Le push reste le mode par défaut, et le pull répond à des contraintes précises : nœuds injoignables, absence de control node, dépôt Git comme source unique. Les deux coexistent sans difficulté dans une même organisation, push pour le datacenter, pull pour ce qui est hors de portée.

Le mode pull ne se comprend vraiment qu'en voyant une machine aller chercher elle-même sa configuration. Le lab monte un dépôt Git local et un script d'orchestration qui lance ansible-pull depuis la cible, avec le pull-playbook.yml en hosts: localhost et connection: local décrits plus haut, puis sa planification périodique. La vérification est structurelle : elle contrôle que le dépôt, le playbook et la planification sont en place, le pattern étant ici mis en œuvre plutôt que mesuré.

  • hosts: db1.lab au lieu de hosts: localhost → erreur de connexion (pas de SSH).
  • git non installé sur le nœud → ansible-pull échoue. Toujours installer ansible-core + git au bootstrap.
  • Repo privé sans deploy key → clone échoue. Déposer une clé SSH déploy via cloud-init.
  • Pas de health-check → un nœud qui plante en boucle est invisible. Ajouter un push vers Prometheus pushgateway en fin de playbook.

Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

6 questions
6 min.
70% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

  • Push = control node → cibles (SSH). Default. AAP compatible. EX294.
  • Pull = cible → repo Git. ansible-pull -U <url>. Hors EX294.
  • hosts: localhost + connection: local dans le playbook (la machine est elle-même la cible).
  • cron ou timer systemd pour la convergence périodique, cloud-init pour le premier démarrage. Ce n'est pas de l'infrastructure immuable : la machine est modifiée, pas remplacée.
  • Logs distribués, agréger via syslog/Loki/ELK pour centralisation.
  • -C ne vaut pas main mais la branche par défaut du dépôt : épinglez sur un commit si vous voulez figer un parc.
  • --verify-commit refuse un commit non signé avant d'exécuter le playbook, à condition que la clé publique soit sur le nœud.
  • Le clone est superficiel : sur un répertoire réutilisé, un SHA ancien échoue et la machine garde son état précédent. Surveillez le code de retour, pas le fait que le cron ait tourné.
  • Le push reste le mode par défaut ; le pull répond à des contraintes précises, nœuds injoignables ou absence de control node.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens ce site gratuitement, sans publicité, sans profilage et sans compte à créer. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn