Aller au contenu

Inventaire Ansible

Organisation de l'inventaire Ansible pour les déploiements multi-environnement, multi-provider, et pilotage de l'état desire depuis l'inventaire.


Convention d'arborescence

L'inventaire suit une arborescence a 4 niveaux :

env / provider-region / topology / project

inventory/
├── dev/
│   └── vsphere-paris/
│       ├── internet/
│       │   └── alpha/
│       │       ├── hosts.yml
│       │       └── group_vars/
│       │           └── all/
│       │               ├── vars.yml
│       │               └── vault.yml
│       ├── extranet/
│       ├── intranet/
│       ├── sandbox/
│       ├── webapp/
│       └── engineering/
├── staging/
│   └── gcp-europe-west1/
│       └── webapp/
│           └── alpha/
│               ├── hosts.yml
│               └── group_vars/
│                   └── all/
│                       ├── vars.yml
│                       └── vault.yml
└── prod/
    ├── vsphere-lyon/
    │   └── intranet/
    │       └── alpha/
    └── aws-eu-west-1/
        └── internet/
            └── beta/

Description des 4 niveaux

Niveau Valeurs typiques Rôle
Environnement dev, staging, prod Cycle de vie de l'application
Provider-region vsphere-paris, gcp-europe-west1, aws-eu-west-1 Infrastructure et localisation géographique
Topologie internet, intranet, sandbox, webapp Zone réseau et niveau de sécurité
Projet alpha, beta, nom de l'application Service cible avec ses hosts et group_vars

Topologies disponibles

Topologie Exposition Usage
internet Public (DMZ) Services exposes sur Internet
extranet Restreint Accès partenaires, fournisseurs
intranet Interne Services internes a consommer
sandbox Isole POC, tests, environnements jetables
webapp Applicatif Front-end applicatif
engineering Dev / CI Outils de développement, exploration

Héritage des variables

Les group_vars places à chaque niveau de l'arborescence permettent l'héritage par surchargé. Les variables se surchargent du plus général au plus spécifique.

Ordre de precedence

  1. inventory/prod/group_vars/all.yml — variables communes à tout l'environnement prod
  2. inventory/prod/vsphere-lyon/group_vars/all.yml — variables spécifiques au provider
  3. inventory/prod/vsphere-lyon/intranet/group_vars/all.yml — variables de la topologie
  4. inventory/prod/vsphere-lyon/intranet/alpha/group_vars/all.yml — variables du projet

Exemple concret

# inventory/prod/group_vars/all.yml
log_retention_days: 30
ntp_servers:
  - ntp1.example.com
  - ntp2.example.com
# inventory/prod/vsphere-lyon/intranet/alpha/group_vars/all.yml
# Surcharge : le projet alpha conserve les logs 90 jours pour conformite
log_retention_days: 90

Ansible résout la variable en appliquant la valeur la plus spécifique. L'hôte srv-01 appartenant au projet alpha recevra log_retention_days: 90 ; tous les autres hôtes prod recevront la valeur par défaut 30.


Piloter les rôles par l'inventaire

Le pattern fondamental : l'état desire est défini dans l'inventaire, pas dans le playbook. Le playbook reste générique et délégué la décision à l'inventaire.

Niveaux de surchargé de l'état

Les variables d'état peuvent être définies a quatre niveaux, du moins au plus prioritaire :

  1. all.vars dans hosts.yml — valeur par défaut pour tous les hôtes
  2. Variables de groupe (children) — valeur pour un groupe d'hôtes
  3. Variables d'hôte (hosts) — valeur pour un hôte spécifique
  4. Extra-vars CLI (-e) — surchargé opérationnelle au moment de l'exécution

Exemple d'inventaire avec pilotage d'état

# inventory/prod/aws-eu-west-1/internet/beta/hosts.yml
all:
  vars:
    remote_users_fact_state: present
  children:
    prod_servers:
      hosts:
        srv-01: {}
        srv-02: {}
    dev_servers:
      hosts:
        dev-01:
          remote_users_fact_state: noop
    legacy:
      vars:
        remote_users_fact_state: absent

Dans cet exemple :

  • srv-01 et srv-02 heritent de all.vars : état present
  • dev-01 surchargé au niveau hôte : état noop (aucune action)
  • Le groupe legacy surchargé au niveau groupe : état absent (desinstallation)

Playbook générique correspondant

# playbooks/remote_users_fact.yml
---
- name: Gerer le role remote_users_fact
  hosts: all
  roles:
    - nuevolia.identity.remote_users_fact

Le playbook ne contient aucune logique d'état. L'inventaire porte l'intention opérationnelle.

noop comme valeur par défaut sur dev

Définir remote_users_fact_state: noop sur les hôtes de développement garantit qu'aucune action destructive ne se produit si un playbook de production est exécuté par erreur sur un mauvais inventaire. C'est une sécurité de dernier recours qui ne remplacé pas le contrôle d'accès, mais qui en réduit l'impact.


Secrets dans l'inventaire

Stratégie a deux niveaux selon la nature et le cycle de vie du secret.

Ansible Vault (secrets de bootstrap)

Les credentials provider et les tokens initiaux vivent dans des fichiers vault.yml chiffres par Ansible Vault, co-localises avec les group_vars du niveau concerne.

inventory/prod/vsphere-lyon/
└── group_vars/
    └── all/
        ├── vars.yml     # variables en clair
        └── vault.yml    # secrets vault (credentials vCenter, tokens)
# Creer un fichier vault
ansible-vault create inventory/prod/vsphere-lyon/group_vars/all/vault.yml

# Editer un fichier vault existant
ansible-vault edit inventory/prod/vsphere-lyon/group_vars/all/vault.yml

# Executer un playbook avec vault ID par environnement
ansible-playbook -i inventory/prod/ playbook.yml --vault-id prod@prompt
ansible-playbook -i inventory/staging/ playbook.yml --vault-id staging@prompt

Secret manager externe (secrets applicatifs)

Les secrets applicatifs (mots de passe BDD, API keys, certificats) sont gérés dans OpenBao et injectes via le plugin de lookup community.hashi_vault.hashi_vault :

# Dans un role ou un playbook
vars:
  db_password: "{{ lookup('community.hashi_vault.hashi_vault',
                           'secret/data/prod/db password') }}"
  api_key: "{{ lookup('community.hashi_vault.hashi_vault',
                       'secret/data/prod/api token') }}"

Répartition des secrets par type

Type de secret Stockage Exemple
Credentials provider Ansible Vault Mot de passe vCenter, access key AWS
Tokens de bootstrap Ansible Vault Token initial OpenBao, clé de chiffrement
Secrets applicatifs OpenBao via lookup Mot de passe BDD, API keys
Certificats TLS OpenBao + nuevolia.identity.tls_certificates TLS serveur, mTLS inter-services

Facts statiques et dynamiques

Deux sources complementaires alimentent les facts disponibles dans les playbooks.

Facts statiques dans group_vars

Les facts statiques décrivent le contexte fixe de la topologie : réseau, sécurité, politique de hardening. Ils sont définis dans les group_vars du niveau topologie ou projet.

# inventory/prod/vsphere-lyon/intranet/group_vars/all.yml
network_vlan: 120
network_gateway: "10.1.120.1"
network_dns_servers:
  - "10.1.0.53"
  - "10.1.0.54"
network_domain: "intranet.lyon.example.com"
hardening_level: strict
ntp_servers:
  - "10.1.0.123"
  - "10.1.0.124"

Facts dynamiques via plugins d'inventaire

Les facts dynamiques sont collectes automatiquement par le plugin d'inventaire du provider. Ils décrivent l'état courant des ressources : adresses IP, tags, état de la VM, métriques.

vSphere avec community.vmware.vmware_vm_inventory :

# inventory/prod/vsphere-lyon/vsphere.yml
plugin: community.vmware.vmware_vm_inventory
hostname: "vcenter.lyon.example.com"
validate_certs: false
with_nested_properties: true
keyed_groups:
  - key: config.guestId
    prefix: os
  - key: guest.net[0].network
    prefix: network
  - key: customValue[?(@.key == 'role')].value
    prefix: role

GCP avec google.cloud.gcp_compute :

# inventory/staging/gcp-europe-west1/gcp.yml
plugin: google.cloud.gcp_compute
projects:
  - mon-projet-staging
regions:
  - europe-west1
auth_kind: serviceaccount
service_account_file: /opt/ansible/sa-staging.json
keyed_groups:
  - key: labels.env
    prefix: env
  - key: labels.role
    prefix: role
  - key: status
    prefix: status

Vérification de l'inventaire

# Lister tous les hotes avec leurs variables
ansible-inventory -i inventory/prod/ --list

# Afficher l'arborescence des groupes
ansible-inventory -i inventory/prod/ --graph

# Inspecter un hote specifique
ansible-inventory -i inventory/prod/ --host srv-01

Réutilisation des facts dans d'autres playbooks

Un fact collecte et mis en cache peut conditionner l'exécution d'un playbook différent. Le pattern repose sur une clause de garde sur ansible_local avant toute action.

Clause de garde sur ansible_local

- name: Verifier la presence du fact avant de continuer
  ansible.builtin.assert:
    that:
      - ansible_local.remote_users_fact is defined
    fail_msg: >-
      Le fact remote_users_fact est absent. Executer le role
      nuevolia.identity.remote_users_fact avant ce playbook.

Exemple 1 : bloquer un déploiement si trop de sessions actives

- name: Lire le nombre de sessions actives
  ansible.builtin.set_fact:
    active_sessions: "{{ ansible_local.remote_users_fact.active_sessions | default(0) }}"

- name: Refuser le deploiement si les sessions actives depassent le seuil
  ansible.builtin.fail:
    msg: >-
      Deploiement annule : {{ active_sessions }} sessions actives
      (seuil : {{ deploy_max_active_sessions }}).
      Attendre la fin des sessions avant de relancer.
  when: active_sessions | int > deploy_max_active_sessions | int

Exemple 2 : adapter le comportement selon le verdict du fact

- name: Lire le verdict de conformite
  ansible.builtin.set_fact:
    compliance_verdict: "{{ ansible_local.remote_users_fact.compliance | default('unknown') }}"

- name: Appliquer la configuration stricte si non conforme
  ansible.builtin.import_tasks: enforce_strict.yml
  when: compliance_verdict == 'non_compliant'

- name: Enregistrer le resultat dans le journal d'audit
  ansible.builtin.lineinfile:
    path: /var/log/ansible-compliance.log
    line: "{{ ansible_date_time.iso8601 }} {{ inventory_hostname }} {{ compliance_verdict }}"
    create: true
    mode: '0640'

La condition when: ansible_local.xxx is defined protégé contre l'absence du fact et evite une erreur silencieuse ou un comportement non deterministe.


Tags et extra-vars en CLI

Les options CLI permettent de cibler finement un sous-ensemble d'hôtes et d'étapes sans modifier l'inventaire ni le playbook.

Cibler un groupe avec --limit

# Executer uniquement sur les serveurs citrix
ansible-playbook -i inventory/prod/ site.yml --limit citrix_servers

# Cibler un hote specifique dans un groupe
ansible-playbook -i inventory/prod/ site.yml --limit srv-01

Forcer un état avec -e

# Forcer l'etat present independamment de l'inventaire
ansible-playbook -i inventory/prod/ site.yml -e remote_users_fact_state=present

# Combiner plusieurs extra-vars
ansible-playbook -i inventory/prod/ site.yml \
  -e remote_users_fact_state=present \
  -e remote_users_fact_version=2.3.1

Exécuter une étape spécifique avec --tags

# Executer uniquement la phase de validation
ansible-playbook -i inventory/prod/ site.yml --tags validate

# Sauter la phase d'installation
ansible-playbook -i inventory/prod/ site.yml --skip-tags install

Combinaison opérationnelle

# Valider uniquement sur les serveurs citrix en prod, sans installer
ansible-playbook -i inventory/prod/aws-eu-west-1/internet/beta/ site.yml \
  --limit citrix_servers \
  --tags validate \
  -e remote_users_fact_state=present

Commandes opérationnelles courantes

Objectif Commande
Valider tous les hôtes prod ansible-playbook -i inventory/prod/ site.yml --tags validate
Installer sur un groupe ansible-playbook -i inventory/prod/ site.yml --limit app_servers
Forcer la suppression sur un hôte ansible-playbook -i inventory/prod/ site.yml -l srv-01 -e state=absent
Vérifier sans appliquer (dry-run) ansible-playbook -i inventory/prod/ site.yml --check --diff
Lister les tâches sans les exécuter ansible-playbook -i inventory/prod/ site.yml --list-tasks

Performance

Sur un inventaire de plusieurs centaines d'hôtes, les parametres par défaut d'Ansible produisent des executions lentes. Les optimisations suivantes sont cumulatives.

Parallélisme avec forks

forks contrôle le nombre d'hôtes traites en parallèle. La valeur par défaut est 5, insuffisante pour les grands inventaires.

# ansible.cfg
[defaults]
forks = 20

Pipelining SSH

pipelining réduit le nombre d'opérations SSH en transmettant plusieurs commandes dans la même connexion. Nécessité requiretty = false dans /etc/sudoers.

# ansible.cfg
[ssh_connection]
pipelining = True

Mises à jour progressives avec serial

serial limite le nombre d'hôtes traites simultanément dans un play. Utile pour les mises à jour sans interruption de service.

# playbooks/site.yml
---
- name: Mettre a jour les serveurs web progressivement
  hosts: web_servers
  serial: 5           # traiter 5 hotes a la fois
  roles:
    - nuevolia.application.webapp
# Avec un pourcentage — 25 % du groupe a la fois
serial: "25%"

Désactiver la collecte des facts

Quand le playbook n'utilise pas les facts système, désactiver leur collecte economise plusieurs secondes par hôte.

---
- name: Mettre a jour les cles SSH autorisees
  hosts: all
  gather_facts: false
  tasks:
    - name: Deployer les cles autorisees
      ansible.posix.authorized_key:
        user: "{{ item.user }}"
        key: "{{ item.key }}"
        state: present
      loop: "{{ authorized_keys_list }}"

Mise en cache des facts

Le cache de facts evite de les collecter à chaque exécution. Particulièrement utile quand les facts sont lus par plusieurs playbooks successifs.

# ansible.cfg
[defaults]
fact_caching            = jsonfile
fact_caching_connection = /tmp/ansible_facts
fact_caching_timeout    = 3600
# Invalider le cache manuellement si necessaire
rm -rf /tmp/ansible_facts/

Combinaison pour les grands inventaires

Sur un inventaire de 200+ hôtes, combiner forks = 20, pipelining = True, gather_facts: false sur les playbooks qui n'en ont pas besoin, et fact_caching = jsonfile avec un TTL de 1 heure réduit typiquement le temps d'exécution de 60 a 80 %. Activer ces options progressivement et mesurer l'impact à chaque étape pour identifier le goulot d'étranglement.