Aller au contenu Skip to main content

Serveur Ansible sur ESXi pour piloter son LAN

Introduction

À partir d’un certain nombre de machines sur son réseau, se connecter en SSH sur chacune pour faire une mise à jour ou changer un fichier de config devient franchement pénible. Tu le fais une fois, deux fois, et le troisième tu oublies une machine. C’est là qu’Ansible change la donne.

L’idée est simple : une seule machine, le Control Node, parle à toutes les autres via SSH. Pas d’agent à installer, pas de daemon à gérer côté cibles. Tu écris un playbook, tu le lances, et Ansible s’occupe du reste sur l’ensemble de ton parc en parallèle.

Je mets le Control Node dans une VM dédiée sur ESXi — c’est propre, isolé, et ça tourne 24h/24 sans toucher à mes autres machines.

flowchart LR
    subgraph ESXi["Serveur ESXi"]
        VM_ANS["VM Ansible\nControl Node\nUbuntu 24.04"]
    end

    subgraph LAN["Réseau Local (192.168.1.0/24)"]
        SRV1["Serveur 1\nDebian 12\n.10"]
        SRV2["Serveur 2\nUbuntu 22.04\n.11"]
        SRV3["NAS\nTrueNAS\n.20"]
        SRV4["Cluster K8s\nNœuds\n.30-.32"]
        WIN["PC Windows\n.50"]
    end

    VM_ANS -->|SSH| SRV1
    VM_ANS -->|SSH| SRV2
    VM_ANS -->|SSH| SRV3
    VM_ANS -->|SSH| SRV4
    VM_ANS -->|WinRM| WIN

    style VM_ANS fill:#e67e22,color:#fff
    style SRV1 fill:#3498db,color:#fff
    style SRV2 fill:#3498db,color:#fff
    style SRV3 fill:#2ecc71,color:#fff
    style SRV4 fill:#9b59b6,color:#fff
    style WIN fill:#1a5276,color:#fff

Résumé des étapes

  1. Créer la VM sur ESXi (Configuration minimale)
  2. Installer Ubuntu Server 24.04
  3. Configurer le réseau (IP fixe, accès LAN)
  4. Installer Ansible
  5. Structurer le projet (Inventaire, playbooks, config)
  6. Déclarer les machines du LAN (Inventaire)
  7. Distribuer les clés SSH (Authentification sans mot de passe)
  8. Tester la connectivité (Premier ping Ansible)
  9. Premiers Playbooks (Mise à jour, durcissement SSH)
  10. Gérer les secrets (Ansible Vault)

C’est Parti ! 🚀

Étape 1 : Créer la VM sur ESXi

Connecte-toi à l’interface web de ton ESXi (https://<IP_ESXI>), puis navigue vers Virtual Machines > Create / Register VM.

Configuration recommandée

ParamètreValeur
Nomansible-control
OSLinux — Ubuntu Linux (64-bit)
CPU2 vCPU
RAM2 Go (Ansible est léger, c’est largement suffisant)
Disque20 Go (thin provisioned)
RéseauVM Network — bridge sur le LAN

Flux de création dans ESXi

flowchart TD
    A["Interface Web ESXi\nhttps://ip-esxi"] --> B["Virtual Machines\n> Create / Register VM"]
    B --> C["Create a new virtual machine"]
    C --> D["Nom : ansible-control\nOS : Ubuntu Linux 64-bit"]
    D --> E["Choisir le Datastore"]
    E --> F["CPU : 2 vCPU\nRAM : 2 Go\nDisque : 20 Go Thin"]
    F --> G["Réseau : VM Network\n(bridge sur le LAN)"]
    G --> H["Attacher l'ISO Ubuntu\ndepuis le Datastore"]
    H --> I["Finaliser & Démarrer"]

    style A fill:#1a5276,color:#fff
    style I fill:#2ecc71,color:#fff

Uploader l’ISO Ubuntu

Si l’ISO n’est pas encore sur le datastore, c’est rapide :

  1. Va dans Storage > Datastore browser
  2. Crée un dossier ISOs
  3. Clique sur Upload et dépose l’ISO Ubuntu Server 24.04

Étape 2 : Installer Ubuntu Server 24.04

Démarre la VM et suis l’installateur. Quelques choix importants à ne pas rater :

  • Type d’installation : Ubuntu Server (sans interface graphique, on n’en a pas besoin)
  • Nom d’hôte : ansible-control
  • Utilisateur : crée un compte, par exemple ansible
  • OpenSSH : coche Install OpenSSH server — on en aura besoin pour administrer la VM à distance

Pour les snaps supplémentaires proposés à la fin, passe tout, rien n’est utile ici.


Étape 3 : Configurer le réseau (IP fixe)

Si tu n’as pas configuré l’IP fixe pendant l’installation, voilà comment le faire via Netplan, le gestionnaire réseau d’Ubuntu Server.

D’abord, identifie le nom de ta carte réseau :

Fenêtre de terminal
ip a
# Tu cherches quelque chose comme : ens192, eth0, ens33...

Édite ensuite la config Netplan :

Fenêtre de terminal
sudo nano /etc/netplan/00-installer-config.yaml
network:
version: 2
ethernets:
ens192: # Remplace par ton nom d'interface
dhcp4: false
addresses:
- 192.168.1.5/24 # L'IP fixe du Control Node
routes:
- to: default
via: 192.168.1.1 # Ta passerelle (box/routeur)
nameservers:
addresses:
- 192.168.1.1
- 8.8.8.8

Applique et vérifie :

Fenêtre de terminal
sudo netplan apply
ping -c 3 8.8.8.8

Étape 4 : Installer Ansible

Sur la VM ansible-control :

Fenêtre de terminal
# Mise à jour du système
sudo apt update && sudo apt upgrade -y
# Ajout du dépôt officiel Ansible (PPA)
sudo apt install -y software-properties-common
sudo add-apt-repository --yes --update ppa:ansible/ansible
# Installation
sudo apt install -y ansible
# Vérification
ansible --version

Tu devrais voir quelque chose comme :

ansible [core 2.17.x]
config file = /etc/ansible/ansible.cfg
python version = 3.12.x

Étape 5 : Structurer le projet Ansible

Plutôt que de travailler dans /etc/ansible/ (qui demande les droits root à chaque fois), crée un répertoire de projet dans ton home. C’est plus propre et tout est versionnable avec Git.

Fenêtre de terminal
mkdir -p ~/ansible/{inventory,playbooks,roles,group_vars,host_vars}
cd ~/ansible

Architecture du projet

flowchart TD
    ROOT["📁 ~/ansible/"] --> INV["📁 inventory/\nhosts.ini"]
    ROOT --> PB["📁 playbooks/\nsite.yml\nupdate.yml"]
    ROOT --> GV["📁 group_vars/\nall.yml\nwebservers.yml"]
    ROOT --> HV["📁 host_vars/\nserveur1.yml"]
    ROOT --> ROLES["📁 roles/\nnginx/\ndocker/"]
    ROOT --> CFG["⚙️ ansible.cfg"]

    INV -->|"Déclare les\nmachines"| PB
    GV -->|"Variables\npar groupe"| PB
    HV -->|"Variables\npar hôte"| PB
    ROLES -->|"Tâches\nréutilisables"| PB

    style ROOT fill:#1565C0,color:#fff
    style INV fill:#2E7D32,color:#fff
    style PB fill:#E65100,color:#fff
    style GV fill:#6A1B9A,color:#fff
    style HV fill:#6A1B9A,color:#fff
    style ROLES fill:#37474F,color:#fff
    style CFG fill:#546E7A,color:#fff

Créer le fichier de configuration

Le fichier ansible.cfg évite d’avoir à répéter les options à chaque commande :

Fenêtre de terminal
cat > ~/ansible/ansible.cfg << 'EOF'
[defaults]
inventory = ~/ansible/inventory/hosts.ini
remote_user = ansible
private_key_file = ~/.ssh/id_ed25519
host_key_checking = False
stdout_callback = yaml
deprecation_warnings = False
[privilege_escalation]
become = True
become_method = sudo
become_user = root
EOF

Étape 6 : Déclarer les machines du LAN (Inventaire)

L’inventaire, c’est la liste de toutes les machines qu’Ansible peut piloter. On les organise en groupes logiques pour pouvoir cibler “tous les serveurs Linux” ou “uniquement le cluster K8s” d’une seule commande.

Fenêtre de terminal
nano ~/ansible/inventory/hosts.ini
~/ansible/inventory/hosts.ini
[linux_servers]
serveur1 ansible_host=192.168.1.10
serveur2 ansible_host=192.168.1.11
nas ansible_host=192.168.1.20
[kubernetes]
k8s-master ansible_host=192.168.1.30
k8s-worker1 ansible_host=192.168.1.31
k8s-worker2 ansible_host=192.168.1.32
[windows]
pc-windows ansible_host=192.168.1.50
ansible_user=Administrateur
ansible_password=VotreMotDePasse
ansible_connection=winrm
ansible_winrm_transport=basic
ansible_winrm_server_cert_validation=ignore
# Groupe parent qui regroupe tout ce qui est Linux
[linux:children]
linux_servers
kubernetes
[linux:vars]
ansible_user=ansible
ansible_python_interpreter=/usr/bin/python3

Vue logique de l’inventaire

flowchart TD
    ALL["Groupe : all"] --> LINUX["Groupe : linux"]
    ALL --> WIN["Groupe : windows"]

    LINUX --> LINUXSRV["Groupe : linux_servers"]
    LINUX --> K8S["Groupe : kubernetes"]

    LINUXSRV --> SRV1["serveur1\n192.168.1.10"]
    LINUXSRV --> SRV2["serveur2\n192.168.1.11"]
    LINUXSRV --> NAS["nas\n192.168.1.20"]

    K8S --> MASTER["k8s-master\n192.168.1.30"]
    K8S --> WK1["k8s-worker1\n192.168.1.31"]
    K8S --> WK2["k8s-worker2\n192.168.1.32"]

    WIN --> WINPC["pc-windows\n192.168.1.50"]

    style ALL fill:#1565C0,color:#fff
    style LINUX fill:#2E7D32,color:#fff
    style WIN fill:#1a5276,color:#fff
    style K8S fill:#6A1B9A,color:#fff
    style LINUXSRV fill:#2E7D32,color:#fff

Étape 7 : Distribuer les clés SSH

Ansible se connecte via SSH. On utilise des clés SSH plutôt que des mots de passe — c’est plus sûr et ça permet l’automatisation complète sans interaction humaine.

Générer une paire de clés sur le Control Node

Fenêtre de terminal
ssh-keygen -t ed25519 -C "ansible-control" -f ~/.ssh/id_ed25519
# Laisse la passphrase vide (Entrée deux fois)

Créer l’utilisateur ansible sur les machines cibles

Sur chaque machine cible, à faire manuellement une seule fois :

Fenêtre de terminal
sudo useradd -m -s /bin/bash ansible
echo "ansible ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/ansible
sudo chmod 440 /etc/sudoers.d/ansible

Distribuer la clé publique

Fenêtre de terminal
ssh-copy-id -i ~/.ssh/id_ed25519.pub ansible@192.168.1.10
ssh-copy-id -i ~/.ssh/id_ed25519.pub ansible@192.168.1.11
ssh-copy-id -i ~/.ssh/id_ed25519.pub ansible@192.168.1.20
# ... pour chaque machine Linux du LAN

Ce qui se passe lors de la connexion

sequenceDiagram
    participant A as Control Node<br/>(ansible-control)
    participant T as Machine Cible<br/>(serveur1)

    Note over A: Clé privée : ~/.ssh/id_ed25519
    Note over T: Clé publique dans ~/.ssh/authorized_keys

    A->>T: Connexion SSH (utilisateur: ansible)
    T->>A: Challenge cryptographique
    A->>T: Signature avec clé privée
    T->>T: Vérifie avec clé publique
    T->>A: Accès accordé ✅
    A->>T: Exécute les tâches Ansible via SSH

Étape 8 : Tester la connectivité

Avant d’écrire quoi que ce soit, vérifie que tout est bien en place. La commande ping d’Ansible ne fait pas un vrai ping réseau — elle vérifie que le Control Node arrive à se connecter en SSH et à exécuter du Python sur la cible.

Fenêtre de terminal
cd ~/ansible
ansible all -m ping

Si tout va bien, tu dois voir ça pour chaque machine :

serveur1 | SUCCESS => {
"changed": false,
"ping": "pong"
}

Si une machine répond UNREACHABLE, le mode verbose te donnera exactement ce qui coince :

Fenêtre de terminal
ansible serveur1 -m ping -vvv

Tu peux aussi tester uniquement un groupe :

Fenêtre de terminal
ansible linux_servers -m ping

Étape 9 : Premiers Playbooks

Place maintenant aux choses concrètes. Voici deux playbooks directement utiles pour piloter un LAN.

Playbook 1 : Mise à jour de toutes les machines Linux

Fenêtre de terminal
nano ~/ansible/playbooks/update_all.yml
---
- name: Mettre à jour tous les systèmes Linux du LAN
hosts: linux
become: yes
gather_facts: yes
tasks:
- name: Mettre à jour le cache APT (Debian/Ubuntu)
apt:
update_cache: yes
cache_valid_time: 3600
when: ansible_os_family == "Debian"
- name: Mettre à jour tous les paquets (Debian/Ubuntu)
apt:
upgrade: dist
autoremove: yes
autoclean: yes
when: ansible_os_family == "Debian"
- name: Mettre à jour tous les paquets (RedHat/Rocky)
dnf:
name: "*"
state: latest
when: ansible_os_family == "RedHat"
- name: Vérifier si un redémarrage est nécessaire
stat:
path: /var/run/reboot-required
register: reboot_required
- name: Notifier si redémarrage requis
debug:
msg: "⚠️ {{ inventory_hostname }} nécessite un redémarrage !"
when: reboot_required.stat.exists
Fenêtre de terminal
ansible-playbook ~/ansible/playbooks/update_all.yml

Playbook 2 : Durcir SSH sur tout le LAN

---
- name: Durcir la configuration SSH sur toutes les machines Linux
hosts: linux
become: yes
tasks:
- name: Désactiver l'authentification par mot de passe SSH
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?PasswordAuthentication'
line: 'PasswordAuthentication no'
state: present
notify: Redémarrer SSH
- name: Désactiver le login root par SSH
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?PermitRootLogin'
line: 'PermitRootLogin no'
state: present
notify: Redémarrer SSH
- name: Définir le timeout d'inactivité (5 minutes)
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?ClientAliveInterval'
line: 'ClientAliveInterval 300'
state: present
notify: Redémarrer SSH
handlers:
- name: Redémarrer SSH
service:
name: sshd
state: restarted

Ce qui se passe quand tu lances un playbook

flowchart TD
    CMD["ansible-playbook update_all.yml"] --> PARSE["Ansible parse le Playbook\net charge l'inventaire"]
    PARSE --> FACTS["Collecte des Facts sur chaque hôte\n(OS, IP, RAM...)"]
    FACTS --> TASK1["Tâche 1 : Mettre à jour le cache APT\n→ Exécuté en parallèle sur tous les hôtes"]
    TASK1 --> COND{"when:\nansible_os_family == Debian ?"}
    COND -->|"Oui → Ubuntu/Debian"| TASK2A["apt update dist-upgrade"]
    COND -->|"Non → Rocky/RedHat"| TASK2B["dnf upgrade"]
    TASK2A --> CHECK["Vérifier /var/run/reboot-required"]
    TASK2B --> CHECK
    CHECK --> REPORT["Rapport final\nchanged / ok / failed par hôte"]

    style CMD fill:#e67e22,color:#fff
    style FACTS fill:#3498db,color:#fff
    style COND fill:#f39c12,color:#000
    style TASK2A fill:#2ecc71,color:#fff
    style TASK2B fill:#2ecc71,color:#fff
    style REPORT fill:#1a5276,color:#fff

Étape 10 : Gérer les secrets avec Ansible Vault

Ne jamais mettre de mots de passe en clair dans les fichiers d’inventaire ou de variables. Ansible Vault chiffre les données sensibles directement dans tes fichiers YAML.

Fenêtre de terminal
# Crée un fichier de secrets chiffré
ansible-vault create ~/ansible/group_vars/all/secrets.yml

L’éditeur s’ouvre, tu peux y mettre tes secrets :

db_password: "MonMotDePasseDB_SuperSecret"
api_key: "sk-xxxxxxxxxxxxxxxxxxxx"
nas_password: "MotDePasseNAS"

Pour lancer un playbook qui utilise ces secrets :

Fenêtre de terminal
# Demande le mot de passe du vault à l'exécution
ansible-playbook playbooks/site.yml --ask-vault-pass
# Ou stocke le mot de passe dans un fichier dédié (chmod 600 obligatoire)
echo "MonMotDePasseVault" > ~/.vault_pass
chmod 600 ~/.vault_pass
ansible-playbook playbooks/site.yml --vault-password-file ~/.vault_pass

Vue d’ensemble : comment tout s’articule

flowchart TD
    subgraph DEV["Ton PC (développement)"]
        ED["Éditeur de code\n(VS Code + Extension Ansible)"]
        GIT["Git\nVersionner les playbooks"]
    end

    subgraph ESXi["Serveur ESXi"]
        subgraph VM["VM : ansible-control\n192.168.1.5"]
            ANS["Ansible Core"]
            INV["inventory/hosts.ini"]
            PB["playbooks/*.yml"]
            VAULT["Ansible Vault\n(secrets chiffrés)"]
        end
    end

    subgraph LAN["LAN 192.168.1.0/24"]
        L1["serveur1\n.10"]
        L2["serveur2\n.11"]
        NAS["NAS\n.20"]
        K8S["Cluster K8s\n.30-.32"]
    end

    ED -->|"SSH / Push"| VM
    GIT -->|"git pull"| VM
    ANS --> INV
    ANS --> PB
    ANS --> VAULT
    ANS -->|"SSH"| L1
    ANS -->|"SSH"| L2
    ANS -->|"SSH"| NAS
    ANS -->|"SSH"| K8S

    style ED fill:#546E7A,color:#fff
    style GIT fill:#e74c3c,color:#fff
    style VM fill:#e67e22,color:#fff
    style ANS fill:#e67e22,color:#fff
    style INV fill:#2E7D32,color:#fff
    style PB fill:#E65100,color:#fff
    style VAULT fill:#6A1B9A,color:#fff
    style L1 fill:#3498db,color:#fff
    style L2 fill:#3498db,color:#fff
    style NAS fill:#2ecc71,color:#fff
    style K8S fill:#9b59b6,color:#fff

Quelques habitudes à prendre

Versionne tes playbooks avec Git. Ton infrastructure est du code. Un git commit après chaque modification, comme pour n’importe quel projet.

Organise l’inventaire par service, pas par machine. Des groupes databases, webservers, monitoring sont bien plus utiles que serveur1, serveur2.

Fais des snapshots ESXi du Control Node. Si tu perds la VM Ansible, tu perds le moyen de gérer tout ton LAN d’un coup. Un snapshot hebdomadaire coûte peu et peut te sauver.

Automatise les mises à jour avec cron. Une fois que le playbook de mise à jour tourne bien, planifie-le sur le Control Node :

Fenêtre de terminal
# Mise à jour tous les dimanches à 3h du matin
0 3 * * 0 /usr/bin/ansible-playbook ~/ansible/playbooks/update_all.yml >> /var/log/ansible-updates.log 2>&1

Conclusion

Le serveur Ansible sur ESXi devient rapidement indispensable dans un homelab. Ce qui prenait une heure de connexions SSH manuelles se réduit à une commande. Et comme tout est dans des fichiers YAML versionnés, tu sais exactement dans quel état sont tes machines à tout moment.

Pour aller plus loin sur les playbooks, les rôles et les fonctionnalités avancées d’Ansible, consulte l’article Maîtriser les Playbooks Ansible.