Lorsque l'on va travailler avec Docker, on va essayer de donner des responsabilités limitées à chacun de nos conteneurs. Typiquement, si on souhaite mettre en place un site web sur Docker, on ne va pas imaginer un conteneur dans lequel on aurait à la fois nginx, php, mariadb... Mais plutôt trois conteneurs qui communiquent ensemble. Et pour cela, au lieu de créer nos conteneurs à la main avec la commande docker run, nous allons utiliser docker-compose.
Si vous êtes sur linux, vous aurez besoin d'installer Docker-Compose. Pour les utilisateurs Mac ou Windows, il est déjà inclût dans votre application Desktop.
Le principe de docker-compose, ça va être de décrire dans un fichier docker-compose.yaml les conteneurs que vous souhaitez avoir ainsi que leurs dépendances.
Si on reprend mon exemple, mon fichier docker-compose.yaml devrait ressembler à quelque chose comme ça
# docker-compose.yaml
# Je définis la version de mon docker-compose ( dernière version au moment où j'écris cet article )
version: '3.8'
services:
db:
# Ma première image, mariadb, pour ma base de données
image: mariadb:10.5.6
environment:
# Vu que je suis en dev, je désactive le mot de passe pour plus de simplicité
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
volumes:
# J'ajoute le volume data sur mon système. En faisant ça, même si je supprime l'intégralité de mes conteneurs et volumes ( avec la commande docker system prune par exemple ), je ne perdrai pas mes données
- ./data:/var/lib/mysql
app:
image: php:7.4.12-fpm-alpine
depends_on:
# Je définis une dépendance entre mes conteneurs. PHP a besoin de la base de donnée pour fonctionner
- db
volumes:
# Grace à ce volume, mon conteneur pourra traiter mon code PHP présent dans mon répertoire
- ./:/var/www/html/
nginx:
image: nginx:1.19.3-alpine
depends_on:
# Nginx a besoin de PHP pour fonctionner
- app
volumes:
- ./:/usr/share/nginx/html
ports:
# Mon serveur web sera accessible sur le port 8080
- 8080:80
En théorie, j'aimerai que ma stack ressemble à ça. Voyons voir un peu comment tout ça fonctionne.
Pour commencer, je vais créer un répertoire ma_stack dans lequel je vais mettre ce fichier docker-compose.yaml. Je vais également mettre un fichier index.html contenant un simple Hello World.
Ensuite, je démarre ma stack en tapant la commande suivante
❯ docker-compose up -d
Creating network "demo_docker_default" with the default driver
Creating demo_docker_db_1 ... done
Creating demo_docker_app_1 ... done
Creating demo_docker_nginx_1 ... done
Pour m'assurer que tous les conteneurs sont là, je vais lancer la commande suivante
❯ docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------------------
demo_docker_app_1 docker-php-entrypoint php-fpm Up 9000/tcp
demo_docker_db_1 docker-entrypoint.sh mysqld Up 3306/tcp
demo_docker_nginx_1 /docker-entrypoint.sh ngin ... Up 0.0.0.0:8080->80/tcp
Je vois que mes trois conteneurs sont up et que seul nginx expose un port sur ma machine physique comme je lui avais demandé dans le docker-compose.yaml.
Si vous souhaitez voir les logs de l'un de ces conteneurs, il est possible d'utiliser la commande logs. Très pratique pour analyser et comprendre un problème.
❯ docker-compose logs -f nginx
Attaching to demo_docker_nginx_1
nginx_1 | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
nginx_1 | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
nginx_1 | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
nginx_1 | 10-listen-on-ipv6-by-default.sh: Getting the checksum of /etc/nginx/conf.d/default.conf
Dans le répertoire ma_stack, vous devriez voir maintenant un nouveau répertoire data. Il s'agit des données de mariadb disponible sur notre machine physique grâce au montage de volume que nous avons fait dans notre fichier docker-compose.yaml.
Si vous vous rendez sur http://localhost:8080, vous devriez bien voir votre hello world qui correspond à votre fichier index.html.
Cela commence plutôt bien, mais ce qui m'intéresse avant tout c'est de faire communiquer ces trois conteneurs les uns avec les autres. Pour commencer, je vais me rendre dans mon conteneur nginx grâce à la commande exec pour voir si il a accès au conteneur app.
❯ docker-compose exec nginx sh
/ # ping app
PING app (172.22.0.3): 56 data bytes
64 bytes from 172.22.0.3: seq=0 ttl=64 time=0.103 ms
64 bytes from 172.22.0.3: seq=1 ttl=64 time=0.149 ms
64 bytes from 172.22.0.3: seq=2 ttl=64 time=0.156 ms
C'est le cas ! Il répond bien au ping 😄 Vous pouvez essayer la même manipulation dans votre conteneur app en faisant un ping vers db, cela fonctionnera également.
Notre première mission, ça va être de faire en sorte que nginx fonctionne correctement avec php-fpm. On va modifier un peu notre docker-compose.yaml
...
app:
image: php:7.4.12-fpm-alpine
depends_on:
- db
volumes:
- ./:/srv/app
nginx:
image: nginx:1.19.3-alpine
depends_on:
- app
volumes:
- ./:/srv/app
- ./docker/nginx/conf.d:/etc/nginx/conf.d
ports:
- 8080:80
Ce que j'ai modifié, ce sont seulement les volumes. Au lieu d'envoyer notre code dans le répertoire par défaut html, je décide de l'envoyer sur /srv/app. Le deuxième montage concerne la configuration de nginx ( /etc/nginx/conf.d ). Je vais donc créer le répertoire docker/nginx/conf.d dans lequel je vais mettre le fichier default.conf suivant
server {
# Je définis la racine de nginx sur /srv/app ( qui correspond au volume sur lequel est mon projet )
root /srv/app;
# Le point d'entré, c'est index.php
index index.php;
location ~ \.php$ {
try_files $uri =404;
# On retrouve ici app qui correspond à notre conteneur php-fpm
fastcgi_pass app:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /srv/app$fastcgi_script_name;
include fastcgi_params;
}
}
Maintenant que l'on a fait ça, on va remplacer notre index.html par un index.php dans lequel on va mettre un simple echo 'Hello World';
On va pouvoir tester tout ça. Dans un premier temps, on va arrêter nos conteneurs et les détruire.
❯ docker-compose down
Stopping demo_docker_nginx_1 ... done
Stopping demo_docker_app_1 ... done
Stopping demo_docker_db_1 ... done
Removing demo_docker_nginx_1 ... done
Removing demo_docker_app_1 ... done
Removing demo_docker_db_1 ... done
Removing network demo_docker_default
Puis, on va redémarrer nos conteneurs avec la commande docker-compose up -d
Une fois que c'est fait, vous devriez voir à nouveau votre Hello World 😄 Pour être certain que notre conteneur app est bien sollicité, on va utiliser la commande suivante
❯ docker-compose logs -f app
Attaching to demo_docker_app_1
app_1 | [02-Nov-2020 14:25:18] NOTICE: fpm is running, pid 1
app_1 | [02-Nov-2020 14:25:18] NOTICE: ready to handle connections
app_1 | 192.168.48.4 - 02/Nov/2020:14:25:20 +0000 "GET /index.php" 200
Victoire ! 🎉 Pour le moment, j'ai donc un conteneur nginx capable de communiquer avec mon conteneur app. La prochaine étape va être de faire la connexion avec la base de données.