![Docker Compose : Créer une stack wordpress - Notamax](https://notamax.be/wp-content/uploads/2019/12/docker_compose.png)
# **Introduction**
Docker Compose est un outil permettant de **définir le comportement de vos conteneurs** et d’**exécuter des applications Docker à conteneurs multiples**. La config se fait à partir d'un fichier YAML, et ensuite, avec une seule commande, vous **créez et démarrez tous vos conteneurs de votre configuration**.
# **Installation du docker-compose**
Docker Compose n'est pas installé par défaut et s'appuie sur le moteur Docker pour fonctionner. Au jour d'aujourd'hui, la dernière version de Docker Compose est la 1.24.0.
Voici la procédure à suivre pour **télécharger Docker Compose sous un environnement Linux** :
Si vous n'avez pas d'erreur, alors vous pouvez poursuivre la lecture de ce chapitre.
# **Docker Compose et Dockerfile**
Le but de cet article est d'améliorer notre ancienne application LAMP. Par la suite nous allons séparer le conteneur de notre application web par rapport au conteneur de notre base de données.
Au préalable, commencez par télécharger les sources du projet en cliquant [ici](https://devopssec.fr/documents/docker/docker-compose/sources.zip) et désarchivez ensuite le projet.
Profitons de cet article pour améliorer le Dockerfile de notre stack LAMP en réduisant son nombre d'instructions. Pour cela, on se basera sur une nouvelle image.
> Si vous souhaitez conteneuriser une application assez connue, alors je vous conseille de toujours fouiller dans le [_Hub Docker_](https://hub.docker.com/), afin de savoir si une image officielle de l'application existe déjà.
En cherchant dans le Hub Docker, j'ai pu dénicher les images adéquates, notamment :
- Une [image officielle php](https://hub.docker.com/_/php) avec le tag 7-apache
- Une [image officielle mysql](https://hub.docker.com/_/mysql)
Une fois que j'ai trouvé les bonnes images, je peux alors m'attaquer à la modification du Dockerfile.
Pour le moment, nous utiliserons ce Dockerfile seulement pour construire une image avec une couche OS, Apache et Php sans implémenter aucun service de base de données. Cette image se basera sur l'image officielle php avec le tag 7-apache qui vient déjà avec un OS (distribution Debian). Concernant l'image mysql nous l'utiliserons plus tard dans notre docker-compose.yml.
Dans le même dossier que vous avez désarchivé, créez un fichier Dockerfile et mettez dedans le contenu suivant :
On va débuter par la récolte des besoins du conteneur de la base de données. Pour celle-ci, il nous faudra :
- Un fichier sql pour créer l'architecture de notre base de données.
- Un volume pour stocker les données.
Avant de foncer tête baissée dans la création/modification de notre fichier sql, il toujours important de vérifier avant ce que nous propose la [page Docker Hub de l'image mysql](https://hub.docker.com/_/mysql). En lisant sa description, les informations qui m'ont le plus captivé sont ses variables d'environnements qu'on peut surcharger, notamment :
-`**MYSQL_ROOT_PASSWORD**`: spécifie le mot de passe qui sera défini pour le compte MySQL root (**c'est une variable obligatoire**).
-`**MYSQL_DATABASE**`: spécifie le nom de la base de données à créer au démarrage de l'image.
-`**MYSQL_USER**` et `**MYSQL_PASSWORD**` : utilisées conjointement pour créer un nouvel utilisateur avec son mot de passe. Cet utilisateur se verra accorder des autorisations de super-utilisateur pour la base de données `**MYSQL_DATABASE**`.
Ces variables d'environnements vont nous aider à créer une partie de l'architecture de notre base de données.
Dans la description de l'image mysql, il existe une autre information très utile. Lorsqu'un conteneur mysql est démarré, il exécutera des fichiers avec des extensions *.sh*, *.sql* et *.sql.gz* qui se trouvent dans */docker-entrypoint-initdb.d*. Nous allons profiter de cette information pour déposer le fichier *articles.sql* (disponible dans les sources téléchargées) dans le dossier */docker-entrypoint-initdb.d* afin de créer automatiquement notre table SQL.
Concernant le conteneur de l'application web, nous aurons besoin de :
- Une communication avec le conteneur de la base de données.
- Un volume pour stocker les sources de l'application web.
Me concernant la seule information utile dans la description de [la page Docker Hub de l'image php](https://hub.docker.com/_/php), est qu'il est possible d'installer et d'activer les modules php dans le conteneur php avec la commande docker-php-ext-install (C'est la commande utilisée dans notre Dockerfile afin d'activer le module pdo et pdo\_mysql).
Histoire de vous donner une idée sur la longueur de la commande docker run sans utiliser le fichier docker-compose.yml. Je vais alors l'utiliser pour démarrer les différents conteneurs de notre application.
Premièrement je vais vous dévoiler, deux nouvelles options de la commande docker run :
-`**-e**` : définit/surcharge des variables d'environnement
-`**--link**` : ajoute un lien à un autre conteneur afin de les faire communiquer entre eux.
Dans cet exemple, on peut vite remarquer que les commandes docker run sont assez longues et par conséquent elles ne sont pas assez lisibles. De plus, vous aurez à lancer cette commande pour chaque nouveau démarrage de l'application. Mais vous aurez aussi à gérer vos différents conteneurs séparément. C'est pour ces raisons, que nous utiliserons le fichier docker-compose.yml afin de **centraliser la gestion de nos multiples conteneurs d'une application Docker depuis un seul fichier**. Dans notre cas il va nous permettre d' **exécuter et définir les services, les volumes et la mise en relation des différents conteneurs** de notre application.
Commencez d'abord par créer un fichier et nommez le *docker-compose.yml*, ensuite copiez collez le contenu ci-dessous. Par la suite, plus bas dans l'article, je vais vous fournir les explications des différentes lignes de ce fichier :
Il existe plusieurs versions rétrocompatibles pour le format du fichier Compose (voici la [liste des versions de Docker Compose selon la version moteur Docker](https://docs.docker.com/compose/compose-file/)). Dans mon cas je suis sous la version 18.09.7 du moteur Docker, donc j'utilise la version 3.7.
Dans une application Docker distribuée, différentes parties de l'application sont appelées **services**. Les services ne sont en réalité que des conteneurs. Dans notre cas nous aurons besoin d'un service pour notre base de données et un autre pour notre application web.
Dans cette partie, on crée un service nommé `**db**`. Ce service indique au moteur Docker de procéder comme suit :
1. Se baser sur l'image `**mysql:5.7**`
2. Nommer le conteneur `**mysql_c**`
3. Le `restart: always` démarrera automatiquement le conteneur en cas de redémarrage du serveur
4. Définir les volumes à créer et utiliser (un volume pour exécuter automatiquement notre fichier sql et un autre pour sauvegarder les données de la base de données)
5. Surcharger les variables d'environnements à utiliser
Placez vous au niveau du dossier qui contient le fichier docker-compose.yml. Ensuite lancez la commande suivante pour **exécuter les services du docker-compose.yml** :
myapp_c docker-php-entrypoint apac ... Up 0.0.0.0:8080->80/tcp
mysql_c docker-entrypoint.sh mysqld Up 3306/tcp, 33060/tcp
```
Si jamais vos conteneurs ne sont pas dans l'état `**UP**`, alors **vérifiez les logs des services de votre Docker Compose** en tapant la commande suivante :
Si tout c'est bien passé, alors visitez la page suivante [http://localhost:8080/](http://localhost:8080/), et vous obtiendrez le résultat suivant :
![image docker avec une stack lamp en utilisant le docker-compose](https://devopssec.fr/images/articles/docker/docker-compose/docker-compose-lamp-app.jpg)
Remplissez le formulaire de l'application, et **tuez les conteneurs du docker-compose.yml**, avec la commande suivante :
Je ne vais pas trop rentrer dans les détails sur la partie réseau, car je vais rédiger un article qui sera dédié à cette partie. Mais sachez juste qu'un réseau bridge est créé par défaut, plus précisément c'est l'interface docker0 (`ip addr show docker0`), c'est un **réseau qui permet une communication entre les différents conteneurs**.
Donc **les conteneurs possèdent par défaut une adresse ip**. Vous pouvez récolter cette information grâce à la commande suivante :
Pour faire communiquer notre application web avec la base de données, on peux utiliser dans le conteneur de l'app web soit l'ip, le nom du service (ici `**db**`) ou le nom du conteneur (ici `**mysql_c**`) de la base de données.
Si vous ouvrez le fichier `*db-config.php*` dans le dossier `*app*`, alors vous verrez la ligne suivante :
```php
const DB_DSN = 'mysql:host=mysql_c;dbname=test';
```
Dans ces cas, j'ai utilisé le nom du conteneur de la base de données pour communiquer avec ce dernier.
# **Conclusion**
Je pense que vous l'aurez compris, le Docker Compose est un outil permettant de faciliter la gestion des applications Docker à conteneurs multiples, comme :
- Démarrer, arrêter et reconstruire des services
- Afficher le statut des services en cours d'exécution
- Diffuser la sortie des logs des services en cours d'exécution
- Exécuter une commande unique sur un service
- etc ...
Comme pour chaque fin de chapitre, je vous liste ci-dessous un récapitulatif de quelques commandes intéressantes du Docker Compose: