Autheurs: Alexandra Cerottini & Miguel Do Vale Lopes
Date: 27.05.2021
Cette étape est visible via cette branche.
Le but de cette étape est d'implémenter un serveur HTTP statique à l'aide de Docker et Apache httpd. Nous avons premièrement créé les dossiers docker-images/apache-php-image
et implémenté notre configuration Docker dans le dossier apache-php-image
.
Nous avons choisi l'image Docker qui nous permet d'utiliser un serveur apache httpd. Il s'agit de l'image php et plus exactement php:7.2-apache
.
Un Dockerfile a ensuite été créé avec cette image.
FROM php:7.2-apache
COPY src/ /var/www/html/
La commande FROM permet de récupérer l'image php en précisant la version. La commande COPY permet de copier le contenu du dossier src dans le dossier /var/www/html
à l'intérieur du container. Le dossier src contient un template bootstrap utilisé comme site web statique. Le fichier index.html
de ce dossier a été adapté selon nos envies.
Pour lancer ce container, il suffit de build l'image depuis l'emplacement du Dockerfile avec la commande: docker build -t res/apache_php .
puis de le run avec docker run -p 9090:80 res/apache_php
. Nous pouvons maintenant voir le résultat en ouvrant une page web et en allant sur localhost:9090
.
Les fichiers de configuration d'apache dans le container se trouvent dans le dossier /etc/apache2/
.
Cette étape est visible via cette branche.
Le but de cette étape est d'implémenter un serveur HTTP dynamique à l'aide de node.js et express.js. Nous avons premièrement créé le dossier express-image
dans le dossier docker-images
.
Nous avons choisi l'image Docker qui nous permet d'utiliser node.js
pour notre application web dynamique. Il s'agit de l'image node et plus exactement: node:14.17
.
Un Dockerfile a ensuite été créé avec cette image.
FROM node:14.17
COPY src/ /opt/app
CMD ["node","/opt/app/index.js"]
La commande CMD
permet d'exécuter notre script lors du lancement du container.
Le dossier src
est également copié et a été créé dans le dossier express-image
. Il contient un fichier index.js
. Ce fichier permet de générer une liste d'animaux avec leur race, nom, genre et date de naissance. Pour générer du contenu random, le module chance a été utilisé. Il a fallu l'ajouter à l'aide de la commande npm install --save chance
. Les requêtes sont faites à l'aide du module express qu'il a aussi fallu ajouter. La commande npm init
a permis la création d'un package.json
.
Pour lancer ce container, il suffit de build l'image depuis l'emplacement du Dockerfile avec la commande: docker build -t res/express_animals .
puis de le run avec docker run -p 3000:3000 res/express_animals
. Nous pouvons maintenant voir le résultat en ouvrant une page web et en allant sur localhost:3030
.
Cette étape est visible via cette branche.
Le but de cette étape est d'implémenter un reverse proxy statique avec Apache. Nous avons premièrement créé le dossier apache-reverse-proxy
dans le dossier docker-images
.
Nous avons choisi l'image Docker qui nous permet d'utiliser un serveur apache httpd. Il s'agit de l'image php et plus exactement php:7.2-apache
(nous avions premièrement utilisé l'image php:7.2-apache
mais elle a dû être changée lors de la step 5).
Un Dockerfile a ensuite été créé avec cette image.
FROM php:7.2-apache
COPY conf/ /etc/apache2
RUN a2enmod proxy proxy_http
RUN a2ensite 000-* 001-*
La commande RUN
permet de lancer les scripts a2enmod
(enable un module) et a2ensite
(activer des sites).
Le dossier conf
est également copié. Celui-ci a été créé dans le dossier apache-reverse-proxy
et contient la configuration du reverse proxy.
Pour tester cette configuration, il faut tout d'abord modifier le fichier etc/hosts
et y ajouter la ligne 127.0.0.1 demo.res.ch
(sur Linux).
Ensuite, il faut exécuter ces diverses commandes qui permettront de lancer les containers:
# Dans le dossier docker-images/apache-php-image:
docker build -t res/apache_php .
# Dans le dossier docker-images/express-image:
docker build -t res/express_animals .
# Dans le dossier docker-images/apache-reverse-proxy:
docker build -t res/apache_rp .
# Pour lancer les containers:
docker run -d --name apache_static res/apache_php
docker run -d --name express_dynamic res/express_animals
docker run --name apache_rp -p 8080:80 res/apache_rp
Nous pouvons maintenant voir le résultat du site statique en ouvrant une page web et en allant sur demo.res.ch:8080
. Pour voir le résultat du serveur HTTP dynamique, il faut aller sur demo.res.ch:8080/api/animals/
.
Les serveurs statique et dynamique peuvent être atteint directement dans notre implémentation car nous nous trouvons sur Linux. En effet, Docker est installé directement sur notre machine. Les réseaux Docker nous sont donc directement accessibles. Nous pouvons accéder au serveur statique en tapant http://172.17.0.2
et au serveur dynamique en tapant http://172.17.0.3:3000
sur un navigateur web.
Le problème dans cette configuration est que nous devons regarder les adresses IP attribuées aux containers statique et dynamique (avec la commande docker inspect <nom_container> | grep -i ipaddr
). Ils doivent ensuite être ajoutés dans le fichier 001-reverse-proxy.conf
comme ceci :
<VirtualHost *:80>
ServerName demo.res.ch
#ErrorLog ${APACHE_LOG_DIR}/error.log
#CustomLog ${APACHE_LOG_DIR}/access.log combined
ProxyPass "/api/students/" "http://172.17.0.3:3000/"
ProxyPassReverse "/api/students/" "http://172.17.0.3:3000/"
ProxyPass "/" "http://172.17.0.2:80/"
ProxyPassReverse "/" "http://172.17.0.2:80"
</VirtualHost>
Cette étape est visible via cette branche.
Le but de cette étape est d'implémenter des requêtes AJAX depuis le serveur statique vers le serveur dynamique. Les trois Dockerfile ont été modifié pour installer nano qui nous permettra d'éditer des fichiers directement dans le container. Cette commande a donc été ajoutée: RUN apt-get update && apt install nano
.
Dans cette étape, un script animals.js
a été ajouté dans le dossier docker-images/apache-php-image/src/js
. Ce script nous permet périodiquement de faire une requête HTTP en arrière plan sans recharger toute la page. Pour ce faire, nous avons utiliser jQuery. Nous avons également modifié le fichier index.html
du dossier docker-images/apache-php-image/src/
pour qu'il appelle notre script animals.js
.
$(function() {
console.log("Loading animals");
function loadAnimals() {
$.getJSON( "/api/animals/", function(animals) {
console.log(animals);
$(".spawn-animal").text(animals[0].name + " the " + animals[0].animal);
});
};
loadAnimals();
setInterval(loadAnimals, 2000);
});
Pour tester cette configuration, il faut rebuild les trois images que nous avions créée précédemment et relancer les containers en veillant bien à ce qu'ils aient la même adresse IP qu'auparavant.
Lorsque nous sommes sur le site demo.res.ch:8080
, nous pouvons voir les requêtes Ajax en ouvrant les webTools et en regardant le trafic via le browser.
Tout ceci ne fonctionnerait pas sans un reverse proxy car un mécanisme de sécurité se prénommant "Same-origin policy" a été spécifié pour prévenir certaines attaques. Cette politique nous dit qu'un script qui est exécuté et qui vient d'un certain nom de domaine, ne peut faire des requêtes que vers le même nom de domaine. Si on travaillait directement avec les adresses IP, on ne pourrait pas envoyer une requête AJAX sur les deux containers car ils n'ont pas la même adresse. Pour éviter ce problème, on met en place un reverse proxy qui agit comme un point d'entrée unique avec un nom DNS (demo.res.ch).
Cette étape est visible via cette branche.
Dans cette étape, nous avons remplacé la configuration statique par une configuration dynamique en définissant des variables d'environnement au lancement du container. Nous avons dû ajouter dans le dossier apache-reverse-proxy
un fichier apache2-foreground
que nous avons récupéré sur le git de php puis nous y avons ajouté notre setup:
# Add setup for RES lab
echo "Setup for the RES lab..."
echo "Static app URL: $STATIC_APP"
echo "Dynamic app URL: $DYNAMIC_APP"
php /var/apache2/templates/config-template.php > /etc/apache2/sites-available/001-reverse-proxy.conf
La version 7.2 d'Apache n'étant plus disponible sur le site, nous avons modifié notre Dockerfile pour utiliser la version 7.4.
On a aussi créé un dossier conf
contenant le fichier config-template.php qui a remplacé la configuration statique du proxy. Un fichier config est ainsi généré au lancement du container en remplaçant dynamiquement les adresses IP par les variables d'envrionnement.
<?php
$dynamic_app = getenv('DYNAMIC_APP');
$static_app = getenv('STATIC_APP');
?>
<VirtualHost *:80>
ServerName demo.res.ch
ProxyPass '/api/animals/' 'http://<?php print "$dynamic_app"?>/'
ProxyPassReverse '/api/animals/' 'http://<?php print "$dynamic_app"?>/'
ProxyPass '/' 'http://<?php print "$static_app"?>/'
ProxyPassReverse '/' 'http://<?php print "$static_app"?>/'
</VirtualHost>
Pour ce faire, nous avons ajouté cette commande dans le Dockerfile: COPY apache2-foreground /usr/local/bin/
et COPY template/ /var/apache2/templates
.
Pour démarrer le container, il faut rebuild l'image et le lancer avec la commande docker run -e STATIC_APP <adresse_ip1> -e DYNAMIC_APP <adresse_ip2> res/apache_rp
.
Le fichier 001-reverse-proxy.conf
a été vidé car il ne nous est plus vraiment utile. Par contre, nous l'avons gardé pour le bon fonctionnement de la commande RUN a2ensite 001-*
du Dockerfile.
Cette étape et la suivante sont visibles via cette branche.
Le but de cette étape est d'implémenter un load balancing. Nous avons trouvé de la documentation sur un module mod_proxy_balancer sur le site d'Apache et nous l'avons implémenté.
Pour ce faire, nous avons modifié le fichier config-template.php
qui se trouve dans le dossier docker_images/apache-reverse-proxy/
pour permettre l'ajout de deux autres variables d'envrionnements et pour implémenter le proxy balancer:
<?php
$dynamic_app_1 = getenv('DYNAMIC_APP_1');
$dynamic_app_2 = getenv('DYNAMIC_APP_2');
$static_app_1 = getenv('STATIC_APP_1');
$static_app_2 = getenv('STATIC_APP_2');
?>
<VirtualHost *:80>
ServerName demo.res.ch
<Location /balancer-manager>
SetHandler balancer-manager
</Location>
ProxyPass /balancer-manager !
<Proxy "balancer://dynamic">
BalancerMember "http://<?php print "$dynamic_app_1"?>"
BalancerMember "http://<?php print "$dynamic_app_2"?>"
</Proxy>
<Proxy "balancer://static">
BalancerMember "http://<?php print "$static_app_1"?>"
BalancerMember "http://<?php print "$static_app_2"?>"
</Proxy>
ProxyPass "/api/animals/" "balancer://dynamic/"
ProxyPassReverse "/api/animals/" 'balancer://dynamic/"
ProxyPass "/" "balancer://static/"
ProxyPassReverse "/" "balancer://static/"
</VirtualHost>
Nous avons également modifié le Dockerfile en ajoutant à la commande RUN a2enmod
le mode proxy_balancer
et le mode lbmethod=byrequests
. En effet, pour utiliser le mode proxy_balancer, il faut que le mode proxy soit activé (déjà fait auparavant), le mode proxy_balancer et un module d'algorithme. Nous avons donc choisi le module lbmethod_byrequest
comme algorithme.
Pour valider cette procédure, nous avons au préalable démarré deux containers statiques et deux containers dynamiques. Nous avons ensuite dû rebuild l'image puis lancer le container à nouveau avec la commande: docker run -d -e STATIC_APP_1=172.17.0.2:80 -e STATIC_APP_2=172.17.0.3:80 -e DYNAMIC_APP_1=172.17.0.4:3000 -e DYNAMIC_APP_2=172.17.0.5:3000 --name apache_rp -p 8080:80 res/apache_rp
.
Nous avons ensuite ouvert le balance-manager que nous avons ajouté dans le config-template.php dans les dernières étapes. Pour l'ouvrir il suffit de taper demo.res.ch:8080/balance-manager
. Nous tuons ensuite un container statique et un container dynamique faisant passer leur status à "Init Err". On remarque ensuite que les deux autres serveurs reprennent la charge, en voyant leur nombre "Elected" augmenter.
Cette étape et la précédante sont visibles via cette branche.
Le but de cette étape est d'implémenter le round-robin ainsi que le sticky sessions. Nous avons trouvé de la documentation sur le round-robin sur le site d'Apache et nous l'avons implémenté sur les serveurs dynamqiues. Les sticky sessions sont décris dans la description du mod_proxy_balancer et ont été implémentés sur les serveurs statiques.
Pour cette étape, nous avons modifié le fichier config-template.php
qui se trouve dans le dossier docker_images/apache-reverse-proxy/
pour implémenter le round-robin et les sticky sessions:
<?php
$dynamic_app_1 = getenv('DYNAMIC_APP_1');
$dynamic_app_2 = getenv('DYNAMIC_APP_2');
$static_app_1 = getenv('STATIC_APP_1');
$static_app_2 = getenv('STATIC_APP_2');
?>
<VirtualHost *:80>
ServerName demo.res.ch
<Location /balancer-manager>
SetHandler balancer-manager
</Location>
ProxyPass /balancer-manager !
<Proxy "balancer://dynamic">
BalancerMember "http://<?php print "$dynamic_app_1"?>"
BalancerMember "http://<?php print "$dynamic_app_2"?>"
ProxySet lbmethod=byrequests
</Proxy>
Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED
<Proxy "balancer://static">
BalancerMember "http://<?php print "$static_app_1"?>" route=1
BalancerMember "http://<?php print "$static_app_2"?>" route=2
ProxySet stickysession=ROUTEID
</Proxy>
ProxyPass "/api/animals/" "balancer://dynamic/"
ProxyPassReverse "/api/animals/" 'balancer://dynamic/"
ProxyPass "/" "balancer://static/"
ProxyPassReverse "/" "balancer://static/"
</VirtualHost>
Nous avons également modifié le Dockerfile pour ajouter l'option headers
à la commande RUN a2enmod...
.
Pour valider cette procédure, nous avons au préalable démarré deux containers statiques et deux containers dynamiques. Nous avons ensuite dû rebuild l'image puis lancer le container à nouveau avec la commande: docker run -d -e STATIC_APP_1=172.17.0.2:80 -e STATIC_APP_2=172.17.0.3:80 -e DYNAMIC_APP_1=172.17.0.4:3000 -e DYNAMIC_APP_2=172.17.0.5:3000 --name apache_rp -p 8080:80 res/apache_rp
.
Pour vérifier le round-robin, nous allons sur notre balance-manager (demo.res.ch:8080/balance-manager
sur un navigateur) et nous regardons le "LoadBalancer Status for balancer://dynamic ..." et nous cherchons la case "Elected". Nous pouvons voir que le compteur augmente de manière alternée entre les deux serveurs lorsque l'on rafraichit la page du load balancer régulièrement. Si nous tuons un serveur dynamique, nous pouvons voir que seulement le compteur du serveur dynamique restant augmentera (cf. Step 6).
Pour vérifier le sticky session, nous allons sur notre balance-manager (demo.res.ch:8080/balance-manager
sur un navigateur) et nous regardons le "LoadBalancer Status for balancer://static ..." et nous cherchons la case "StickySession". Nous voyons que ROUTEID y est écrit alors qu'auparavant la case comportait la mention (None). Nous constatons que chaque serveur statique possède un numéro de route (1 et 2).
Le but de cette étape est de contrôler l'envrionnement Docker depuis le web. En cherchant des UI manager avec Docker sur internet, nous sommes tombés sur ce site. En le parcourant, nous avons décidé d'utiliser Portainer sur Docker. Pour ce faire, si l'utilisateur se trouve sur Linux, il lui suffit d'exécuter les commandes suivantes:
docker volume create portainer_data
docker run -d -p 8000:8000 -p 9000:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce
Il faut ensuite aller sur localhost:9000
pour manager ses containers. Lors de la première connexion, il est demandé de choisir un mot de passe pour le compte admin. Il faut ensuite cliquer sur "Gérer l'environnement docker local" pour accéder à notre infrastructure.
Pour valider cette procédure, nous avons éteint puis rallumé un container Docker depuis l'interface tout en vérifiant entre deux sur un terminal en faisant un docker ps
que le container n'apparaissait plus puis qu'il réapparaissait par la suite.