Vagrant & Ansible : L'Art du "Control Node" Automatisé
Par Nicolas DELAHAYE | v.1974 | Architecte Solution
STATUS: SSH_KEYS_DISTRIBUTED
C'est un mur que tout ingénieur DevOps rencontre tôt ou tard. Vous voulez construire un lab réaliste : Une VM "Maître" (Control Node) qui configure plusieurs VMs "Esclaves" (Workers) via Ansible.
Le problème ? Vagrant est conçu pour isoler. Par défaut, il génère une clé SSH unique par machine. Résultat : votre VM Maître ne peut pas se connecter aux Workers. La solution naïve consiste à lancer ansible_local sur chaque machine indépendamment, mais c'est un anti-pattern qui ne simule pas la réalité d'un cluster.
// Pour comprendre en détail pourquoi l'architecture ansible_local est souvent incontournable (surtout sur Windows), je vous invite à lire mon comparatif : Vagrant : Ansible vs Ansible_Local et le mythe du Control Node.
Pour réussir une Vagrant Ansible Inventory propre et automatisée, nous devons inverser la logique : générer une clé de confiance unique et construire l'inventaire dynamiquement.
1. Le concept : Une clé pour les gouverner toutes
Au lieu de laisser Vagrant gérer ses clés, nous allons créer une paire de clés "Cluster" sur l'hôte (votre PC) et la distribuer.
1. Host : Génère une paire de clés SSH (Privée/Publique).
2. Vagrant : Injecte la clé Publique dans tous les Workers.
3. Vagrant : Monte la clé Privée dans le Control Node.
4. Ruby : Génère le fichier d'inventaire
.ini automatiquement.
2. L'Implémentation dans le Vagrantfile
Voici le code complet. Il fait tout le travail sale à votre place. Pas de bidouille manuelle.
Note : Ce script écrit le fichier d'inventaire sur votre machine hôte pour qu'il soit accessible dans la VM via le dossier partagé /vagrant. Si vous rencontrez des problèmes de performance ou de permissions sur ce partage, vérifiez votre configuration de montage (voir mon article : Vagrant Synced Folders : Le casse-tête Windows vs Linux).
# 1. Génération de la clé Cluster (si absente) KEY_PATH = ".vagrant/cluster_key" unless File.exist?(KEY_PATH) system("ssh-keygen -t ed25519 -f #{KEY_PATH} -N '' -C 'vagrant-cluster'") end CLUSTER_PUBKEY = File.read("#{KEY_PATH}.pub") # 2. Préparation de l'inventaire dynamique inventory_content = ["[all:vars]", "ansible_user=vagrant", "ansible_ssh_private_key_file=/vagrant/#{KEY_PATH}", "ansible_ssh_common_args='-o StrictHostKeyChecking=no'", "", "[controllers]", "control-node ansible_host=192.168.56.10", "", "[workers]"] Vagrant.configure("2") do |config| # --- DEFINITION DES WORKERS --- (1..2).each do |i| ip = "192.168.56.2#{i}" name = "worker#{i}" config.vm.define name do |node| node.vm.box = "ubuntu/jammy64" node.vm.network "private_network", ip: ip node.vm.hostname = name # Injection de la clé publique node.vm.provision "shell", inline: "echo '#{CLUSTER_PUBKEY}' >> /home/vagrant/.ssh/authorized_keys" # Ajout à l'inventaire en mémoire inventory_content << "#{name} ansible_host=#{ip}" end end # --- DEFINITION DU CONTROL NODE --- config.vm.define "control-node" do |node| node.vm.box = "ubuntu/jammy64" node.vm.network "private_network", ip: "192.168.56.10" node.vm.hostname = "control-node" # Injection de la clé publique (pour qu'il puisse se connecter à lui-même si besoin) node.vm.provision "shell", inline: "echo '#{CLUSTER_PUBKEY}' >> /home/vagrant/.ssh/authorized_keys" # Installation d'Ansible sur le Control Node uniquement node.vm.provision "shell", inline: "apt-add-repository ppa:ansible/ansible -y && apt-get update && apt-get install ansible -y" # 3. Écriture du fichier d'inventaire sur le disque Hôte # Il sera accessible dans la VM via /vagrant/inventory.ini File.write("inventory.ini", inventory_content.join("\n")) # 4. Lancement du Playbook (Mode Parallel Execution) node.vm.provision "ansible_local" do |ansible| ansible.playbook = "playbook.yml" ansible.inventory_path = "/vagrant/inventory.ini" ansible.limit = "all" ansible.verbose = true end end end
3. Pourquoi ça change tout ?
Avec cette configuration :
- Zéro Friction : Un simple
vagrant upconstruit le cluster, les clés et lance Ansible. - Isolation Propre : Votre machine Windows/Mac ne lance pas Ansible. C'est la VM "control-node" qui le fait, via le montage
/vagrant. - Scalabilité : Changez
(1..2)en(1..10)et votre inventaire se met à jour automatiquement.
C'est la différence entre "bidouiller des scripts" et faire de l'Infrastructure as Code. Vous respectez le principe DRY (Don't Repeat Yourself) et vous préparez un environnement qui ressemble à 99% à une production réelle (Bastion + Private Subnet).