Ansible : introduction et présentation d'un cas d'usage avec Oracle Database

A l’heure où l’API-sation des systèmes d’information est devenue une étape indispensable pour toutes les entreprises, les gestionnaires de configuration sont des outils qui sont en pleine explosion.
Vous les connaissez surement car vous en avez entendu parlé ou même déjà utilisé, ils s’appellent Puppet, Chef, SaltStack, Fabric… Aujourd’hui nous allons parler d’Ansible.

Ansible, c’est quoi ?

Rachetée en 2015 par RedHat, Ansible est donc un gestionnaire de configuration, mais pas que.
Il permet de faire du déploiement multi-nœuds et de l’exécution à distance de tâches.
Open-source, Ansible est basé sur l’écriture de « playbooks » YAML pour décrire les tâches de déploiement de vos applications. Peu importe le système sur lequel vous désirez pousser vos configurations, le langage restera le même.

Ansible, en quoi c’est différent des autres ?

L’un des avantages majeur d’Ansible, c’est qu’il est « agent-less ». En effet, il est basé sur le SSH et il n’est donc pas nécessaire d’installer des agents sur les noeuds sur lesquels vous voulez déployer vos configurations.
Autre avantage, l’écriture de « playbook » est relativement simple pour des administrateurs systèmes, moins habitués aux langages de développement tels que Ruby. Le YAML permet d’ailleurs d’avoir des « playbooks » très facilement lisibles par n’importe qui. En conséquence, la courbe d’apprentissage est très faible comparée à Puppet ou CFEngine par exemple.

Ansible, comment ça marche ?

C’est simple, et on a finalement déjà presque tout dis en présentant Ansible.
Première chose, il vous faut un serveur qui va exécuter les playbooks sur vos nœuds distants (on l’appellera « master »). Celui-ci devra donc pouvoir se connecter en SSH sur vos machines (via un échange de clé par exemple).
Ensuite, il vous faut évidemment Ansible d’installé sur votre master. Rien de plus simple, un « yum install ansible » fera l’affaire (lors de l’écriture de cet article, la dernière version disponible est la 2.4).
Et … c’est tout ! C’est là toute la configuration qu’il vous sera nécessaire de réaliser pour commencer à écrire des playbooks et à les exécuter sur vos cibles.
Pour illustrer mes propos, regardons un peu comment se présente un playbook.

Cas d’usage : installation des pré-requis au moteur Oracle Database 11g

Un playbook est une succession de tâches. Une tâche est une description d’un état voulu.
Prenons l’exemple de la création de l’utilisateur « oracle » :

- name: Create oracle user
  user:
    name: oracle
    comment: "Oracle Software Owner"
    uid: 601
    groups: oinstall,dba

Le module ansible utilisé ici est « user ». Il prendra en argument un nom (« name »), un commentaire optionnel (« comment »), l’UID désiré pour cet utilisateur (« uid »), et les groupes auxquels le rattacher (« groups »).
Que va donc faire Ansible quand il va vouloir résoudre cette tâche ? Et bien s’il constate que l’utilisateur en question n’existe pas, il va le créer avec les différentes caractéristiques voulues. Si au contraire l’utilisateur existe déjà, il va regarder si la configuration est la même, et dans le cas contraire, appliquer les changements ! C’est toute la magie d’un gestionnaire de configuration.
Des modules ansible il en existe pour beaucoup, beaucoup, beaucoup de choses : user, group, yum, authorized_key, sysctl, mount, etc… C’est une véritable boîte à outils à laquelle vous avez accès.
Si on reprend notre exemple d’installation des pré-requis à l’installation du moteur Oracle Database, voilà ce que ça pourrait donner :

- name: Create oracle groups (oinstall, dba)
  group:
    name: "{{ item.name }}"
    gid: "{{ item.gid }}"
    state: present
  with_items:
    - { name: 'oinstall', gid: '601' }
    - { name: 'dba', gid: '602' }
- name: Create oracle user
  user:
    name: oracle
    comment: "Oracle Software Owner"
    uid: 601
    groups: oinstall,dba
- name: Install prerequisite packages for Oracle
  register: result_prerequisite
  yum:
    name:
      - binutils
      - libstdc++.so.5
      - libstdc++.so.5()(64bit)
      - elfutils-libelf
      - elfutils-libelf-devel
      - gcc
      - gcc-c++
      - glibc
      - glibc-common
      - libaio
      - libgcc
      - libstdc++
      - libstdc++-devel
      - make
      - sysstat
      - xorg-x11-xauth
      - xorg-x11-utils
      - xorg-x11-apps
      - rlwrap
      - glibc-devel(x86-64)
      - glibc-devel(x86-32)
      - libXp(x86-64)
      - libXp(x86-32)
      - libXtst(x86-64)
      - libXtst(x86-32)
      - libaio-devel(x86-32)
      - libaio-devel(x86-64)
      - unixODBC(x86-32)
      - unixODBC(x86-64)
      - unixODBC-devel(x86-32)
      - unixODBC-devel(x86-64)
- name: Update sysctl.conf parameters (add Oracle prerequisites)
  sysctl:
    name: "{{ item.name }}"
    value: "{{ item.value }}"
    state: present
  with_items:
    - { name: 'fs.file-max', value: '6815744' }
    - { name: 'fs.aio-max-nr', value: '1048576' }
    - { name: 'kernel.shmmni', value: '4096' }
    - { name: 'kernel.sem', value: '250 32000 100 128' }
    - { name: 'net.ipv4.ip_local_port_range', value: '9000 65500' }
    - { name: 'net.core.rmem_default', value: '4194304' }
    - { name: 'net.core.rmem_max', value: '4194304' }
    - { name: 'net.core.wmem_default', value: '262144' }
    - { name: 'net.core.wmem_max', value: '1048576' }
- name: Update limits.conf parameters
  pam_limits:
    domain: oracle
    limit_type: "{{ item.type }}"
    limit_item: "{{ item.item }}"
    value: "{{ item.value }}"
  with_items:
    - { type: 'soft', item: 'nproc', value: '2047' }
    - { type: 'hard', item: 'nproc', value: '16384' }
    - { type: 'soft', item: 'nofile', value: '1024' }
    - { type: 'hard', item: 'nofile', value: '65536' }

Maintenant que votre playbook est bien entamé, il ne vous reste plus qu’à le lancer !

[root ~]# ansible-playbook oracle_playbook.yml -i liste_hosts.inv

On ne rentre pas plus dans les détails, la documentation ansible est excellente et les ressources sont très nombreuses !