Je vais essayer de rapprocher mon exemple d'un cas d'utilisation Production Ready afin que cet exemple soit le plus concret possible...(enfin je vais essayer 😜)
Le but va être de publier une application web (Ghost) et sa base de données (Mariadb) derrière un reverse proxy (Nginx) avec du HTTPS.
Podman v2
Tout d'abord je vais devoir installer Podman sur ma machine. J'ai réalisé ce tutoriel sur Fedora 32 et avec Podman 2.0.1.
Je n'ai pas l'habitude d'utiliser Fedora, ce changement n'est dû qu'à un souhait : Essayer Podman sur cette distribution avec le support du cgroupv2. Cela n'a aucun impact sur le reste de ce tutoriel.
Pour installer cette version sur Fedora, rien de plus simple :
sudo dnf -y install --enablerepo updates-testing podman
Si vous souhaitez utiliser Ubuntu/Debian ou tout autres systèmes, vous pouvez suivre les directives d'installation de Podman présentes ici :
Ou compiler votre propre version :
Container Rootless & Pod
L'intégralité des lignes qui vont suivre sont donc exécutées avec l'utilisateur fedora
qui est présent sur ma machine ( VPS ) :
[[email protected] ~]$ id
uid=1000(fedora) gid=1000(fedora) groups=1000(fedora),4(adm),10(wheel),190(systemd-journal)
Si je dois effectuer certaines commandes en root alors je préciserai l'utilisation de la commande sudo
.
Commençons immédiatement avec la création de notre Pod
.
Pour rappel, un pod est un ensemble de container qui vont partager certaines ressources dont le réseau :
Mon pod, que je vais nommer ici myblog :
podman pod create --name myblog -p 80:80,443:443
Mon application web va donc être disponible sur le port 80 et 443.
Je vais ensuite créer ma base de données avec la ligne suivante :
podman run -dt --name db \
--pod myblog \
--restart on-failure \
--env-file=$HOME/myblog/.mariadb.env \
-v mariadb-data:/var/lib/mysql \
docker.io/mariadb:10
Voici le contenu de mon fichier de variables d'environnements .mariadb.env
que je stocke dans un dossier myblog
dans mon répertoire personnel :
MYSQL_RANDOM_ROOT_PASSWORD=yes
MYSQL_PASSWORD=MYPASSWORD
MYSQL_DATABASE=MYDATABASE
MYSQL_USER=MYUSER
Vous allez obtenir une erreur car le Pod
va démarrer avec votre base de données. Et celui-ci souhaite s'accaparer les ports 80 et 443, mais votre utilisateur courant ne possède pas ce droit ... ! On lance en root
!? Sûrement pas !
Nous allons autoriser notre utilisateur à bind les ports < 1024 ( qui sont considérés comme privilégiés ) :
sudo sysctl net.ipv4.ip_unprivileged_port_start=80
Vous pouvez l'ajouter dans le fichier /etc/sysctl.conf
afin d'être pris en compte au démarrage :
Vous pouvez supprimer le container db
et le créer de nouveau :
podman rm db
podman run -dt --name db \
--pod myblog \
--restart on-failure \
--env-file=$HOME/myblog/.mariadb.env \
-v mariadb-data:/var/lib/mysql \
docker.io/mariadb:10
Vérifiez son démarrage avec la commande logs
:
podman logs -f db
Il ne me reste plus qu'à lancer Ghost :
podman run -dt --name app \
--restart on-failure \
--pod myblog \
-e url=https://myblog.mydomain.com \
--env-file=$HOME/myblog/.ghost.env \
-v www-data:/var/lib/ghost/content \
docker.io/ghost:3
Et mon fichier .ghost.env
, qui est dans mon dossier myblog
:
database__client=mysql
database__connection__host=127.0.0.1
database__connection__user=MYUSER
database__connection__password=MYPASSWORD
database__connection__database=MYDATABASE
À la grande différence de Docker
, grâce à mon Pod je peux déclarer pour Ghost l'utilisation d'une base de données sur l'interface locale alors qu'il s'agit bien de deux containers différents.
Il ne reste qu'à mettre en place Nginx comme reverse-proxy pour notre application avec un certificat SSL. Je vais utiliser certbot pour générer des certificats let's encrypt.
Nginx et HTTPS
Il va d'abord être nécessaire d'installer certbot
:
sudo dnf -y install certbot
Ensuite je vais exécuter celui-ci avec mon compte fedora
:
certbot certonly --standalone --config-dir=$HOME/config/ --work-dir=$HOME/work/ --logs-dir=$HOME/logs/ -d myblog.mydomain.com
Si votre Pod
est en cours d'éxécution il va être nécessaire de le stopper pour générer le certificat :
podman pod stop myblog
Enfin je vais lancer Nginx :
podman run -dt --name nginx \
--pod myblog \
--restart on-failure \
-v $HOME/myblog/nginx.conf:/etc/nginx/nginx.conf:ro \
-v $HOME/config/live/myblog.dubarbu.fr/fullchain.pem:/etc/letsencrypt/live/myblog.dubarbu.fr/fullchain.pem:ro \
-v $HOME/config/live/myblog.dubarbu.fr/privkey.pem:/etc/letsencrypt/live/myblog.dubarbu.fr/privkey.pem:ro \
docker.io/nginx
Voici mon fichier de configuration nginx.conf :
La configuration est minimaliste mais elle fait le boulot. Le but de cet article n'étant pas de configurer Nginx, je ne vais pas m'y attarder !
🚩 Et là, le drame ... ! Pour le moment le container Nginx renvoie systématiquement une erreur de permission sur le fichier de configuration. Je n'ai pour le moment trouvé qu'une solution :
- Désactiver selinux ... :
sudo setenforce 0
Pour rendre la modification permanente, éditez le fichier /etc/selinux/config
et passez la variable SELINUX
à disabled
:
Oui, cette modification n'est pas très Production Ready ... 🚩
Supprimez le container nginx et relancez le. Vous ne devriez plus avoir d'erreur.
Il ne reste plus qu'à essayer la connexion vers votre blog : HTTPS://<YOUR_DOMAIN>
Ok mais si je redémarre mon serveur !?
Let's Go
Nous allons générer les fichiers nécessaires à systemd
pour lancer notre stack au démarrage de notre machine.
Dans un premier temps, créez le dossier suivant à la racine votre $HOME
:
mkdir -p $HOME/.config/systemd/user/
Enfin générons nos fichiers de service avec Podman :
cd $HOME/.config/systemd/user
podman generate systemd --files --name --new myblog
Enfin il faut les activer :
systemctl --user enable pod-myblog.service
systemctl --user enable container-db.service
systemctl --user enable container-app.service
systemctl --user enable container-nginx.service
Oui mais :
The systemd user instance is started after the first login of a user and killed after the last session of the user is closed.
Il va donc falloir modifier cela afin que vos services ne se coupent pas lors de votre déconnexion du serveur :
sudo loginctl enable-linger username
Un reboot
devrait vous permettre de valider tout ça !
Mise à jour :
Pour garder SELinux
actif avec Nginx, vous pouvez remplacer la commande de lancement du container avec la suivante :
podman run -dt --name nginx \
--pod myblog \
--restart on-failure \
-v $HOME/myblog/nginx.conf:/etc/nginx/nginx.conf:ro,Z \
-v $HOME/config:/etc/letsencrypt:ro,Z \
docker.io/nginx
SELinux
ne posera plus aucun souci de droit avec les volumes !
Merci à ruskofd_ pour son retour sur Twitter !
Nous avons pu voir au cours de cet article, comment mettre en place une stack web avec Podman en mode Rootless.
Il s'agit d'une première découverte et il reste énormément de chose à découvrir sur ce sujet. J'avais d'ailleurs initialement prévu un encart Feedback à cet article afin de vous donner mon ressenti sur cette première intégration et de discuter autour des bugs /soucis de configuration (PEBKAC) rencontrés lors de mes essais.
Mais l'article ayant déjà une taille conséquente - et mon encart Feedback également 😉 - je reviendrai un peu plus tard sur cette intégration !
En quelques mots , j'apprécie toujours autant avancer sur ce sujet : la sécurité de nos containers et le principe de moindre privilège !
Bien évidemment il est difficile de conseiller - pour l'instant - Podman en production ( hormis pour des projets très simples, comme l'exemple d'aujourd'hui ) mais la solution est déjà très fonctionnelle.
Le sujet amène aussi beaucoup de questions : Traefik comme reverse-proxy, c'est possible ? Comment avoir mon site en haute disponibilité avec Podman ? Et si j'héberge plusieurs services sur la même adresse IP ? Etc ... !
En tout cas n'hésitez pas à m'apporter des remarques ou des commentaires sur Twitter, ou ici 👇
Petite aparté : Sachez simplement que la rédaction de ces articles, demandent un temps conséquent et engage quelques dépenses ( location des serveurs notamment... ). Alors, si vous souhaitez soutenir le blog, alors n'hésitez plus!
buymeacoff.ee/lfache
J'en profite pour remercier - très chaleureusement - mon premier supporter sur la plateforme ! Merci à toi pour le geste !
Mais aussi tout ceux qui me suivent régulièrement, c'est grâce à vous que je garde la motivation pour continuer ce projet ! 😘
Vous êtes de plus en plus nombreux à venir sur le site et j'expliquerai dans un futur article ce que je souhaite construire avec vous autour des solutions de conteneurisation afin de faire découvrir tout ceci au plus grand nombre !