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 serveur

  • back.<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 frontend

  • back.<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.net vers http://front:80

  • back.<id-personnel>.enseirb.conf \(\Rightarrow\) Redirige les requêtes de back.<id-personnel>.enseirb.net vers http://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…#

  1. Que pourrait-on modifier pour améliorer la sécurité de ce déploiement ?

  2. Implémenter ces modifications

  3. 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 domaine gitlab.sakiut.fr serait enregistrée dans un fichier gitlab.sakiut.conf.