Deuxi√®me partie de la s√©rie consacr√©e √† Ansible. Cette fois nous parlerons plus en d√©tail de l’inventaire, √† quoi √ßa sert, comment l’organiser, comment l’exploiter, etc.

L’inventaire Ansible

L’inventaire est la liste de hosts qu’Ansible est capable de g√©rer. Il peut se d√©finir de deux fa√ßons : sous forme INI ou bien en YAML. L’inventaire par d√©faut est celui situ√© dans /etc/ansible/hosts, mais celui-ci peut √™tre un fichier appel√© √† la vol√©e.

Exemple d’inventaire au format INI :

mail.example.com

[webservers]
foo.example.com
bar.example.com

[dbservers]
one.example.com
two.example.com
three.example.com

Le même, en YAML.

all:
  hosts:
    mail.example.com:
  children:
    webservers:
      hosts:
        foo.example.com:
        bar.example.com:
    dbservers:
      hosts:
        one.example.com:
        two.example.com:
        three.example.com:

Groupement de hosts

Pour que l’inventaire soit facile √† maintenir et l’ex√©cution d’Ansible coh√©rente, il est possible de regrouper les hosts sous diff√©rentes banni√®res. De m√™me, vous pouvez faire des groupes de groupes pour √©viter de r√©p√©ter plusieurs fois les m√™mes √©l√©ments et ainsi potentiellement les oublier en cas de rajout.

Deux groupes par d√©faut existent syst√©matiquement, qu’ils soient nomm√©s ou non :

  • all : prend la totalit√© des hosts de l’inventaire
  • ungrouped : prend uniquement les hosts membres d’aucun groupe en dehors de all.

Pour grouper des hosts, il suffit d’utiliser l’instruction children qui permet de d√©finir la hi√©rarchie.

Admettons que nous avons une application dont les serveurs sont r√©partis √† plusieurs emplacements g√©ographiques, et avec une plateforme de production situ√©e √† Paris et une pr√©-production √† Lille. On pourrait concevoir l’inventaire ainsi :

all:
  hosts:
    srv1.example.com
  children:
    webservers:
      hosts:
        web1.example.com
        web2.example.com
        web3.example.com
    dbservers:
      hosts:
        db1.example.com
        db2.example.com
        db3.example.com
    paris:
      hosts:
        web1.example.com
        web3.example.com
        db1.example.com
        db3.example.com
    lille:
      hosts:
        web2.example.com
        db2.example.com
    prod:
      hosts:
        web1.example.com
        web2.example.com
        db1.example.com
        db2.example.com
    preprod:
      hosts:
        web3.example.com
        db3.example.com

Dans cet exemple, les servers webX et dbX sont r√©p√©t√©s entre leur r√īle, leur emplacement, et leur type de plateforme. L’√©criture suivante permet d’exploiter les sous groupes et limiter la redondance d’information.

all:
  hosts:
    srv1.example.com
  children:
    webservers:
      hosts:
        web1.example.com
        web2.example.com
        web3.example.com
    dbservers:
      hosts:
        db1.example.com
        db2.example.com
        db3.example.com
    paris:
      hosts:
        web1.example.com
        web3.example.com
        db1.example.com
        db3.example.com
    lille:
      hosts:
        web2.example.com
        db2.example.com
    prod:
      children:
        paris:
    preprod:
      children:
        lille:

Avec cet exemple, nous savons que la production est √† Paris et la pre-production √† Lille. Il suffit donc d’indiquer le groupe Paris et Lille √† leurs emplacements respectifs. Par contre, on garde un d√©doublement d’information concernant le r√īle technique des serveurs et leur localisation. Et si la preprod et la prod venaient √† s’inverser, les plateformes seraient les m√™mes mais les membres du groupe prod et preprod changeront.

Les groupes webservers et dbservers peuvent √™tre inutiles aussi si jamais dans notre besoin, nous consid√©rons que nous g√©rons les plateformes par localisation et non par r√īle technique.

En version INI, nous aurions le résultat suivant :

srv1.example.com #le serveur n'est pas groupé

[prod:children]
paris

[preprod:children]
lille

[webservers]
web1.example.com
web2.example.com
web3.example.com

[dbservers]
db1.example.com
db2.example.com
db3.example.com

[paris]
web1.example.com
web3.example.com
db1.example.com
db3.example.com

[lille]
web2.example.com
db2.example.com

Les variables d’inventaires

Il est parfaitement possible d’assigner des variables pour un host au sein de l’inventaire, par exemple un port d’√©coute, une IP, un user, etc. N√©anmoins, si ce besoin commence √† devenir trop cons√©quent, il conviendra de recourir √† des fichiers s√©par√©s qui seront nativement charg√©s par Ansible : les group_vars et hosts_vars notamment.

Exemple d’attribution de variable √† un host.

[lille]
web1.example.com http_port=80
web2.example.com http_port=81

Les variables de hosts sont utiles pour d√©finir des informations de bas niveau tel que des configurations sp√©cifiques SSH. Exemple pour indiquer √† Ansible le port et l’utilisateur de connexion :

[lille]
web1.example.com ansible_port=1234 ansible_user=user1
web2.example.com ansible_port=2222 ansible_user=user2

Group_vars et inventaires

Comme dit plus haut, si on a besoin de g√©rer beaucoup de variables sur un d√©ploiement, il conviendra d’utiliser les fichiers group_vars ou hosts_vars. Le lien entre le fichier group_vars et l’inventaire se fait avec le nom du groupe.

Exemple d’arborescence :

inventory/
    production/
        hosts #ce fichier contient l'inventaire
        group_vars/
            all.yml #ce fichier contient des variables applicables à l'ensemble des hosts de l'inventaire
            webservers.yml # ce fichier contient des variables applicables uniquement aux membres du groupe webservers
            dbservers.yml # ce fichier contient des variables applicables uniquement aux membres du groupe dbservers
        hosts_vars/
            all.yml #ce fichier contient des variables applicables à l'ensemble des hosts de l'inventaire
            webservers.yml # ce fichier contient des variables applicables uniquement aux membres du groupe webservers
            dbservers.yml # ce fichier contient des variables applicables uniquement aux membres du groupe dbservers
    preprod/
        hosts #ce fichier contient l'inventaire
        group_vars/
            all.yml #ce fichier contient des variables applicables à l'ensemble des hosts de l'inventaire
            webservers.yml # ce fichier contient des variables applicables uniquement aux membres du groupe webservers
            dbservers.yml # ce fichier contient des variables applicables uniquement aux membres du groupe dbservers
        hosts_vars/
            all.yml #ce fichier contient des variables applicables à l'ensemble des hosts de l'inventaire
            webservers.yml # ce fichier contient des variables applicables uniquement aux membres du groupe webservers
            dbservers.yml # ce fichier contient des variables applicables uniquement aux membres du groupe dbservers

La principale diff√©rence avec une arborescence de ce type, c’est que nous utilisons deux fichiers d’inventaire diff√©rents. Un pour la prod, un pour la preprod. L’inventaire est le fichier host pr√©sent dans le sous dossier inventory/preprod et inventory/prod.

Cela change la fa√ßon dont on appellera l’inventaire lors d’une ex√©cution Ansible.

# en prod
ansible-playbook -i inventory/production/hosts monplaybook.yml

# en preprod
ansible-playbook -i inventory/preprod/hosts monplaybook.yml

Il s’agit ainsi d’une approche diff√©rente de l’inventaire que nous avions fait en exemple. En effet, dans notre inventaire nous avions mis la totalit√© de nos serveurs de preprod et prod et deux groupes pour les diff√©rencier. Ces groupes auraient permis de lancer des actions en contextualisant le code (si membre du groupe prod, alors…). Avec des inventaires s√©par√©s entre prod et preprod, le code ex√©cut√© peut th√©oriquement √™tre le m√™me et c’est l’inventaire qui le contextualisera.

Nous verrons comment exploiter les group_vars et host_vars dans le billet qui sera d√©di√© aux r√īles Ansible.

Points d’attention

L’inventaire est un √©l√©ment fortement structurant d’un playbook ou d’un r√īle Ansible. Son organisation conditionnera comment vous √©crirez vos proc√©dures, c’est donc un composant qui n√©cessite une certaine r√©flexion.

Comprendre la port√©e des variables du host_vars et du group_vars est essentiel pour √©viter des r√©√©critures de code co√Ľteuses en temps.

Exemples de portée de variables :

  • L’application d√©ploy√©e par Ansible poss√®de des arborescences de dossier cens√©es √™tre identiques entre tous les hosts qui ont le r√īle “webserver” => ces valeurs sont √† mettre dans group_vars/webservers.yml
  • L’application d√©ploy√©e par Ansible est un ensemble de plusieurs bases de donn√©es qui ont chacune un nom d’instance diff√©rent => cette valeur est √† mettre dans hosts_vars/dbservers.yml
  • L’application √©coute le port 443 en production et 4443 en preproduction => cette variable est √† mettre dans le group_vars avec la valeur attendue pour le contexte
  • Les serveurs web d√©ploy√©s sur les hosts √©coutent chacun un port diff√©rent, un load balancer expose en frontal le port utilis√© par les clients => le port sp√©cifique de chaque host est √† mettre dans le hosts_vars

Nous verrons dans le billet consacr√© aux r√īles comment exploiter les variables du group_vars et hosts_vars.

Conclusion

Nous avons donc vu ce qu’est l’inventaire et comment on peut l’organiser et l’exploiter. A titre personnel, j’ai une pr√©f√©rence pour le format INI que je trouve beaucoup plus lisible que le YAML pour le coup.

Dans le prochain billet, nous rédigerons et exécuterons notre premier playbook.