Nous suivons depuis longtemps le sujet de l'utilisation de systemd dans les conteneurs. En 2014, notre ingénieur en sécurité Daniel Walsh a écrit un article
Dans cet article, nous montrerons ce qui a changé au fil du temps et comment Podman peut nous aider dans ce domaine.
Il existe de nombreuses raisons d'exécuter systemd dans un conteneur, telles que :
- Conteneurs multiservices – de nombreuses personnes souhaitent extraire leurs applications multiservices de machines virtuelles et les exécuter dans des conteneurs. Il vaudrait bien sûr mieux diviser ces applications en microservices, mais tout le monde ne sait pas encore comment le faire ou n’a tout simplement pas le temps. Par conséquent, exécuter des applications telles que des services lancés par systemd à partir de fichiers unitaires est parfaitement logique.
- Fichiers d'unité Systemd – La plupart des applications exécutées dans des conteneurs sont créées à partir de code précédemment exécuté sur des machines virtuelles ou physiques. Ces applications disposent d'un fichier unité qui a été écrit pour ces applications et qui comprend comment elles doivent être lancées. Il est donc toujours préférable de démarrer les services en utilisant les méthodes prises en charge, plutôt que de pirater votre propre service d'initialisation.
- Systemd est un gestionnaire de processus. Il gère les services (arrête, redémarre les services ou tue les processus zombies) mieux que tout autre outil.
Cela dit, il existe de nombreuses raisons de ne pas exécuter systemd dans des conteneurs. Le principal est que systemd/journald contrôle la sortie des conteneurs et des outils comme
L'arrivée de Podman
Nous sommes heureux d’annoncer que la situation a enfin progressé. L'équipe responsable de l'exécution des conteneurs chez Red Hat a décidé de développer
Beaucoup le font.
Mon Podman et moi ne sommes en aucun cas contre les conteneurs basés sur systemd. Après tout, Systemd est le sous-système d'initialisation Linux le plus couramment utilisé, et ne pas lui permettre de fonctionner correctement dans des conteneurs signifie ignorer la façon dont des milliers de personnes sont habituées à exécuter des conteneurs.
Podman sait quoi faire pour que systemd fonctionne correctement dans un conteneur. Il a besoin de choses comme monter tmpfs sur /run et /tmp. Elle aime que l'environnement « conteneurisé » soit activé et attend des autorisations d'écriture sur sa partie du répertoire cgroup et sur le dossier /var/log/journald.
Lorsque vous démarrez un conteneur dans lequel la première commande est init ou systemd, Podman configure automatiquement tmpfs et Cgroups pour garantir que systemd démarre sans problème. Pour bloquer ce mode de lancement automatique, utilisez l'option --systemd=false. Veuillez noter que Podman n'utilise le mode systemd que lorsqu'il constate qu'il doit exécuter une commande systemd ou init.
Voici un extrait du manuel :
homme podman courir
...–systemd = vrai | faux
Exécuter un conteneur en mode systemd. Activé par défaut.
Si vous exécutez une commande systemd ou init dans un conteneur, Podman configurera les points de montage tmpfs dans les répertoires suivants :
/run, /run/lock, /tmp, /sys/fs/cgroup/systemd, /var/lib/journal
Le signal d'arrêt par défaut sera également SIGRTMIN+3.
Tout cela permet à systemd de s'exécuter dans un conteneur fermé sans aucune modification.
REMARQUE : systemd tente d'écrire sur le système de fichiers du groupe de contrôle. Cependant, SELinux empêche les conteneurs de le faire par défaut. Pour activer l'écriture, activez le paramètre booléen containers_manage_cgroup :
setsebool -P conteneur_manage_cgroup vrai
Regardez maintenant à quoi ressemble le Dockerfile pour exécuter systemd dans un conteneur à l'aide de Podman :
# cat Dockerfile
FROM fedora
RUN dnf -y install httpd; dnf clean all; systemctl enable httpd
EXPOSE 80
CMD [ "/sbin/init" ]
C'est tout.
Maintenant, nous assemblons le conteneur :
# podman build -t systemd .
Nous disons à SELinux d'autoriser systemd à modifier la configuration des Cgroups :
# setsebool -P container_manage_cgroup true
D’ailleurs, beaucoup de gens oublient cette étape. Heureusement, cela ne doit être fait qu'une seule fois et le paramètre est enregistré après le redémarrage du système.
Maintenant, nous démarrons simplement le conteneur :
# podman run -ti -p 80:80 systemd
systemd 239 running in system mode. (+PAM +AUDIT +SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD +IDN2 -IDN +PCRE2 default-hierarchy=hybrid)
Detected virtualization container-other.
Detected architecture x86-64.
Welcome to Fedora 29 (Container Image)!
Set hostname to <1b51b684bc99>.
Failed to install release agent, ignoring: Read-only file system
File /usr/lib/systemd/system/systemd-journald.service:26 configures an IP firewall (IPAddressDeny=any), but the local system does not support BPF/cgroup based firewalling.
Proceeding WITHOUT firewalling in effect! (This warning is only shown for the first loaded unit using IP firewalling.)
[ OK ] Listening on initctl Compatibility Named Pipe.
[ OK ] Listening on Journal Socket (/dev/log).
[ OK ] Started Forward Password Requests to Wall Directory Watch.
[ OK ] Started Dispatch Password Requests to Console Directory Watch.
[ OK ] Reached target Slices.
…
[ OK ] Started The Apache HTTP Server.
Ça y est, le service est opérationnel :
$ curl localhost
<html xml_lang="en" lang="en">
…
</html>
REMARQUE : n'essayez pas ceci sur Docker ! Là, il faut encore danser avec un tambourin pour lancer ce genre de conteneurs via le démon. (Des champs et packages supplémentaires seront requis pour que tout cela fonctionne de manière transparente dans Docker, ou il devra être exécuté dans un conteneur privilégié. Pour plus de détails, voir
Quelques autres choses intéressantes sur Podman et systemd
Podman fonctionne mieux que Docker dans les fichiers d'unité systemd
Si les conteneurs doivent être démarrés au démarrage du système, vous pouvez simplement insérer les commandes Podman appropriées dans le fichier d'unité systemd, qui démarrera le service et le surveillera. Podman utilise le modèle fork-exec standard. En d’autres termes, les processus conteneurs sont des enfants du processus Podman, donc systemd peut facilement les surveiller.
Docker utilise un modèle client-serveur et les commandes Docker CLI peuvent également être placées directement dans un fichier unité. Cependant, une fois que le client Docker se connecte au démon Docker, il (le client) devient simplement un autre processus traitant stdin et stdout. À son tour, systemd n'a aucune idée de la connexion entre le client Docker et le conteneur qui s'exécute sous le contrôle du démon Docker et, par conséquent, dans ce modèle, systemd ne peut fondamentalement pas surveiller le service.
Activation de systemd via socket
Podman gère correctement l'activation via socket. Étant donné que Podman utilise le modèle fork-exec, il peut transmettre le socket à ses processus conteneurs enfants. Docker ne peut pas faire cela car il utilise un modèle client-serveur.
Le service varlink que Podman utilise pour communiquer avec les clients distants vers les conteneurs est en fait activé via un socket. Le package cockpit-podman, écrit en Node.js et faisant partie du projet cockpit, permet aux utilisateurs d'interagir avec les conteneurs Podman via une interface Web. Le démon Web exécutant cockpit-podman envoie des messages à un socket varlink sur lequel systemd écoute. Systemd active ensuite le programme Podman pour recevoir des messages et commencer à gérer les conteneurs. L'activation de systemd sur un socket élimine le besoin d'un démon exécuté en permanence lors de l'implémentation d'API distantes.
De plus, nous développons un autre client Podman appelé podman-remote, qui implémente la même CLI Podman mais appelle varlink pour exécuter des conteneurs. Podman-remote peut s'exécuter sur les sessions SSH, vous permettant d'interagir en toute sécurité avec des conteneurs sur différentes machines. Au fil du temps, nous prévoyons de permettre à podman-remote de prendre en charge MacOS et Windows aux côtés de Linux, afin que les développeurs sur ces plates-formes puissent exécuter une machine virtuelle Linux avec Podman varlink en cours d'exécution et bénéficier de l'expérience complète de l'exécution des conteneurs sur la machine locale.
SD_NOTIFY
Systemd vous permet de différer le lancement des services auxiliaires jusqu'au démarrage du service conteneurisé dont ils ont besoin. Podman peut transmettre le socket SD_NOTIFY au service conteneurisé afin que le service informe systemd qu'il est prêt à fonctionner. Et encore une fois, Docker, qui utilise un modèle client-serveur, ne peut pas le faire.
les plans
Nous prévoyons d'ajouter la commande podman generate systemd CONTAINERID, qui générera un fichier unité systemd pour gérer un conteneur spécifique spécifié. Cela devrait fonctionner à la fois en mode root et sans racine pour les conteneurs non privilégiés. Nous avons même vu une demande pour un runtime systemd-nspawn compatible OCI.
Conclusion
Exécuter systemd dans un conteneur est un besoin compréhensible. Et grâce à Podman, nous disposons enfin d'un runtime de conteneur qui n'entre pas en conflit avec systemd, mais qui le rend facile à utiliser.
Source: habr.com