TP 7 : Montage de l’infrastructure groupomania sur serveur ubuntu#
À partir d’ici, le terme « identifiant personnel » désignera un identifiant composé de la première lettre de votre prénom et des quatre premières lettres de votre nom de famille. Il sera régulièrement utilisé pour vous identifier.
Exemple : Paul MARTIN \(\Rightarrow\) pmart
1. Images de base#
Pour le backend, nous nous baserons désormais sur l’image sakiut/groupomania-expressts:1.0.0-alpine du Docker Hub.
Pour le frontend en revanche, qui contient des variables d’environnement qu’il faut définir au moment de la construction de l’image, il faudra continuer de construire l’image localement.
Cela pose une question : Comment partager cette image entre le poste de travail et le serveur ?
Pour y répondre, nous pourrions choisir d’utiliser directement le Docker Hub, d’y stocker toutes les versions de nos images,
pour finalement les récupérer sur le serveur. Nous avons ici choisi une autre approche : utiliser un registre privé.
Ce registre sera le suivant : registry.enseirb.net. Il est protégé par un identifiant et un mot de passe, qui vous seront
fournis en séance pour des raisons évidentes de sécurité.
Afin de vous y connecter, commencez par exécuter la commande de connexion sur votre poste de travail et sur le serveur :
docker login registry.enseirb.net
Par défaut, Docker stocke vos identifiants localement et les réutilisera pour se reconnecter au registre. En production, il est donc impératif d’avoir des identifiants temporaires qui expirent rapidement pour garantir la sécurité de votre registre.
Avant de construire l’image frontend, modifiez la variable d’environnement contenu dans le Dockerfile :
ENV VITE_API_HOST="http://<ip-serveur>:3000"
Puis construisez-la via la commande :
docker build -t registry.enseirb.net/<id-personnel>/grp-front .
Puis téléversez-la sur le registre en exécutant :
docker push registry.enseirb.net/<id-personnel>/grp-front
2. Déploiement de l’infrastructure#
Commencez par créer un dossier de travail dans votre répertoire home nommé grp :
mkdir grp
cd grp
On déploiera l’infrastructure via le fichier de configuration docker-compose.yml suivant, en prenant garde de remplacer
l’image du frontend par celle que vous avez construite et poussée précédemment sur le registre :
version: "3"
networks:
net:
volumes:
db-data:
services:
db:
image: postgres:14-alpine
networks:
- net
volumes:
- db-data:/var/lib/postgresql/data
environment:
POSTGRES_USER: "admin"
POSTGRES_PASSWORD: "password"
POSTGRES_DB: "grp"
api:
image: sakiut/groupomania-expressts:1.0.0-alpine
environment:
NODE_ENV: development
DATABASE_URL: "postgresql://admin:password@db:5432/grp?schema=public"
SECRET_KEY: secret
networks:
- net
ports:
- "3000:3000"
front:
image: "registry.enseirb.net/id-personnel/grp-front"
networks:
- net
ports:
- "3001:80"
Il nous faudra ouvrir les ports nécessaires au fonctionnement de l’application dans le firewall pour l’instant :
sudo ufw allow 3000
sudo ufw allow 3001
Puis, pour déployer la configuration, exécuter la commande :
docker compose up -d
Une fois la configuration en place, vous pouvez valider son bon fonctionnement en accédant à la page http://<ip-serveur>:3001.
3. Déploiement d’un serveur#
3.1. Objectifs#
L’objectif de la dernière partie de ce TP est de mettre en application le contenu du TP 5 dans un contexte serveur. Pour cela, deux noms de domaines vous ont été attribués :
<id-personnel>.enseirb.net\(\Rightarrow\) Pointe vers l’adresse IP de votre serveurback.<id-personnel>.enseirb.net\(\Rightarrow\) Pointe vers le premier domaine
Cette architecture a un avantage : si l’adresse IP vient à changer, il n’y a qu’un enregistrement DNS à changer. Ce TP ne traitera pas de la gestion d’un domaine et des enregistrements DNS.
L’objectif dans un premier temps est de créer deux redirections, comme suit :
<id-personnel>.enseirb.net\(\Rightarrow\) Affiche le frontendback.<id-personnel>.enseirb.net\(\Rightarrow\) Redirige les requêtes sur le backend
3.2. Préparation#
Modifiez le fichier Dockerfile du frontend, construisez l’image et poussez-la sur le registre.
ENV VITE_API_HOST="http://back.<id-personnel>.enseirb.net"
docker build -t registry.enseirb.net/<id-personnel>/grp-front .
docker push registry.enseirb.net/<id-personnel>/grp-front
Également, à l’aide des commandes suivantes, retirez les quatre règles créées précédemment du firewall :
sudo ufw status numbered
sudo ufw delete <num-regle>
3.3. Écriture des configurations nginx#
3.3.1. Rappel sur nginx (TP5 section 1.3)#
Nginx est un puissant serveur web, mais c’est également un excellent reverse-proxy.
Indication
Un proxy inverse (reverse proxy) ou serveur mandataire inverse est un type de serveur, habituellement placé en [amont] de serveurs web. Contrairement au serveur proxy qui permet à un utilisateur d’accéder au réseau Internet, le proxy inverse permet à un utilisateur d’Internet d’accéder à des serveurs internes. Une des applications courantes du proxy inverse est la répartition de charge (load-balancing).
D’après Wikipédia
Nous allons ici chercher à l’exploiter de manière à aiguiller les requêtes arrivant dans notre réseau.
Le répertoire de fonctionnement de nginx est /etc/nginx.
Un fichier de configuration nginx a cette forme :
server {
listen 80; # Port d'écoute IPv4
listen [::]:80; # Port d'écoute IPv6
server_name example.com; # Domaine concerné par la règle
# On renvoie tout le traffic en example.com/* sur 192.168.0.1, port 8080
location / {
proxy_pass http://192.168.0.1:8080;
}
# On renvoie seulement le traffic en example.com/media/* sur 192.168.0.2, port 8978
location /media/ {
proxy_pass http://192.168.0.2:8978;
}
}
On enregistre cette configuration dans un fichier example.conf1, que l’on place ensuite
dans le répertoire /etc/nginx/conf.d. Nginx le charge alors automatiquement, et s’occupera
de rediriger les paquets conformément à la configuration[^2].
Astuce
En pratique, on ajoute quelques headers au moment de faire une redirection, pour la stabiliser et la documenter. Par exemple, l’exemple ici concerné deviendrait :
location / {
proxy_pass http://192.168.0.1:8080;
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-NginX-Proxy true;
}
3.3.2. Mise en œuvre#
Écrire deux configurations nginx, telles que :
<id-personnel>.enseirb.conf\(\Rightarrow\) Redirige les requêtes de<id-personnel>.enseirb.netvershttp://front:80back.<id-personnel>.enseirb.conf\(\Rightarrow\) Redirige les requêtes deback.<id-personnel>.enseirb.netvershttp://api:3000
Stocker ensuite ces deux fichiers sous ~/grp/nginx/.
3.4. Configuration de l’infrastructure Docker#
Nous reprenons la configuration établie précédemment, et la mettons à jour de manière à y intégrer nginx, conteneurisé.
Indication
Si vous vous sentez à l’aise avec nginx et docker-compose, vous pouvez tenter d’établir par vous-même cette configuration.
Nginx va écouter directement sur le port 80 pour recevoir les paquets HTTP (on ne se préoccupe pas de HTTPS et du port 443 pour l’instant). À l’inverse, les autres conteneurs du réseau ne doivent plus faire l’objet d’une redirection de port, puisqu’ils communiqueront désormais à travers le reverse-proxy.
Tout ceci donne la configuration suivante :
version: "3"
networks:
net:
volumes:
db-data:
services:
db:
image: postgres:14-alpine
networks:
- net
volumes:
- db-data:/var/lib/postgresql/data
environment:
POSTGRES_USER: "admin"
POSTGRES_PASSWORD: "password"
POSTGRES_DB: "grp"
api:
image: sakiut/groupomania-expressts:1.0.0-alpine
networks:
- net
environment:
NODE_ENV: development
DATABASE_URL: "postgresql://admin:password@db:5432/grp?schema=public"
SECRET_KEY: secret
front:
image: "registry.enseirb.net/id-personnel/grp-front"
networks:
- net
nginx:
image: nginx:stable-alpine
networks:
- net
volumes:
- ./nginx/:/etc/nginx/conf.d/
ports:
- "80:80"
Que vous pourrez monter via la commande :
docker compose up -d
Vous devriez normalement pleinement accéder à l’application via l’URL http://<id-personnel>.enseirb.net.
4. Pour aller plus loin…#
Que pourrait-on modifier pour améliorer la sécurité de ce déploiement ?
Implémenter ces modifications
On pourrait envisager ici de supprimer un conteneur afin de simplifier l’infrastructure. Lequel ? Comment ? Est-ce souhaitable ?
- 1
Par convention, on nomme les fichiers de configuration nginx en fonction du domaine qu’ils concernent, en remplaçant le domaine de premier niveau par l’extension du fichier,
.conf. Ainsi, une règle concernant le domainegitlab.sakiut.frserait enregistrée dans un fichiergitlab.sakiut.conf.