Dans cet article, je vais configurer une répartition de charge qui va dispatcher le trafic vers 3 serveurs web nginx. Ces 4 serveurs sont tous hébergés sur des conteneurs docker.

Sommaire

Environnement

  • Ubuntu 19.10
  • Docker version 19.03.2

Attention : Toutes les commandes docker lancées ici le sont en tant qu’utilisateur root. Faites attention à ce que vous faites !

Situation cible

Le schéma ci-dessous indique la configuration cible.

Schéma de l'architecture

Serveurs web nginx

La première étape consiste à créer un fichier index.html différent dans votre répertoire de travail, pour chaque serveur web, afin de pouvoir les identifier facilement lors des tests.

 ~/Documents/reverse-proxy $ mkdir www1
 ~/Documents/reverse-proxy $ echo "<h1>Hello 1</h1>" > www1/index.html
 ~/Documents/reverse-proxy $ mkdir www2
 ~/Documents/reverse-proxy $ echo "<h1>Hello 2</h1>" > www2/index.html
 ~/Documents/reverse-proxy $ mkdir www3
 ~/Documents/reverse-proxy $ echo "<h1>Hello 3</h1>" > www3/index.html
 ~/Documents/reverse-proxy $ tree ./
./
├── www1
│   └── index.html
├── www2
│   └── index.html
└── www3
    └── index.html

Une fois que les fichiers sont crées, on peut lancer les conteneurs. Les conteneurs utilisés sont les conteneurs nginx de base.

nginx1

 ~/Documents/reverse-proxy $ docker container run --rm \
    --name nginx1 \
    -v /home/fox/Documents/reverse-proxy/www1:/usr/share/nginx/html:ro \
    -d \
    -p 8081:80 \ 
    nginx

nginx2

~/Documents/reverse-proxy $ docker container run --rm \
    --name nginx2 \
    -v /home/fox/Documents/reverse-proxy/www2:/usr/share/nginx/html:ro \
    -d \
    -p 8082:80 \ 
    nginx

nginx3

 ~/Documents/reverse-proxy $ docker container run --rm \
    --name nginx3 \
    -v /home/fox/Documents/reverse-proxy/www3:/usr/share/nginx/html:ro \
    -d \
    -p 8083:80 \ 
    nginx

Options utilisées

docker container run : Permet de lancer le conteneur.
--rm : indique à docker de supprimer le conteneur ainsi que son système de fichiers.
--name : donne un nom au conteneur. Si cette option n’est pas indiquée, un nom aléatoire sera donné.
-v : indique les volumes à monter dans le conteneur. Dans ce cas-là, je monte en lecture (option ro à la fin) le répertoire www1, www2 ou www3 de mon hôte local à l’emplacement /usr/share/nginx/html du conteneur. Ce répertoire est le répertoire par défaut permettant de stocker les fichiers HTML servis par nginx. Il est important de mettre le chemin absolu pour identifier les répertoires locaux.
-d : permet de détacher le conteneur du terminal actuel. Pour se connecter au conteneur par la suite, on utilise la commande docker container exec -it <nom_du_conteneur> /bin/bash.
-p : mappe le port du host local sur le port du conteneur.
nginx : indique quel modèle de conteneur utiliser.

Vérifications

Une fois que les 3 conteneurs sont lancés, on peut vérifier qu’ils sont bien lancés :

 ~fox/Documents/reverse-proxy $ docker container ps
CONTAINER ID    IMAGE     COMMAND                  CREATED        STATUS        PORTS                  NAMES
3daa11c28579    nginx     "nginx -g 'daemon of…"   4 hours ago    Up 4 hours    0.0.0.0:8083->80/tcp   nginx3
0cc187ff28b4    nginx     "nginx -g 'daemon of…"   4 hours ago    Up 4 hours    0.0.0.0:8082->80/tcp   nginx2
9239a53b4480    nginx     "nginx -g 'daemon of…"   4 hours ago    Up 4 hours    0.0.0.0:8081->80/tcp   nginx1

On va également tester leur bon fonctionnement en se rendant aux l’URL http://127.0.0.1:8081, http://127.0.0.1:8082 et http://127.0.0.1:8083 afin d’accéder respectivement à nginx1, nginx2 et nginx3. On devrait voir s’afficher les pages suivantes

Répartiteur de charge nginx

La répartition de charge du trafic est également effectuée par un conteneur docker nginx. Pour les serveurs web, le fichier de configuration par défaut était suffisant, mais ce n’est pas le cas pour le loadbalancer. Il va donc falloir créer un fichier de configuration spécifique, et le rendre accessible au conteneur. En effet, ce n’est pas conseillé de modifier la configuration directement dans le conteneur, car celle-ci serait perdue en cas de redémarrage de celui-ci.

Fichier de configuration nginx

Les lignes importantes à modifier/ajouter sont les lignes 6 à 10 et 16 à 20.

Les premières permettent d’indiquer les serveurs destination de la répartition de charge. si aucune option n’est ajoutée avant la liste des serveurs, ils vont être choisis en mode round robin, donc les uns après les autres dans la liste. Il est possible une répartition selon le nombre de connexion (option least_conn;) ou encore un hash IP en fonction de l’adresse IP source utilisée (option ip_hash;). Il est également possible d’assigner un poids à chaque serveur, en indiquant l’option weight=x sur la même ligne que la déclaration du serveur.

Remarque : Pour récupérer l’adresse IP de chaque conteneur docker nginx, on peut utiliser la commande suivante :

~/Documents/reverse-proxy $ docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <nom_du_conteneur>

Une fois les adresse IP récupérées, on peut les indiquer dans le fichier de configuration nginx.

events {
    worker_connections  1024;
}

http {
    upstream backend {
        server 172.17.0.2;
        server 172.17.0.3;
        server 172.17.0.4;
    }

    server {
        listen 80 default_server;

        location / {
        	proxy_redirect      off;
	        proxy_set_header    X-Real-IP $remote_addr;
	        proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
	        proxy_set_header    Host $http_host;
            proxy_pass http://backend;
        }
    }
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    include /etc/nginx/conf.d/*.conf;

}

Ce fichier de configuration est mis dans un répertoire rp pour être utilisé par le conteneur.

 ~/Documents/reverse-proxy $ tree ./
./
├── rp
│   └── nginx.conf
├── www1
│   └── index.html
├── www2
│   └── index.html
└── www3
    └── index.html

Une fois que le fichier de configuration est correctement crée, on peut lancer le conteneur.

 ~/Documents/reverse-proxy $ docker container run --rm \
    --name rp \
    -v /home/fox/Documents/reverse-proxy/rp/nginx.conf:/etc/nginx/nginx.conf:ro 
    -d \ 
    -p 80:80 \ 
    nginx

Les options utilisées ici sont les mêmes que pour le lancement des serveurs web, à l’exception près qu’on ne mappe plus un répertoire sur un répertoire, mais un fichier sur un autre fichier.

Informations sur les conteneurs

Nom du conteneurAdresse IPPort en écoute
host172.17.0.1N.A.
nginx1172.17.0.28081
nginx2172.17.0.28082
nginx3172.17.0.28083
rp172.17.0.280

Vérifications

Une fois que le loadbalancer est lancé, on peut a nouveau vérifier que tous nos conteneurs fonctionnent bien.

 ~fox/Documents/reverse-proxy $ docker container ps
CONTAINER ID    IMAGE     COMMAND                  CREATED        STATUS        PORTS                  NAMES
fe66cd87549f    nginx     "nginx -g 'daemon of…"   3 hours ago    Up 3 hours    0.0.0.0:80->80/tcp     rp
3daa11c28579    nginx     "nginx -g 'daemon of…"   4 hours ago    Up 4 hours    0.0.0.0:8083->80/tcp   nginx3
0cc187ff28b4    nginx     "nginx -g 'daemon of…"   4 hours ago    Up 4 hours    0.0.0.0:8082->80/tcp   nginx2
9239a53b4480    nginx     "nginx -g 'daemon of…"   4 hours ago    Up 4 hours    0.0.0.0:8081->80/tcp   nginx1

Maintenant, en se rendant à l’URL http://127.0.0.1, on peut observer qu’à chaque actualisation, on tombe sur un autre serveur web.

Conclusion

La prochaine étape est de mettre en place un monitoring de ces conteneurs. On génèrera du trafic vers le répartiteur de charge afin de vérifier que celui-ci répartit bien le trafic de manière équitable entre les serveurs (ou d’une autre manière, en fonction de la configuration).

Sources

Laisser un commentaire