Dans cet atelier/tutoriel, nous allons déployer une base de données SQL (MariaDB) et une application web conteneurisée (via Docker) avec Ansible. Nous verrons également comment utiliser Molecule pour générer un rôle Ansible et le tester en local.
Prérequis
Afin de pouvoir réaliser ce tutoriel, vous devez avoir installé Docker, Python3 et Pip.
Le tutoriel a été réalisé sur Linux, je ne promet rien si vous avez un autre système d’exploitation 😉
Architecture du serveur
L’objectif de projet Ansible est d’installer Docker et MariaDB sur une machine distance. Le schéma ci-dessus représente l’architecture de test du projet.
Molecule, Docker et Ansible seront installés sur la machine locale (votre ordinateur). Nous allons provisionner un conteneur Docker dans lequel Ansible installera notre application de test (i.e MariaDB et notre application web). Le conteneur de test est celui à gauche du schéma.
Ce conteneur recevra un accès au socket de Docker, ce qui lui permettra de lancer le conteneur de l’application web. Attention, ce conteneur ne sera pas situé à l’intérieur du conteneur de test mais bien côte à côte de celui-ci.
Le conteneur isolant l’application web recevra un accès à MariaDB via un socket. Pour cela, on utilisera un volume partagé entre le conteneur de test et celui de l’application web.
Création d’un rôle Ansible avec Molecule
Un rôle Ansible regroupe un ensemble de tâches à accomplir pour atteindre un but précis. Développer un ensemble de rôles réutilisables et testés permet d’éviter des bugs et de factoriser la logique du déploiement.
Comme notre exemple est très simple, nous allons créer un seul rôle, nommé app. Si la complexité de l’application grandit, vous pourrez séparer les tâches de ce rôle dans plusieurs autres rôles et en créér de nouveaux pour les tâches additionnelles que votre client vous demande d’accomplir.
Par exemple, dans mon projet actuel, j’ai séparé mon déploiement en quatre rôles:
- Configuration de Docker, MariaDB et création des conteneurs applicatifs
- Installation de Certbot (certificats SSL) et de Nginx (proxy vers les conteneurs)
- Installation d’un serveur FTP
- Création d’un utilisateur MariaDB accessible à distance via une application Qt
Voici comment créer la structure du projet et installer Ansible et Molecule dans un virtualenv Python:
mkdir -p tutoriel-ansible/roles
cd tutoriel-ansible
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install ansible "molecule[docker,lint]"
Nous pouvons maintenant créer la structure du rôle app avec Molecule:
cd roles molecule init role app --driver-name docker
Vous pouvez voir la structure du rôle créé avec la commande tree app. Voici sa sortie que nous allons examiner ensemble:
app ├── defaults │ └── main.yml ├── files ├── handlers │ └── main.yml ├── meta │ └── main.yml ├── molecule │ └── default │ ├── converge.yml │ ├── molecule.yml │ └── verify.yml ├── README.md ├── tasks │ └── main.yml ├── templates ├── tests │ ├── inventory │ └── test.yml └── vars └── main.yml
Contenu des dossiers du rôle Ansible créé
Dossier de tâches
Le dossier tasks contient les tâches à accomplir lors de l’exécution de ce rôle.
Dossier de variables
Les dossiers vars et defaults contiennent des jeux de variables. On stockera les variables par défaut dans defaults. Des variables correspondant à des scénarios particuliers peuvent être placées dans vars.
Les variables importées à partir de defaults seront écrasées par celles importées depuis vars. Vous pouvez lire la documentation concernant les priorités des variables pour plus de détails sur ce mécanisme.
Dossier Molecule
Le dossier molecule/default du rôle app contient deux playbooks Ansible:
- converge.yml
- verify.yml
Le premier playbook converge.yml est lancé avec la commande molecule converge qui lance les tâches du rôle courant avec comme inventaire (i.e ensemble des machines sur lesquelles installer des applications) le conteneur Docker de test défini dans molecule.yml.
Le second playbook, verify.yml est exécuté avec molecule verify. Le contenu de ce playbook vise à tester l’état du conteneur de test pour voir si l’installation s’est bien passée.
Dossier meta
app/meta contient un fichier main.yml qui décrit le rôle app.
Vous devriez remplacer les paramètres author et description par une description qui fais sens et l’auteur par la personne ayant créé le rôle.
Les paramètres role_name et namespace devront également être ajoutés.
galaxy_info: role_name: app namespace: tutorial author: Jules Sagot--Gentil description: | Install MariaDB, Docker and deploy a demo app and a database.
Instance de test de nos rôles
Nous allons modifier l’instance de test provisionnée par Ansible afin de rendre le démon Docker accessible. Pour cela, éditez le fichier app/molecule/default/molecule.yml.
--- dependency: name: galaxy driver: name: docker platforms: - name: tutorial-instance image: debian:bullseye volumes: - /var/run/docker.sock:/var/run/docker.sock:rw - /sys/fs/cgroup:/sys/fs/cgroup:ro - instance-mariadb-socket:/var/run/mysqld privileged: true provisioner: name: ansible verifier: name: ansible
Molecule va maintenant lancer notre rôle Ansible app dans le conteneur Docker nommé tutorial-instance utilisant l’image Docker de Debian Bullseye.
Le volume docker nommé instance-mariadb-socket va permettre de partager le socket MariaDB entre l’application web conteneurisée et le conteneur tutorial-instance.
On peut lancer le maintenant provisionnement du conteneur de test avec:
cd app molecule create
Installation de Docker et de MariaDB
On va éditer le fichier tasks/main.yml qui contient les tâches de notre rôle qui seront exécutées par Ansible. Nous allons dans un premier temps installer Docker et MariaDB.
--- - name: mise à jour des paquets apt: upgrade: yes update_cache: yes - name: installation des dépendances de docker apt: name: - ca-certificates - curl - gnupg - lsb-release - name: installation de la clef GPG du projet Docker apt_key: data: "{{ lookup('file', 'docker_repo_gpg_key.asc') }}" state: present - name: ajout du dépôt Debian de Docker apt_repository: repo: deb [arch=amd64] https://download.docker.com/linux/debian bullseye stable state: present update_cache: yes - name: installation de docker apt: name: - docker-ce - docker-ce-cli - containerd.io update_cache: yes - name: installation de python pip apt: name: - python3-pip - name: installation du sdk python pour Docker pip: name: docker - name: installation de MariaDB apt: name: mariadb-server - name: /var/run/mysql doit appartenir à mysql file: path: /var/run/mysqld owner: mysql group: mysql - name: démarrage du service MariaDB service: name: mariadb state: started enabled: yes
Le dossier files contient des fichiers statiques nécéssaires au projet. Il vous faudra télécharger la clef GPG de Docker pour installer ce logiciel en toute sécurité.
curl https://download.docker.com/linux/ubuntu/gpg > files/docker_repo_gpg_key.asc
Nous pouvons maintenant lancer molecule converge afin de déployer notre rôle sur l’instance Docker de test.
Pour vérifier que tout s’est passé comme prévu, on va vérifier qu’on peut lancer le conteneur hello-world depuis l’instance de test.
On ajoute cette tâche au playbook Ansible molecule/default/verify.yml
- name: Verify hosts: all gather_facts: false tasks: - name: run docker hello world community.docker.docker_container: name: test_hello_world image: hello-world detach: no cleanup: yes
Pour vérifier que les tests passent, lancer molecule verify.
Partager et utiliser des rôles Ansible classiques avec Ansible Galaxy
Le projet Ansible Galaxy permet aux utilisateurs d’Ansible de partager leurs rôles. Par exemple, dans notre rôle, l’installation de Docker prend 4 étapes. Il existe sûrement un rôle Ansible Galaxy permettant d’installer Docker.
Utiliser les rôles d’Ansible Galaxy permet de factoriser son application Ansible avec des rôles testés unitairement ainsi qu’en production par d’autres utilisateurs d’Ansible.
Une collection Ansible Galaxy est un ensemble de rôles partageant une même thématique. Nous allons utiliser les deux collections de rôles Ansible suivants:
- community.docker
- community.mysql
Le premier permet d’intéragir avec les conteneurs Docker et le second de requêter une base de données SQL.
Ces collections de rôles seront listées comme une dépendance du rôle app. Pour ce faire, nous allons définir un fichier de dépendances, requirements.yml
collections: - name: community.docker - name: community.mysql
Pour installer ces collections de rôles (depuis le fichier requirements.yml), lancez la commande suivante:
ansible-galaxy collection install -vr requirements.yml
Administration de la base de données
Les rôles de la collection Ansible Galaxy community.mysql que nous avons précédemment installée va nous permettre de créer:
- Un utilisateur MariaDB
- Une base de données
Création d’un utilisateur MariaDB
On ajoute une template Jinja2 de fichier de configuration MariaDB my.cnf.j2 dans templates qui permettra de sauvegarder le mot de passe de l’utilisateur MariaDB créé pour les prochaines connexions et garantir l’idempotence du rôle Ansible:
[client] user={{ root_user }} password={{ root_password }}
Les variabes root_user et root_password auront comme valeurs par défaut demo. Nous stockons ces défauts dans defaults/main.yml, ainsi que le nom de la base de données à créer.
root_user: demo root_password: demo database: demo-db
Ajoutons la création d’un utilisateur MariaDB à tasks/main.yml:
#... - name: installation du SDK python pour MariaDB pip: name: PyMySQL - name: création d'un utilisateur root avec mot de passe community.mysql.mysql_user: name: "{{ root_user }}" password: "{{ root_password }}" plugin: mysql_native_password priv: '*.*:ALL,GRANT' state: present login_unix_socket: /var/run/mysqld/mysqld.sock - name: sauvegarde du compte MariaDB template: src: my.cnf.j2 dest: /root/.my.cnf owner: root group: root mode: '0600' - name: suppression de l'utilisateur root MariaDB community.mysql.mysql_user: name: root state: absent
Création d’une base de données
On crée une base de données avec le rôle mysql_db contenu dans la collection galaxy community.mysql téléchargée précédemment:
#... - name: creation de la base de données community.mysql.mysql_db: name: "{{ database }}" state: present
Instantiation d’une application web
Pour cet atelier, nous allons simplement déployer PHPMyAdmin qui est un logiciel libre permettant de visualiser/modifier une base de données.
Nous allons cette fois utiliser la collection de rôle Ansible Galaxy community.docker et plus précisément le rôle container.
La nouvelle tâche suivante est à insérer dans tasks/main.yml.
#... - name: instantiation de l'application web community.docker.docker_container: name: webapp image: phpmyadmin:5-apache env: PMA_SOCKET: "/var/run/mysqld/mysqld.sock" PMA_HOST: localhost PMA_USER: "{{ root_user }}" PMA_PASSWORD: "{{ root_password }}" volumes: "instance-mariadb-socket:/var/run/mysqld" ports: - "3000:80"
Nous ajoutons également un test vérifiant si PHPMyAdmin répond aux reqûetes sur le port 3000. Le code suivant est à ajouter aux tâches du playbook verify.yml qui sera lancé lors du test de notre rôle Ansible avec molecule verify.
- name: l'application web doit répondre aux requêtes command: "curl -s http://localhost:3000/" delegate_to: localhost
Code source de l’atelier
Le code source que nous avons écrit ensemble dans le cadre de ce tutoriel est disponible sur Gitlab.
Conclusion
Ce tutoriel vous a permis d’avoir un aperçu des possibilités qu’offrent les rôles d’Ansible en terme de factorisation/qualité de code. Molecule et Docker apportent de leur côté un déploiement standard des applications (en les conteneurisant) et la possibilité de tester le bon déroulement d’un rôle Ansible.
L’automatisation des tests de déploiement avec Ansible, Molecule et
Docker permet ainsi d’être confiant lors des releases en production et
d’éviter les erreurs humaines, ainsi que d’assurer une traçabilité de
l’infrastructure.
Créer et tester ses rôles Ansible avec Docker et Molecule