Ce fichier décrit la solution au TP Docker avancé, année scolaire 2018-19 Pôle sup de la salle - https://www.polesup-delasalle.fr/formations/nos-formations/securite-informatique-bac3/?parent=/formations-pole-sup-de-la-salle
Dans un répertoire nommé bsi-nginx
On part de l'image debian stretch en version slim, dans laquelle on installe le paquet nginx :
FROM debian:stretch-slim
RUN apt update && apt install -y nginx
A ce stade, on peut déjà créer l'image et naviguer dedans grâce à un shell :
root@debian:/home/user/BSI/bsi-nginx# docker build -t bsi/nginx .
Sending build context to Docker daemon 7.168kB
Step 1/2 : FROM debian:stretch-slim
---> c08899734c03
Step 2/2 : RUN apt update && apt install -y nginx
---> Using cache
---> 5d2c1d83d9cd
Successfully built 5d2c1d83d9cd
Successfully tagged bsi/nginx:latest
root@debian:/home/user/BSI/bsi-nginx# docker run -it bsi/nginx
root@2b312cff4e13:/# ls -l /etc/nginx/sites-available/
total 4
-rw-r--r-- 1 root root 2416 Nov 7 05:40 default
root@2b312cff4e13:/# exit
exit
root@debian:/home/user/BSI/bsi-nginx#
On va extraire le fichier de configuration du site par défaut, et le modifier en dehors de l'image. Pour cela, il suffit de redémarrer un conteneur en lui imposant la commande cat /etc/nginx/sites-available/default
. Ce conteneur se termine dès que la commande cat a fini de s'exécuter.
root@debian:/home/user/BSI/bsi-nginx# docker run -it bsi/nginx cat /etc/nginx/sites-available/default > server.conf
root@debian:/home/user/BSI/bsi-nginx# ls -l default
-rw-r--r-- 1 root root 2507 avril 20 16:43 default
On le modifie de la manière suivante afin de servir :
- le répertoire /var/www/html
- en http et https
- les scripts PHP étant exécutés sur le serveur fastCGI hébergé par localhost (que nous changerons plus tard), en écoute sur le port 9000.
server {
listen 80 default_server;
listen [::]:80 default_server;
# SSL configuration
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
#
# Self signed certs generated by the ssl-cert package
# Don't use them in a production server!
#
include snippets/snakeoil.conf;
root /var/www/html;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
server_name _;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
# pass PHP scripts to FastCGI server
location ~ \.php$ {
include snippets/fastcgi-php.conf;
# # With php-cgi (or other tcp sockets):
fastcgi_pass localhost:9000;
}
}
On modifie alors le Dockerfile pour copier ce fichier lors du build de l'image, et exécuter nginx comme commande par défaut au démarrage du conteneur :
FROM debian:stretch-slim
RUN apt update && apt install -y nginx
RUN rm /etc/nginx/sites-enabled/default
COPY server.conf /etc/nginx/sites-available/server.conf
RUN ln -s /etc/nginx/sites-available/server.conf /etc/nginx/sites-enabled/server.conf
CMD nginx -g "daemon off; error_log stderr info;"
Après un nouveau build, on peut voir que nginx échoue à démarrer car les certificats ne sont pas créés (et le fichier de config nous expliquait bien qu'il utilisait les fichiers créés par le paquet ssl-cert
) :
root@debian:/home/user/BSI/bsi-nginx# docker run -it -p 8000:80 bsi/nginx
nginx: [emerg] BIO_new_file("/etc/ssl/certs/ssl-cert-snakeoil.pem") failed (SSL: error:02001002:system library:fopen:No such file or directory:fopen('/etc/ssl/certs/ssl-cert-snakeoil.pem','r') error:2006D080:BIO routines:BIO_new_file:no such file)
On adapte le Dockerfile pour ajouter le paquet manquant :
FROM debian:stretch-slim
RUN apt update && apt install -y nginx ssl-cert
RUN rm /etc/nginx/sites-enabled/default
COPY server.conf /etc/nginx/sites-available/server.conf
RUN ln -s /etc/nginx/sites-available/server.conf /etc/nginx/sites-enabled/server.conf
CMD nginx -g "daemon off; error_log stderr info;"
Après avoir relancé un conteneur avec la commande précédente, la page d'accueil de nginx s'affiche correctement lorsqu'on ouvre l'URL http://localhost:8000/ depuis l'hôte. L'image créée apparait dans la liste des images locales du système :
root@debian:/home/user/BSI/bsi-nginx# sudo docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
bsi/nginx latest 65f34d00cc5c 2 hours ago 129MB
Ajoutons enfin à l'image un fichier de test permettant de tester la bonne exécution des scripts PHP :
FROM debian:stretch-slim
RUN apt update && apt install -y nginx ssl-cert
RUN rm /etc/nginx/sites-enabled/default
COPY server.conf /etc/nginx/sites-available/server.conf
RUN ln -s /etc/nginx/sites-available/server.conf /etc/nginx/sites-enabled/server.conf
RUN echo '<?php phpinfo(); ?>' > /var/www/html/phpinfo.php
CMD nginx -g "daemon off; error_log stderr info;"
Dans un répertoire nommé bsi-php
Le fichier Dockerfile suivant permet d'installer le paquet php-fpm
et le module MySQL pour php. La commande sed
permet de remplacer la directive de configuration :
listen = /run/php/php7.0-fpm.sock
par :
listen = 9000
dans le fichier de configuration /etc/php/7.0/fpm/pool.d/www.conf
FROM debian:stretch-slim
RUN apt update && apt install -y php-fpm php-mysql
RUN sed -i -e 's#listen = /run/php/php7.0-fpm.sock#listen = 9000#' /etc/php/7.0/fpm/pool.d/www.conf
RUN mkdir /run/php
RUN mkdir -p /var/www/html && echo '<?php phpinfo(); ?>' > /var/www/html/phpinfo.php
CMD /usr/sbin/php-fpm7.0 --nodaemonize
Enfin, la commande par défaut permet de démarrer le démon PHP-FPM lorsque le conteneur est créé.
Par défaut, différents conteneurs Docker ne peuvent pas se joindre. Nous devons créer un réseau interne pour cela, ici nommé webserver :
root@debian:/home/user/BSI# docker network create webserver
cb2bdbee24279529f31c882b8959cda0c42fae9b0f2b88fa94c3093fba49b11b
Démarrons le conteneur PHP-FPM, connecté au réseau webserver :
root@debian:/home/user/BSI# docker run --network webserver --name php bsi/php
Ce conteneur porte le nom php, ce qui permet aux autre conteneurs accrochés au réseau webserver d'utiliser le serveur DNS interne de Docker pour résoudre son adresse IP. Par exemple ici en utilisant un conteneur debian:stretch :
user@debian:~$ sudo docker run --network webserver debian:stretch ping php
PING php (172.18.0.2) 56(84) bytes of data.
64 bytes from php.webserver (172.18.0.2): icmp_seq=1 ttl=64 time=0.153 ms
64 bytes from php.webserver (172.18.0.2): icmp_seq=2 ttl=64 time=0.254 ms
64 bytes from php.webserver (172.18.0.2): icmp_seq=3 ttl=64 time=0.195 ms
64 bytes from php.webserver (172.18.0.2): icmp_seq=4 ttl=64 time=0.299 ms
64 bytes from php.webserver (172.18.0.2): icmp_seq=5 ttl=64 time=0.178 ms
^C
--- php ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4078ms
rtt min/avg/max/mdev = 0.153/0.215/0.299/0.056 ms
Nous devons donc modifier le fichier bsi-nginx/server.conf
pour modifier la direcctive fastcgi_pass
ainsi, avant de recréer (docker build) l'image bsi/nginx :
fastcgi_pass php:9000;
Démarrons désormais le conteneur nginx :
root@debian:/home/user/BSI/bsi-nginx# docker run --network webserver -p 8000:80 bsi/nginx
L'URL http://localhost:8000/phpinfo.php affiche désormais le script phpinfo, ce qui permet de vérifier que nginx dialogue correctement avec le conteneur php-fpm.
Important
Lorsque nginx appelle FastCGI pour lui faire exécuter un script PHP, il lui fournit le chemin du script à exécuter, soit dans notre exemple précédent
/var/www/html/phpinfo.php
. Le conteneur qui exécute PHP-FPM doit donc posséder lui aussi ce script PHP dans son répertoire/var/www/html
, sinon le démon PHP-FPM renverra lui-même une erreur HTTP 404.
Pour simplifier cette étape, nous allons utiliser une image MariaDB toute faite, le meilleur choix étant l'image officielle : https://hub.docker.com/_/mariadb
Cette image requiert la variable d'environnement MYSQL_ROOT_PASSWORD
pour démarrer, comme décrit dans l'exemple du Docker hub :
$ docker run --name some-mariadb -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mariadb
Il faut commencer par télécharger le script Wordpress depuis la page https://fr.wordpress.org/download/, puis extraire ces fichiers dans le répertoire wordpress
.
root@debian:/home/user/BSI/wordpress# docker run --network webserver --name php -v $(pwd)/wordpress:/var/www/html -it bsi/php
Les varaibles d'environnement permettent de créer une base wordpress et un utilisateur au démarrage de la base de données :
root@debian:/home/user/BSI/bsi-nginx# docker run --name mariadb -e MYSQL_ROOT_PASSWORD=my-secret-pw -e MYSQL_DATABASE=wordpress -e MYSQL_USER=wordpress -e MYSQL_PASSWORD=wordpress --network webserver mariadb
root@debian:/home/user/BSI# docker run --network webserver -p 8000:80 -v $(pwd)/wordpress:/var/www/html bsi/nginx
En ouvrant la page http://localhost:8000 sur l'hôte, on peut désormais configurer Wordpress pour qu'il se connecte sur la base utilisant le hostname mariadb, avec l'identifiant wordpress, le mot de passe wordpress et la base wordpress.
Mais que se passe-t-il si un conteneur plante ? Si la base est arrêtée avec la commande docker stop mariadb
?