Skip to main content

Chapitre 2 - Déployer une Infrastructure Docker avec Ansible - Pratique 02

Dans ce chapitre, nous allons explorer l'utilisation d'Ansible pour automatiser des tâches sur une infrastructure Docker de manière efficace et structurée. Cette infrastructure sera composée de plusieurs conteneurs utilisant différentes distributions Linux (Ubuntu, Debian, AlmaLinux) qui nous permettront de :

  • Configurer et gérer plusieurs conteneurs Docker de manière centralisée
  • Automatiser des tâches complexes sur différentes distributions Linux avec des conditions adaptées (Ubuntu, Debian, AlmaLinux)
  • Organiser et structurer nos conteneurs de manière logique et maintenable
  • Mettre en place des bonnes pratiques d'automatisation avec Ansible
  • Créer des playbooks réutilisables et modulaires

📋 Table des Matières

  1. Introduction
  2. Étape 1 : Installer Docker et Docker Compose
  3. Étape 2 : Créer et Démarrer les Conteneurs
  4. Étape 3 : Configurer l'Accès SSH pour Ansible
  5. Étape 4 : Créer l'Inventaire Ansible avec Groupes
  6. Étape 5 : Lister les Hôtes par Groupe
  7. Étape 6 : Tester la Connectivité et Exécuter des Commandes
  8. Étape 7 : Exécuter des Actions Spécifiques sur des Groupes
  9. Étape 8 : Écrire et Exécuter un Playbook Ansible
  10. Étape 9 : Vérifier le Déploiement
  11. Conclusion

📝 Introduction

Nous allons déployer une infrastructure Docker avec plusieurs conteneurs de différentes distributions Linux, configurer l'accès SSH pour Ansible, organiser les conteneurs en groupes dans un inventaire Ansible, et automatiser des tâches sur ces conteneurs en tenant compte des spécificités de chaque distribution.


🌍 Étape 1 : Installer Docker et Docker Compose

Sur votre machine de contrôle (Ubuntu Desktop 22.04 ou Ubuntu Server 22.04), exécutez les commandes suivantes pour installer Docker et Docker Compose :

sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release git
git clone https://github.com/SkillFlowCoach/install-docker-ubuntu2204.git
cd install-docker-ubuntu2204/
chmod +x install-docker.sh
sudo ./install-docker.sh
apt install docker-compose
docker-compose version

🗄️ Étape 2 : Créer et Démarrer les Conteneurs

2.1. Créer un Répertoire de Travail

Créez un nouveau répertoire pour votre projet et accédez-y :

mkdir ansible_project
cd ansible_project

2.2. Créer le Fichier docker-compose.yml

Architecture de l'infrastructure à créer avec docker-compose :

                          +----------------------+
| Ansible Controller |
| Ubuntu 22.04 |
| IP: 172.20.0.X |
+----------------------+
|
|
--------------------------------------------------------------------------
| | | | | | |
+---------+ +---------+ +---------+ +---------+ +---------+ +---------+ +---------+
| Node1 | | Node2 | | Node3 | | Node4 | | Node5 | | Node6 | | NodeX |
| Ubuntu | | Debian | | AlmaLin | | AlmaLin | | Ubuntu | | Ubuntu | | (opt) |
| 172.20.0.2| 172.20.0.3| 172.20.0.4| 172.20.0.5| 172.20.0.6| 172.20.0.7| ... |
+---------+ +---------+ +---------+ +---------+ +---------+ +---------+ +---------+

Légende :

  • Ansible Controller : Machine principale de contrôle sous Ubuntu 22.04.
  • Nodes (Node1 à Node6) :
    • Node1 : Ubuntu
    • Node2 : Debian
    • Node3, Node4 : AlmaLinux
    • Node5, Node6 : Ubuntu
  • Toutes les machines sont sur le réseau ansible_network avec des adresses IP statiques dans le sous-réseau 172.20.0.0/24.

Créez le fichier docker-compose.yml :

nano docker-compose.yml

2.3. Contenu du Fichier docker-compose.yml

Copiez et collez le contenu suivant dans le fichier, en veillant à ce que la configuration pour les conteneurs AlmaLinux soit correcte :

version: '3'

services:
node1:
image: ubuntu:latest
container_name: node1
networks:
ansible_network:
ipv4_address: 172.20.0.2
command: /bin/bash -c "apt update && apt install -y openssh-server python3 && service ssh start && tail -f /dev/null"
expose:
- "22"
- "80"

node2:
image: debian:latest
container_name: node2
networks:
ansible_network:
ipv4_address: 172.20.0.3
command: /bin/bash -c "apt update && apt install -y openssh-server python3 && service ssh start && tail -f /dev/null"
expose:
- "22"
- "80"

node3:
image: almalinux:latest
container_name: node3
networks:
ansible_network:
ipv4_address: 172.20.0.4
command: /bin/bash -c "yum update -y && yum install -y openssh-server passwd python3 && echo 'root:root' | chpasswd && ssh-keygen -A && /usr/sbin/sshd -D"
expose:
- "22"
- "80"

node4:
image: almalinux:latest
container_name: node4
networks:
ansible_network:
ipv4_address: 172.20.0.5
command: /bin/bash -c "yum update -y && yum install -y openssh-server passwd python3 && echo 'root:root' | chpasswd && ssh-keygen -A && /usr/sbin/sshd -D"
expose:
- "22"
- "80"

node5:
image: ubuntu:latest
container_name: node5
networks:
ansible_network:
ipv4_address: 172.20.0.6
command: /bin/bash -c "apt update && apt install -y openssh-server python3 && service ssh start && tail -f /dev/null"
expose:
- "22"
- "80"

node6:
image: ubuntu:latest
container_name: node6
networks:
ansible_network:
ipv4_address: 172.20.0.7
command: /bin/bash -c "apt update && apt install -y openssh-server python3 && service ssh start && tail -f /dev/null"
expose:
- "22"
- "80"

networks:
ansible_network:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/24

Remarques Importantes :

  • Python3 est installé sur tous les conteneurs pour assurer la compatibilité avec Ansible.
  • Les conteneurs AlmaLinux exécutent sshd -D pour garder le conteneur actif.
  • Les ports 22 et 80 sont exposés pour SSH et HTTP.

Voici un tableau récapitulatif des informations pour chaque nœud avec le détail de la distribution utilisée, l'adresse IP, et les actions effectuées :

NœudImage (OS)Adresse IPCommandes exécutéesPorts exposésBut principal
node1Ubuntu (latest)172.20.0.2apt update, installation openssh-server, python3, démarrage SSH22, 80Nœud de test pour Ansible (Ubuntu)
node2Debian (latest)172.20.0.3apt update, installation openssh-server, python3, démarrage SSH22, 80Nœud de test pour Ansible (Debian)
node3AlmaLinux (latest)172.20.0.4yum update, installation openssh-server, passwd, python3, génération clé SSH22, 80Nœud de test pour Ansible (AlmaLinux)
node4AlmaLinux (latest)172.20.0.5yum update, installation openssh-server, passwd, python3, génération clé SSH22, 80Nœud de test pour Ansible (AlmaLinux)
node5Ubuntu (latest)172.20.0.6apt update, installation openssh-server, python3, démarrage SSH22, 80Nœud de test pour Ansible (Ubuntu)
node6Ubuntu (latest)172.20.0.7apt update, installation openssh-server, python3, démarrage SSH22, 80Nœud de test pour Ansible (Ubuntu)

Explication des colonnes :

  • Nœud : Nom du conteneur.
  • Image (OS) : Système d'exploitation utilisé pour le conteneur.
  • Adresse IP : Adresse IP fixe dans le réseau ansible_network.
  • Commandes exécutées : Commandes exécutées pour préparer l'environnement (mise à jour du système, installation de packages nécessaires).
  • Ports exposés : Ports ouverts pour accéder au conteneur (SSH et HTTP).
  • But principal : Utilisation prévue du conteneur (test des playbooks Ansible sur différentes distributions).

2.4. Démarrer les Conteneurs

Exécutez la commande suivante pour démarrer tous les conteneurs en arrière-plan :

docker-compose up -d

Vérifiez que les conteneurs sont en cours d'exécution :

docker ps

N'exécutez pas la commande ci-dessous maintenant. Elle doit être exécutée à la fin car elle permet d'arrêter et de supprimer tous les conteneurs + réseau , volumes etc...:

docker-compose down

🔑 Étape 3 : Configurer l'Accès SSH pour Ansible

3.1. Générer une Clé SSH (si elle n'existe pas)

Générez une clé SSH sans phrase de passe :

ssh-keygen -t rsa -b 2048 -N "" -f ~/.ssh/id_rsa

3.2. Copier la Clé Publique vers Chaque Conteneur

Pour tous les conteneurs (node1 à node6) :

for i in {1..6}; do
docker exec -it node$i mkdir -p /root/.ssh
docker cp ~/.ssh/id_rsa.pub node$i:/root/.ssh/authorized_keys
docker exec -it node$i chmod 600 /root/.ssh/authorized_keys
done

Scénario de connexion SSH avec Ansible:

  1. Le master (machine Ansible) envoie une requête de connexion SSH aux nœuds (conteneurs).
  2. Chaque nœud (esclave) envoie un challenge chiffré avec la clé publique.
  3. Le master utilise sa clé privée pour déchiffrer le challenge et prouver son identité.
  4. Si la réponse est correcte, la connexion SSH est établie, permettant à Ansible d'exécuter des commandes sur le nœud sans mot de passe.

Résumé :

Le master prouve son identité aux nœuds pour établir une connexion sécurisée et automatiser la gestion via Ansible.

3.3. Vérifier la Connexion SSH pour Chaque Conteneur

Supprimez les anciennes entrées d'hôtes connus pour éviter les conflits :

rm -f ~/.ssh/known_hosts
ssh-keygen -R 172.20.0.2
ssh-keygen -R 172.20.0.3
ssh-keygen -R 172.20.0.4
ssh-keygen -R 172.20.0.5
ssh-keygen -R 172.20.0.6
ssh-keygen -R 172.20.0.7

Lorsqu'une clé publique de serveur a été modifiée, le client SSH détecte une incohérence avec l'empreinte stockée et bloque la connexion pour des raisons de sécurité ; il faut donc supprimer l'ancienne empreinte dans known_hosts pour établir une nouvelle connexion sans erreur.

Ensuite, vérifiez la connexion SSH :

for i in {1..6}; do
IP=172.20.0.$((i+1))
ssh -o StrictHostKeyChecking=no root@$IP exit
done
  1. Cette boucle SSH désactive la vérification stricte des clés d'hôtes (StrictHostKeyChecking=no) pour éviter toute demande de confirmation lors de la connexion aux adresses IP des conteneurs.
  2. Pour chaque IP de 172.20.0.2 à 172.20.0.7, une connexion SSH est testée (avec exit pour quitter immédiatement), permettant de préenregistrer automatiquement l'empreinte dans le fichier known_hosts.

📜 Étape 4 : Créer l'Inventaire Ansible avec Groupes

Créez un fichier inventory.ini dans votre répertoire de travail :

nano inventory.ini

Ajoutez le contenu suivant :

[node_containers]
node1 ansible_host=172.20.0.2 ansible_user=root
node2 ansible_host=172.20.0.3 ansible_user=root
node3 ansible_host=172.20.0.4 ansible_user=root
node4 ansible_host=172.20.0.5 ansible_user=root
node5 ansible_host=172.20.0.6 ansible_user=root
node6 ansible_host=172.20.0.7 ansible_user=root

[web]
node1
node5

[database]
node2
node3

[mail]
node4
node6

Un inventaire Ansible définit la liste des machines cibles avec leurs adresses IP, noms d'hôte et paramètres de connexion. Il permet de regrouper les machines par rôles ou services afin d'exécuter des tâches spécifiques sur un ensemble d'hôtes de manière organisée.

Ce fichier est un exemple d' inventaire Ansible qui liste les hôtes et les regroupe en catégories :

  1. [node_containers] :

    • Groupe principal contenant tous les conteneurs avec leurs adresses IP (ansible_host) et l'utilisateur SSH utilisé (ansible_user=root).
  2. [web] :

    • Groupe des nœuds affectés aux services web (node1 et node5).
  3. [database] :

    • Groupe des nœuds pour les services de base de données (node2 et node3).
  4. [mail] :

    • Groupe des nœuds pour le service de messagerie (node4 et node6).

Résumé :

Cet inventaire organise les conteneurs par rôles spécifiques pour exécuter des playbooks Ansible ciblés sur certains groupes (web, base de données, messagerie).


📝 Étape 5 : Lister les Hôtes par Groupe

5.1. Lister les Hôtes du Groupe web

ansible web -i inventory.ini --list-hosts

5.2. Lister les Hôtes du Groupe mail

ansible mail -i inventory.ini --list-hosts

5.3. Lister Tous les Hôtes Définis

ansible all -i inventory.ini --list-hosts

5.4. Lister les Détails d'un Hôte Spécifique (node1)

ansible node1 -i inventory.ini --list-hosts

📝 Étape 6 : Tester la Connectivité et Exécuter des Commandes

6.1. Tester la Connectivité avec ping pour Tous les Conteneurs

ansible all -m ping -i inventory.ini

6.2. Afficher la Date Actuelle sur node1

ansible node1 -m command -a "date" -i inventory.ini

C'est un exemple de commande ad hoc Ansible qui exécute le module command sur l'hôte node1 pour afficher la date actuelle via la commande date. L'option -i inventory.ini précise le fichier d'inventaire contenant les informations sur les hôtes cibles.

6.3. Afficher la Date Actuelle sur Tous les Conteneurs

ansible all -m command -a "date" -i inventory.ini

📝 Étape 7 : Exécuter des Actions Spécifiques sur des Groupes

7.1. Redémarrer le Service Apache sur le Groupe web

Nous devons tenir compte des différences entre les distributions :

  • Sur Ubuntu/Debian, le service Apache s'appelle apache2.
  • Sur AlmaLinux, le service s'appelle httpd.

Cependant, dans le groupe web, nous avons node1 et node5, qui sont tous deux des conteneurs Ubuntu. Nous utiliserons donc apache2.

Installer Apache sur le Groupe web :

ansible web -m apt -a "name=apache2 state=present" -i inventory.ini

Démarrer et Activer le Service Apache :

ansible web -m service -a "name=apache2 state=started enabled=yes" -i inventory.ini

Redémarrer le Service Apache sur le Groupe web

ansible web -m service -a "name=apache2 state=restarted" -i inventory.ini

Note : Si vous aviez des conteneurs AlmaLinux dans le groupe web, vous devriez utiliser des conditions ou séparer les tâches.

7.2. Vérifier l'Uptime sur le Groupe mail

Le conteneur node4 (AlmaLinux) semble ne pas avoir la commande uptime installée par défaut. Nous allons installer procps qui fournit uptime.

7.2.1. Installer procps sur les Conteneurs AlmaLinux

ansible mail -m yum -a "name=procps-ng state=present" -i inventory.ini

7.2.2. Vérifier l'Uptime

ansible mail -m command -a "uptime" -i inventory.ini
ansible node4 -m command -a "uptime" -i inventory.ini
ansible node6 -m command -a "uptime" -i inventory.ini

7.3. Vérifier l'Utilisation du Disque sur le Groupe database

La commande df devrait être disponible sur toutes les distributions.

ansible database -m command -a "df -h" -i inventory.ini
  • La commande df -h permet de vérifier l’état de l’espace disque sur les serveurs du groupe database afin de diagnostiquer les éventuels problèmes liés à l'espace disponible.

7.4. Installer vim sur le Groupe database

Nous avons des conteneurs Ubuntu/Debian et AlmaLinux dans le groupe database. Nous devons utiliser le gestionnaire de paquets approprié pour chaque distribution.

7.4.1. Créer un Playbook pour Gérer les Différentes Distributions

Créez un fichier install_vim.yml :

nano install_vim.yml

Contenu :

- name: Install vim on database servers
hosts: database
become: yes
tasks:
- name: Install vim on Debian-based systems
apt:
name: vim
state: present
when: ansible_facts['os_family'] == 'Debian'

- name: Install vim on RedHat-based systems
yum:
name: vim-enhanced
state: present
when: ansible_facts['os_family'] == 'RedHat'

Explication de become: yes :

  • become: yes est une directive Ansible utilisée pour élever les privilèges lors de l'exécution des tâches.
  • Cela signifie que les commandes seront exécutées avec les droits de superutilisateur (souvent équivalent à sudo sur les systèmes Linux).

Détail du fonctionnement :

  • Lorsqu'une tâche nécessite des permissions administratives (comme l'installation de logiciels), Ansible utilise become: yes pour basculer vers l'utilisateur privilégié (root ou un autre si spécifié).
  • Par défaut, become: yes utilise sudo, mais cela peut être personnalisé (become_method peut être défini sur sudo, su, pbrun, etc.).

Exemple du playbook :

  • Hôtes ciblés : Le groupe database, qui inclut les machines node2 et node3 selon ton inventaire.
  • Tâches exécutées :
    1. Si le système est basé sur Debian (par exemple Ubuntu, Debian), Ansible utilise le module apt pour installer vim.
    2. Si le système est basé sur RedHat (par exemple RedHat, AlmaLinux, CentOS), Ansible utilise le module yum pour installer vim-enhanced.

Sans become: yes :

  • Sans cette directive, Ansible exécuterait les commandes avec des permissions limitées (l'utilisateur SSH, souvent root, est requis par défaut).
  • Si l'utilisateur est non privilégié, certaines tâches (comme l'installation de logiciels) échoueraient sans become: yes.

Pour résumer la description du playbook du point 7.4.1, become: yes permet à Ansible d'exécuter les tâches avec des privilèges administratifs (similaire à sudo). Dans ce playbook, il est nécessaire pour installer vim sur les machines cibles (database) sans erreurs liées aux permissions.

7.4.2. Exécuter le Playbook

ansible-playbook -i inventory.ini install_vim.yml

📝 Étape 8 : Écrire et Exécuter un autre Playbook Ansible

8.1. Créer un Playbook pour Configurer Apache sur Tous les Serveurs Web

Créez un fichier configure_apache.yml :

nano configure_apache.yml

Contenu :

- name: Configure Apache on Web Servers
hosts: web
become: yes
tasks:
- name: Install Apache on Debian-based systems
apt:
name: apache2
state: present
when: ansible_facts['os_family'] == 'Debian'

- name: Start Apache on Debian-based systems
service:
name: apache2
state: started
enabled: true
when: ansible_facts['os_family'] == 'Debian'

- name: Install Apache on RedHat-based systems
yum:
name: httpd
state: present
when: ansible_facts['os_family'] == 'RedHat'

- name: Start Apache on RedHat-based systems
service:
name: httpd
state: started
enabled: true
when: ansible_facts['os_family'] == 'RedHat'

- name: Create index.html
copy:
content: "<h1>Bienvenue sur votre serveur web!</h1>"
dest: /var/www/html/index.html

Ce playbook Ansible installe et démarre le service Apache sur les serveurs web en fonction de leur système d'exploitation (apache2 pour Debian/Ubuntu, httpd pour RedHat/CentOS). Il s'assure que le service Apache est activé au démarrage. Enfin, il crée un fichier index.html avec un message de bienvenue dans le dossier racine du serveur web.

8.2. Exécuter le Playbook

ansible-playbook -i inventory.ini configure_apache.yml

🔎 Étape 9 : Vérifier le Déploiement

9.1. Obtenir les Adresses IP des Conteneurs

for i in {1..6}; do
IP=172.20.0.$((i+1))
echo "node$i IP: $IP"
done

9.2. Vérifier l'Accès aux Serveurs Web

Utilisez curl pour tester les serveurs web :

for i in 1 5; do
IP=172.20.0.$((i+1))
echo "Testing node$i at $IP:"
curl http://$IP
echo -e "\n------------------------\n"
done

Vous devriez voir le message :

<h1>Bienvenue sur votre serveur web!</h1>

🎯 Conclusion

Nous avons réussi à :

  • Installer Docker et Docker Compose.
  • Créer et démarrer plusieurs conteneurs Docker de différentes distributions.
  • Configurer l'accès SSH pour Ansible.
  • Créer un inventaire Ansible avec des groupes.
  • Exécuter des commandes spécifiques en tenant compte des différences entre les distributions.
  • Écrire et exécuter des playbooks Ansible pour automatiser des tâches.

🛠️ Conseils Supplémentaires

  • Modules Ansible Appropriés : Utilisez le module apt pour Debian/Ubuntu et yum pour RedHat/AlmaLinux.
  • Conditions dans les Playbooks : Utilisez les conditions when pour exécuter des tâches spécifiques à une distribution.
  • Installer les Paquets Nécessaires : Assurez-vous que les commandes que vous voulez utiliser sont disponibles (par exemple, installer procps pour la commande uptime sur AlmaLinux).
  • Gestion des Services : Le nom du service Apache diffère selon la distribution (apache2 vs httpd).