URL: https://linuxfr.org/users/trim/journaux/utiliser-podman-en-mode-rootless-pour-executer-en-service-des-containers-rootless Title: Utiliser Podman en mode rootless pour exécuter en service des containers rootless Authors: Adrien Dorsaz Date: 2022年04月29日T11:35:24+02:00 License: CC By-SA Tags: docker, podman, systemd, service, grafana, debian et firefox Score: 40 Hello, J'ai eu l'occasion de remonter mon serveur et tous ses services suite à un bug sur le système de fichier. Je pouvais juste remonter les sauvegardes de ma Debian 11 Bullseye, mais j'avais prévu une nouvelle machine et je voulais en profiter pour refaire à la main les installations des services. J'emploie Debian et j'utilise donc d'habitude les paquets Debian. Mais, bien sûr, j'ai certains services, comme Firefox Sync et Grafana, qui ne sont pas disponible dans les répertoires Debian. Cette fois, je voulais profiter d'avoir un peu plus d'expérience avec Docker pour installer ces services sous formes de container au lieu d'ajouter leur répertoire `apt` dans Debian (et donc leur donner les droits d'administration sur ma machine lors de l'installation et mise à jour). Pour être un peu plus serein, je ne voulais pas utiliser Docker en mode "service avec les droits root" pour éviter de donner trop de privilèges aux containers. J'ai donc voulu essayer d'utiliser podman parce que j'en avais pas mal entendu parler: podman est un gestionnaire de container qui est prévu pour pouvoir être employé par un utilisateur standard, c'est à dire sans droits d'administrations (autrement dit en mode _rootless_). Pour info, Docker sait aussi s'exécuter en mode _rootless_, c'est juste un peu moins clé en main dans Debian. J'ai un peu galéré pour la gestion des volumes et du réseau, alors je me suis dit que c'était une bonne occasion de partager cette expérience et de montrer comment j'ai pu monter un service sur mon serveur qui exécute un container en mode _rootless_. Pour l'exemple, je vais prendre un service [Grafana](https://grafana.com/) qui permet de visualiser l'état de mon serveur. J'ai volontairement pris en exemple Grafana, parce qu'il soulève le problème des droits sur les volumes et parce qu'il a besoin de communiquer avec l'hôte dans ma configuration (pour accéder à Prometheus et à Postgresql installés sur l'hôte). Le problème de droits sur les volumes est dû au fait que l'image de Grafana suit la bonne pratique d'utiliser, à l'intérieur du container, un utilisateur standard pour exécuter le processus Grafana. Le mode _rootless_ sera donc appliqué au gestionnaire de container de l'hôte (podman) et à l'intérieur du container lui-même (Grafana). # Préparation du système hôte Au début de mes recherches, je suis tombé sur le site https://rootlesscontaine.rs/ qui explique bien comment débuter avec podman (Docker et d'autre gestionnaires) en mode rootless. J'installe quelques outils, en suivant leurs conseils: ```sh sudo apt install podman slirp4netns uidmap dbus-user-session fuse-overlayfs systemd-container ``` * `podman`: le gestionnaire de container * `slirp4netns`: outil qui permet à l'utilisateur de gérer un namespace réseau sans privilèges d'administration * `uidmap`: utilitaires pour gérer les namespaces d'identifiants utilisateurs (les UID et GID) sans privilèges d'administration * `dbus-user-session`: les sessions dbus utilisateurs [sont requis](https://rootlesscontaine.rs/getting-started/common/login/#optional-enable-dbus-user-session) pour utiliser systemd avec les cgroup v2 * `fuse-overlayfs`: [pour les kernels < 5.11](https://rootlesscontaine.rs/how-it-works/overlayfs/), il vaut mieux utiliser FUSE pour la gestion du système de fichier par utilisateur * `systemd-container`: permettra d'utiliser `machinectl` [pour se connecter avec l'utilisateur](https://rootlesscontaine.rs/getting-started/common/login/) et ainsi avoir la variable `XDG_RUNTIME_DIR` configurée # Configuration de l'utilisateur pour exécuter le service Ensuite, je crée un user dédié au service: ```sh sudo adduser --system --disabled-password grafana ``` Comme l'utilisateur devra toujours faire tourner ce service, il faut dire à systemd que cet utilisateur doit toujours avoir une session ouverte: ```sh sudo loginctl enable-linger grafana ``` Comme indiqué sur rootlesscontaine.rs, je donne des plages d'UID et de GID à l'utilisateur pour qu'il puisse les utiliser pour exécuter des containers rootless. Je modifie donc les fichiers `/etc/subuid` et `/etc/subgid` pour leur ajouter une ligne comme: ``` grafana:100000:65536 ``` Ça veut dire que le système dédie une plage de 65'536 identifiants à l'utilisateur grafana (il peut donc utiliser les identifants de 100'000 à 165'535). [Une information très importante](https://github.com/containers/podman/issues/12715#issuecomment-1002915917): si vous avez essayé d'exécuter une commande podman en tant qu'utilisateur standard __avant__ d'avoir modifié ces deux fichiers, il faut dire à podman de "migrer" avec la commande (à exécuter en tant qu'utilisateur): ```sh podman system migrate ``` J'ai galéré un peu à comprendre pourquoi je continuais d'avoir des erreurs qui me disaient _potentially insufficient UIDs or GIDs available in user namespace_ alors que je venais de corriger le fichier /etc/subgid. # Préparer et démarrer le service Pour se connecter avec l'utilisateur sur mon serveur, [je dois utiliser machinectl](https://rootlesscontaine.rs/getting-started/common/login/): ```sh sudo machinectl shell grafana@ ``` Comme j'ai créé un utilisateur avec l'option `--system`, Debian n'a pas copié les fichiers par défaut. Si vous avez besoin de certains fichiers, pensez à les copier: ```sh cp -a /etc/skel/.config/ ~ ``` Pour stocker la configuration du container, je créé un fichier `.env` dans le dossier utilisateur. Ce fichier permettra de changer la configuration du container sans avoir besoin de modifier le fichier `.service` de systemd. ```sh # Ajuster le masque utilisateur pour refuser la lecteur par les autres umask 077 editor grafana.env ``` Pour Grafana, il faut lire la [documentation](https://grafana.com/docs/grafana/latest/administration/configure-docker/) et j'y ai mis: ``` # Nous allons monter un volume dans le dossier /grafana GF_PATHS_CONFIG=/grafana/grafana.ini # Pour remonter les logs à Podman, il faut mettre les logs dans stdout et stderr GF_LOG_MODE=console ``` Ensuite, je crée un volume avec la configuration de Grafana. ```sh # Ajuster le masque utilisateur pour refuser la lecteur par les autres umask 077 mkdir grafana editor grafana/grafana.ini ``` J'avais déjà un fichier `grafana.ini` de mon ancien serveur, je l'ai copié et j'ai fait quelques ajustements: En mode _rootless_, podman utilise le service `slirp4netns` et le _gateway_ réseau vu par le container a toujours l'adresse IP `10.0.2.2`. Mon fichier `grafana.ini` comptait sur le service Postgresql du serveur local, j'ai donc dû remplacer `localhost` par `10.0.2.2` comme serveur Postgresql. L'image Docker de Grafana suit la bonne pratique de modifier l'UID de l'utilisateur qui exécute le binaire dans le container. L'utilisateur de Grafana utiliser l'UID `472`, mais celui-ci n'existe pas vraiment sur le système hôte, on ne peut donc pas faire un simple `chown 472:nogroup -R grafana`. Pour pouvoir partager ce dossier via un volume, il faut demander à podman d'ajuster les droits au dossier: ```sh podman unshare chown 472:0 -R grafana ``` Pour plus d'explications sur cette partie de la configuration des droits du volume, vous pouvez suivre [cet article](https://www.redhat.com/sysadmin/rootless-podman-makes-sense) de Dan Walsh. Enfin, on peut exécuter le container Grafana: ```sh podman run --name=grafana -p 3000:3000 --env-file ~/grafana.env --volume /home/grafana/grafana:/grafana --net slirp4netns:allow_host_loopback=true docker.io/grafana/grafana-oss ``` C'est une commande podman (ou Docker assez classique), à l'exception de l'option `--net slirp4netns:allow_host_loopback=true` qui demande à `slirp4netns` d'autoriser la communication depuis le container vers l'hôte. J'ai besoin de cette communication pour permettre à Grafana de joindre Postgresql et Prometheus (j'ai dû aussi mettre à jour le DataSource Prometheus pour utiliser l'adresse IP `10.0.2.2`). # Créer un service systemd et le démarrer Enfin, on est prêt à configurer systemd pour démarrer ce container automatiquement. Pour ça, j'ai suivi [cet article](https://www.redhat.com/sysadmin/podman-run-pods-systemd-services) et j'y ai entre autre appris que podman est un gestionnaire de `pod`, une notion que j'utilise régulièrement avec _OpenShift_ (et donc _Kubernetes_). Un `pod` peut contenir un ensemble de containers et leur permet de communiquer ensemble avec le hostname `localhost`. Comme vous pouvez le voir dans l'article, podman propose une commande qui génère les fichiers services systemd à installer dans le bon répertoire (dans notre cas 1 seul fichier, parce qu'on a crée un container sans pod): ```sh mkdir -p ~/.config/systemd/user cd ~/.config/systemd/user podman generate systemd --name --new --restart-policy=on-failure -f grafana ``` Enfin, il faut avertir systemd de démarrer au boot ce service et de l'exécuter maintenant: ```sh systemctl --user daemon-reload systemctl --user enable --now container-grafana.service ``` # Conclusion Je suis assez content d'avoir pu installer des services qui n'existent pas dans les paquets Debian sans avoir eu besoin de leur donner un accès `root` (ce qui se passe quand on utilise `apt` pour l'installation et les mises à jour). C'était plus long et compliqué que prévu, mais au final ça tourne. Peut être que l'installation d'une version minimale de Kubernetes ou d'OpenShift (enfin, [OKD](https://www.okd.io/)) aurait été plus rapide, je ne sais pas et je ne sais pas non plus quelles sont les prérequis réseaux et matériels pour ces outils. Pour l'instant, j'ai vu ces inconvénients: * Je n'ai plus la vérification GPG faite par `apt`, je fais directement confiance à la gestion du service publique _Docker Hub_. * Les services systèmes de systemd ne sont pas accessibles depuis l'utilisateur. J'ai dû donc pour chaque utilisateur copier un service `notify-admin@.service` pour pouvoir ajouter l'option `OnFailure` qui va bien. * Les logs des containers ne sont accessibles uniquement avec `podman logs grafana`. J'espérais les voir dans les logs de l'utilisateur avec `journalctl --user`, mais je n'ai rien du tout. Je dois manquer d'indices pour configurer `systemd-journald` et podman. Le top aurait était que l'utilisateur `root` de l'hôte puisse voir tous les logs de tous les services avec `journalctl` pour me simplifier la gestion de mon serveur. Pour aller encore un peu plus loin, il faudrait encore sécuriser ces services avec la configuration AppArmor ou SELinux qui va bien (Debian installe par défaut AppArmor et RedHat SELinux).

AltStyle によって変換されたページ (->オリジナル) /