Lancer Nginx, PHP et Node.js avec un docker-compose.yml

À la fin de cette leçon vous saurez installer dans un serveur (ou en local) les outils Nginx, PHP et Node.js en passant par Docker.

Ci-dessous un schéma qui illustre comment les choses fonctionneront.

Gestion d'une requête via Ngninx pour PHP et Node.js.

Il faut connaître le fonctionnement de Docker pour bien comprendre cette leçon. Si ce n’est pas le cas, vous pouvez passer par la formation Docker.

Préparer : site PHP et site Node.js

Au commencement de cet exercice, nous allons préparer le terrain. Nous n’allons donc pas pour le moment nous occuper de Docker.

Pour vous y retrouver et afin de bien organiser les choses, je vous invite à vous placer à un endroit au choix dans votre machine. Créez ensuite un dossier /exercice.

mkdir exercice

Il contiendra tout notre projet.

Créez deux autres dossiers à l’intérieur de celui-ci que nous appellerons respectivement /php et /nodejs.

Ils comporteront nos deux sites internet.

cd exercice && mkdir php && mkdir nodejs

Nous rappelons que pour notre exercice, un site sera exécuté sous PHP et l’autre sous Node.js.

À ce stade, voici l’arborescence du projet.

Création du dossier exercice, php et nodejs

Site internet avec PHP

Nous allons créer un site internet très simple, juste pour le test. Pour ce faire, plaçons-nous dans le dossier /php. Nous allons créer le fichier index.php.

cd php && touch index.php

On ouvre ce fichier avec notre éditeur de texte préféré, on y inscrit le code ci-dessous.

<?php

 echo "Bonjour, je me sers de PHP.";

Nous allons maintenant tester si le site fonctionne.

Pour faire ce test, il faut que PHP soit installé au préalable sur notre machine locale, car nous allons utiliser la commande php.

Pour lancer le site en PHP, tapez la commande qui suit. Attention, il faut que le port 8888 soit libre, sinon choisissez un autre port et adaptez les commandes qui suivront.

php -S "localhost:8888"

Ouvrez votre navigateur et tapez dans la barre d’adresse : http://localhost:8888.

Normalement, vous devriez tomber sur le même résultat que celui affiché.

Site en php simple

C’est bon pour PHP 😃. Occupons-nous maintenant du site sous Node.js.

Site internet sous Node.js

Les choses se passent différemment sous Node.js.

On va aller dans notre dossier /nodejs. Si vous êtes encore dans le dossier /php, il faudra taper la commande suivante.

cd ../nodejs

Initialisons ce projet avec la commande npm init -y. Un fichier package.json sera généré.

On va maintenant installer le module express.

npm install express

Après, nous allons créer un fichier server.js.

touch server.js

Nous ouvrons ce fichier et l’on insère le code suivant.

const express = require('express');

const app = express();

app.get('/', function(req, res) {

    res.send("Bonjour, j'utilise NODEJS.");

});


app.listen(8887);

On lance ensuite le serveur.

node server.js

Et l’on ouvre notre navigateur à l’adresse : http://localhost:8887.

Site en Node.js simple

Comme vous l’avez certainement deviné, pour tester notre site Node.js, il faut qu’il soit installé dans notre ordinateur, car nous utilisons la commande node.

Deux sites prêts

À ce stade, nous avons deux sites internet. Un qui fonctionne sous PHP et l’autre sous Node.js.

Ils serviront pour tester lorsque nous les utiliserons avec Docker.

Car pour le moment ces sites jouent leur rôle, mais « à l’ancienne » et en local. Notre objectif dans cette leçon est de les déployer à partir d’un serveur web qui jouera le rôle de proxy inverse (Nginx) avec des conteneurs Docker.

C’est ce que nous verrons à partir de maintenant.

À l’heure actuelle, nous avons cette arborescence.

Création des fichiers index.php et server.js

Préparer les images Docker

Nous utiliserons des images Docker pour :

  • Nginx
  • PHP
  • Node.js

Pour bien organiser les choses, je vous invite à créer un dossier /images dans le dossier exercice.

mkdir images

Après, dans le dossier images nous allons créer trois autres dossiers qui porteront les noms, nginx, php et node.

cd images && mkdir nginx php node

Dans chacun de ces trois dossiers, nous allons créer un fichier Dockerfile.

Répéter la commande qui suit dans chacun des dossiers nginx, php et node.

touch Dockerfile

Maintenant, vous devriez avoir l’arborescence suivante.

Créer les fichiers Dockerfile

Remplir les Dockerfiles

Nous utiliserons des images légères qui seront basées sur Alpine Linux.

① Dockerfile : Nginx

Nous remplirons le Dockerfile de Nginx avec le contenu suivant.

FROM nginx:1.19-alpine
RUN apk update && apk add nano bash

En plus de l’image Nginx, nous ajoutons une commande qui nous donnera la possibilité d’utiliser bash et Nano (un éditeur de texte). Ces outils nous seront utiles plus tard.

② Dockerfile : PHP

Pour celui de PHP, nous insérons le texte ci-dessous.

FROM php:7.4.16-fpm-alpine

Un Dockerfile très simple avec PHP-FPM.

③ Dockerfile : Node

FROM node:16.13.2-alpine
WORKDIR /www
EXPOSE 8887
CMD ["node", "server.js"]

Comme la manipulation d’un projet Node.js est différente d’un projet PHP, le Dockerfile contient d’autres informations.

Les instructions de cette image nous permettent de baser notre image sur une image Node.js, de nous positionner dans le dossier /www et d'exécuter une commande qui nous permettra de lancer notre serveur Node.js.

Instructions du docker-compose.yml

Continuons 😌 ! Placez-vous dans le dossier /exercice. Et tapez la commande ci-dessous pour créer notre fichier docker-compose.yml.

touch docker-compose.yml

Ouvrez le fichier nouvellement créé avec un éditeur et commencez par le remplir avec les données suivantes.

version: '3'

services:

  nginx:
    build: images/nginx/


  php:
    build: images/php/

  node:
    build: images/node/

Nous avons ici trois services :

  • nginx
  • php
  • node

Ils sont basés sur des images qui seront générées (ou construite) à partir de leur Dockerfile respectif.

Avant d’exécuter les instructions du docker-compose.yml, nous allons y ajouter d’autres informations.

version: '3'

services:

  nginx:
    build: images/nginx/

  php:
    build: images/php/

  node:
    build: images/node/

# Volume managé ajouté
volumes:
  nginx_conf:

Un volume managé a été créé. Il nous servira à garder en mémoire les fichiers de configuration de Nginx. Nous nous en servirons plus tard.

Continuons à ajouter des informations dans notre docker-compose.yml.

version: '3'

services:

  nginx:
    build: images/nginx/
    # Volumes ajoutés
    volumes:
      - nginx_conf:/etc/nginx/
      - ./php:/www

  php:
    build: images/php/
    # Volume ajouté
    volumes:
      - ./php:/www

  node:
    build: images/node/
    # Volume ajouté
    volumes:
      - ./nodejs:/www

volumes:
  nginx_conf:

Des volumes ont été ajoutés.

Dans le service Nginx, nous ajoutons le volume managé que nous avons créé au préalable pour le connecter au dossier de configuration de Nginx dans notre conteneur. Nous avons également mappé le dossier /php qui contient notre site en PHP avec un dossier de notre conteneur : /www.

Pour le service php, nous avons aussi mappé le dossier /php avec le dossier /www de ce conteneur.

Et pour Node.js, c’est le dossier avec notre site en Node.js, /nodejs qui a été connecté au dossier /www de ce conteneur.

Noter qu’il n’est pas utile de mapper le site en Node.js dans notre conteneur nginx, contrairement au dossier /php. Pour la simple et bonne raison que PHP et Node.js ne seront pas gérés de la même façon par Nginx.

Mapper les ports dans le docker-compose.yml

Il nous faut ajouter encore une dernière chose dans notre docker-compose.yml. Cette ligne en plus consistera à mapper le port 80 de notre conteneur avec le port 80 de notre machine locale (ou celui de notre serveur physique).

version: '3'

services:

  nginx:
    build: images/nginx/
    volumes:
      - nginx_conf:/etc/nginx/
      - ./php:/www
    # Port ajouté
    ports:
      - "80:80"

  php:
    build: images/php/
    volumes:
      - ./php:/www

  node:
    build: images/node/
    volumes:
      - ./nodejs:/www

volumes:
  nginx_conf:

Et voilà 🥵 ! Notre fichier docker-compose.yml est prêt. Il ne nous reste plus qu’à le lancer et ensuite à configurer Nginx.

Lancer le docker-compose.yml

Pour exécuter notre fichier docker-compose.yml, tapons la commande suivante (il faut se positionner dans le dossier /exercice avant).

docker-compose up -d

Ensuite, dans un navigateur tapez http://localhost (ou http://localhost:80).

La belle page par défaut de Nginx apparaît 😎.

Page d'accueil par défault du serveur web Nginx

C’est très bien, mais ce qui nous serait utile c’est d’afficher nos sites personnels (en PHP et en Node.js).

Pour atteindre cet objectif, il faut modifier un fichier de configuration.

Modification du fichier de configuration du conteneur Nginx

Nous allons nous occuper du fichier de configuration de Nginx qui se trouve dans /etc/nginx/conf.d/default.conf.

Pour ce faire, listons les conteneurs actifs.

docker ps
CONTAINER ID   IMAGE            COMMAND                  CREATED         STATUS         PORTS                NAMES
7019624db605   exercice_nginx   "/docker-entrypoint.…"   3 seconds ago   Up 2 seconds   0.0.0.0:80->80/tcp   exercice_nginx_1
a0e1e20760c3   exercice_node    "docker-entrypoint.s…"   3 seconds ago   Up 2 seconds   8887/tcp             exercice_node_1
b6c0b77080f9   exercice_php     "docker-php-entrypoi…"   3 seconds ago   Up 2 seconds   9000/tcp             exercice_php_1

Nos trois conteneurs (basés sur trois images : Nginx, PHP et Node.js) apparaissent.

Nous allons entrer dans notre conteneur Nginx.

Bien entendu, les id des conteneurs qui apparaîtront dans votre machine ne seront pas comme les miens.

docker exec -it <id> bash
# Dans mon cas : docker exec -it 7019624db605 bash

Nous sommes maintenant dans notre conteneur Nginx et on va se diriger vers le dossier qui contient notre fichier de configuration.

cd /etc/nginx/conf.d/

On utilisera nano qui est un éditeur de texte pour ouvrir notre fichier.

nano default.conf

Normalement, nano devrait être présent dans Nginx, car nous avons paramétré notre image de telle sorte que cet éditeur soit présent. Si ce n’est pas le cas, vérifiez le Dockerfile de Nginx.

On tombe sur le fichier de configuration avec énormément d’informations 😳. L'objectif de cette leçon n'est pas d'expliquer comment fonctionne Nginx. Sinon elle serait encore plus longue qu'elle ne l’est actuellement.

Mais on va essayer de simplifier les choses et on n’entrera pas dans le détail du pourquoi du comment.

Fichier default.conf de Nginx

Notre fichier default.conf étant ouvert, nous pouvons commencer à paramétrer Nginx.

Le mieux c'est de partir de zéro et de supprimer tout le contenu de notre default.conf.

Rappelons ce que permet de faire ce fichier.

Nginx nous donne la possibilité de récupérer une requête pour ensuite l'orienter à un endroit bien précis. Et bien, default.conf permet de savoir quoi faire selon le numéro du port ou le nom de domaine qui est utilisé.

Dans ce fichier, un bloc server est utilisé pour expliquer chaque cas de figure. Et selon nos besoins, nous pouvons créer plusieurs blocs server.

Comprendre le fonctionnement du fichier conf.d/default.cong dans Nginx

Remplir le default.conf pour le site PHP

On commence par notre premier server qui concernera notre site PHP.

server {

    # PHP

    listen       80;
    server_name  localhost;

    root   /www;
    index index.php;
	
    location ~ \.php$ {

        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;

    }

}

Je ne vais pas tout expliquer. Mais je vais mettre en évidence certaines lignes qui sont importantes à comprendre.

  • listen 80; : Nginx écoute sur le port 80

  • server_name localhost; : Permet à Nginx de savoir quel est le nom de domaine qui doit pointer sur ce bloc

  • root /www; : Le dossier du conteneur avec le contenu de notre site

  • fastcgi_pass php:9000; : En vulgarisant, cette instruction permet de faire une relation avec le conteneur PHP que nous avons lancé en même temps que celui de Nginx (php est le nom du service que nous avons choisi lorsque nous avons créé le docker-compose.yml et 9000 le port de connexion).

On quitte l'éditeur nano et on n’oublie pas de sauvegarder notre travail.

Pour quitter nano, utilisez le raccourci clavier CTRL + X ou si celui-ci ne fonctionne pas, référez-vous aux indications en bas de l'éditeur. Indication éditeur Nano

On va maintenant relancer Nginx avec la commande ci-dessous.

/usr/sbin/nginx -s reload

Ensuite, on retourne dans notre navigateur et l’on tape http://localhost.

Et normalement, vous tombez sur la page suivante.

Page PHP via Nginx

Si c'est le cas, cela signifie que tout a bien fonctionné 🤩. Notre site en PHP fonctionne et l’on passe bien par Nginx et des conteneurs Docker 👍 pour atteindre ce site.

Modifier le default.conf pour le site en Node.js

Nous allons maintenant nous attaquer au site Node.js 😑.

Il y a une différence entre PHP et Node.js dans la configuration du fichier default.conf.

Cependant, nous ajouterons un bloc server comme pour PHP. Ci-dessous le fichier avec le bloc server pour PHP et celui de Node.js.

server {

    # PHP

    listen       80;
    server_name  localhost;

    root   /www;
    index index.php;
	
    location ~ \.php$ {

        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;

    }

}

server {
    
    # Node.js

    listen       81;
    server_name  localhost;

    location / {

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://node:8887;

    }

}

Nous allons expliquer quelques lignes.

  • listen 81; : Cette fois-ci pour différencier notre site de PHP nous utiliserons un autre port, c'est-à-dire le n°81

  • proxy_pass http://node:8887; : node est le nom donné à notre service dans le docker-compose.yml pour le conteneur Node.js et 8887 est le port choisi dans fichier server.js de Node.js.

On enregistre et l’on quitte nano.

Et l’on relance Nginx.

/usr/sbin/nginx -s reload

Si dans mon navigateur je tape http://localhost (ou http://localhost:80), cela fonctionne bien pour le site en PHP. Mais si je tape http://localhost:81 pour afficher le site en Node.js, cela ne fonctionne pas et c'est normal 😡. Nous allons y remédier tout de suite.

Modifier le docker-compose.yml pour faire fonctionner le site en Node.js

Si vous connaissez bien le fonctionnement de Docker, vous avez peut-être compris pourquoi pour le moment le site en Node.js ne fonctionne pas.

Je vais vous montrer.

Sortons du conteneur Nginx en tapant exit.

Vous êtes maintenant dans votre machine locale. Placez-vous dans le dossier /exercice si vous ne l'êtes déjà pas.

Ouvrez le fichier docker-compose.yml et observez le service nginx de la sous-partie ports.

Que constatons-nous 🤔 ?

Que le port 80 du conteneur a bien été mappé avec le port 80 de notre machine, mais pas le port 81.

Il faut donc ajouter la relation !

version: '3'

services:

  nginx:
    build: images/nginx/
    volumes:
      - nginx_conf:/etc/nginx/
      - ./php:/www
    ports:
      - "80:80"
      # Port 81 mappé
      - "81:81"

  php:
    build: images/php/
    volumes:
      - ./php:/www

  node:
    build: images/node/
    volumes:
      - ./nodejs:/www
      
volumes:
  nginx_conf:

Enregistrez votre docker-compose.yml.

Retournez à votre terminal ou invite de commande.

Normalement, vous vous trouvez dans le dossier /exercice et dans celui-ci, il y a le docker-compose.yml que nous venons de modifier.

Tapez la commande suivante pour relancer les instructions du docker-compose.yml.

docker-compose up -d

Et enfin 🥵, utilisez votre navigateur pour taper l'adresse http://localhost:81.

Et ça fonctionne bien, on voit notre site sous Node.js 🤩.

Vous pouvez également taper http://localhost:80 pour apercevoir notre site en PHP.