We starten systemd in een container

We hebben de ontwikkeling van systemd in containers al een tijd in de gaten gehouden. Al in 2014 schreef onze beveiligingsingenieur Daniel Walsh een artikel Running systemd within a Docker Container, en een paar jaar later – een ander, getiteld Running systemd in a non-privileged container, waarin hij vaststelde dat de situatie niet veel verbeterd was. Hij schreef bijvoorbeeld: "helaas, zelfs twee jaar later, als je 'Docker system' googelt, verschijnt als eerste altijd zijn oude artikel. Het is tijd voor verandering." Daarnaast hebben we al eens gesproken over het conflict tussen de ontwikkelaars van Docker en systemd.

We starten systemd in een container

In dit artikel laten we zien wat er in de tussentijd is veranderd en hoe Podman ons hierbij kan helpen.

Er zijn veel redenen om systemd binnen een container te draaien, zoals:

  1. Multiservicecontainers – velen willen hun multiservice-applicaties uit virtuele machines halen en ze in containers draaien. Het is natuurlijk beter om dergelijke applicaties op te splitsen in microservices, maar niet iedereen kan dat nog of heeft eenvoudigweg geen tijd. Daarom heeft het zeker zin om deze applicaties als diensten, met behulp van systemd via unit-bestanden, te draaien.
  2. Systemd-unitbestanden – de meeste applicaties die binnen containers draaien, zijn opgebouwd uit code die eerder op virtuele of fysieke machines draaide. Deze applicaties hebben een unit-bestand dat specifiek voor deze applicaties is geschreven en begrijpt hoe ze moeten worden gestart. Het is dus beter om diensten op te starten met ondersteunde methoden, in plaats van je eigen init-service te hacken.
  3. Systemd is een procesbeheerder. Het beheert diensten (stopt, herstart of verwijdert zombieprocessen) beter dan welk ander hulpmiddel ook.

Toch zijn er ook veel redenen om systemd niet in containers te draaien. De belangrijkste is dat systemd/journald de uitvoer van containers beheert, terwijl tools zoals Kubernetes of OpenShift ervan uitgaan dat containers logs rechtstreeks naar stdout en stderr schrijven. Dus, als je van plan bent om containers te beheren via orchestration tools zoals eerder genoemd, moet je serieus nadenken over het gebruik van systemd-gebaseerde containers. Bovendien waren de ontwikkelaars van Docker en Moby vaak fel tegen het gebruik van systemd in containers.

De opkomst van Podman

We zijn blij te melden dat de situatie eindelijk in beweging is gekomen. Het team van Red Hat dat verantwoordelijk is voor het lanceren van containers, heeft besloten hun eigen containerengine te ontwikkelen. Het heeft de naam gekregen Podman en biedt dezelfde command line interface (CLI) als Docker. Bijna alle Docker-commando's kunnen op dezelfde manier worden gebruikt in Podman. We houden vaak workshops die nu worden genoemd Overstappen van Docker naar Podman, en de eerste dia roept op om te schrijven: alias docker=podman.

Veel mensen doen dat.

Met onze Podman zijn we op geen enkele manier tegen containers op basis van systemd. Systemd wordt immers vaak gebruikt als init-systeem in Linux, en het niet goed laten functioneren in containers betekent dat we negeren hoe duizenden mensen gewend zijn om containers op te starten.

Podman weet wat nodig is om systemd goed te laten functioneren in een container. Het heeft dingen nodig zoals het koppelen van tmpfs aan /run en /tmp. Het werkt het beste wanneer de "containeromgeving" is ingeschakeld, en het wacht op schrijfrechten in zijn cgroup-directory en de map /var/log/journald.

Bij het opstarten van een container waarvan de eerste opdracht init of systemd is, configureert Podman automatisch tmpfs en Cgroups zodat systemd zonder problemen kan starten. Om deze automatische startmodus te blokkeren, kan de optie --systemd=false worden gebruikt. Let op dat Podman de systemd-modus alleen gebruikt wanneer het ziet dat er een systemd- of init-opdracht moet worden uitgevoerd.

Hier is een citaat uit de handleiding:

man podman run
…

--systemd=true|false

Start een container in de systemd-modus. Standaard is dit ingeschakeld.

Als er binnen de container een systemd- of init-opdracht wordt uitgevoerd, configureert Podman de tmpfs-koppelpunten in de volgende mappen:

/run, /run/lock, /tmp, /sys/fs/cgroup/systemd, /var/lib/journal

Daarnaast wordt standaard het signaal SIGRTMIN+3 gebruikt als stop-signaal.

Dit alles stelt systemd in staat om te functioneren in een afgesloten container zonder enige aanpassingen.

OPMERKING: systemd probeert te schrijven naar het cgroup-bestandssysteem. Echter, SELinux staat containers dit standaard niet toe. Om schrijven toe te staan, schakelt u de logische parameter container_manage_cgroup in:

setsebool -P container_manage_cgroup true

Bekijk nu hoe een Dockerfile eruitziet voor het opstarten van systemd in een container met behulp van Podman:

# cat Dockerfile

FROM fedora

RUN dnf -y install httpd; dnf clean all; systemctl enable httpd

EXPOSE 80

CMD [ "/sbin/init" ]

Dat is alles.

Laten we nu de container bouwen:

# podman build -t systemd .

Laat SELinux systemd toestaan om de configuratie van Cgroups te wijzigen:

# setsebool -P container_manage_cgroup true

Veel mensen vergeten deze stap trouwens. Gelukkig hoeft dit maar ƩƩn keer te worden gedaan en de instellingen blijven behouden na het herstarten van het systeem.

Nu starten we gewoon de container:

# 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.

Klaar, de service is gestart en werkt:

$ curl localhost

<html  xml_lang="en" lang="en">

…

</html>

OPMERKING: Probeer dit niet op Docker! Daar zijn nog steeds allerlei ingewikkelde stappen nodig om dit soort containers via de daemon te starten. (Extra velden en pakketten zijn nodig om dit soepel te laten werken in Docker, of je moet het in een bevoorrechte container draaien. Zie voor details artikel.)

Nog een paar leuke dingen over Podman en systemd

Podman werkt beter dan Docker in systemd-unitbestanden

Als je containers bij het opstarten van het systeem wilt starten, kun je eenvoudig de bijbehorende Podman-commando's in het systemd-unitbestand invoegen, dat de service start en deze monitort. Podman gebruikt het standaard fork-exec-model tijdens de uitvoering. Met andere woorden, de containerprocessen zijn kindprocessen van de Podman-proces, waardoor systemd ze eenvoudig kan monitoren.

Docker gebruikt een client-servermodel, en Docker CLI-commando's kunnen ook rechtstreeks in het unitbestand worden geplaatst. Nadat de Docker-client echter is verbonden met de Docker-daemon, wordt deze (de client) gewoon een ander proces dat stdin en stdout verwerkt. Systemd heeft op zijn beurt geen idee van de relatie tussen de Docker-client en de container die onder de Docker-daemon draait, en daarom kan systemd in dit model de service principieel niet monitoren.

Activatie van systemd via de socket

Podman werkt correct met socketactivatie. Aangezien Podman het fork-exec-model gebruikt, kan het de socket doorgeven aan zijn kindcontainerprocessen. Docker kan dit niet omdat het een client-servermodel gebruikt.

De varlink-service die Podman gebruikt voor de interactie tussen externe clients en containers, wordt eigenlijk geactiveerd via een socket. Het pakket cockpit-podman, geschreven in Node.js en onderdeel van het cockpit-project, stelt gebruikers in staat om te communiceren met Podman-containers via een webinterface. De webdaemon waarop cockpit-podman draait, verzendt berichten naar de varlink-socket, die door systemd wordt afgeluisterd. Vervolgens activeert systemd het Podman-programma om berichten te ontvangen en het beheer van containers te starten. De activatie van systemd via de socket maakt het mogelijk om zonder een voortdurend draaiende daemon te werken bij het implementeren van externe API's.

Daarnaast ontwikkelen we een andere client voor Podman, genaamd podman-remote, die dezelfde Podman CLI implementeert, maar varlink aanroept om containers te starten. Podman-remote kan werken bovenop SSH-sessies, waardoor veilig contact maken met containers op verschillende machines mogelijk is. In de toekomst zijn we van plan om podman-remote te ondersteunen voor MacOS en Windows naast Linux, zodat ontwikkelaars op deze platforms een Linux-virtuele machine met een draaiende Podman varlink kunnen starten en een volledig gevoel hebben dat de containers op hun lokale machine draaien.

SD_NOTIFY

Systemd maakt het mogelijk om de lancering van hulpservices uit te stellen tot het moment dat de vereiste containerized service opstart. Podman kan de SD_NOTIFY-socket doorgeven aan de containerized service, zodat deze service systemd kan informeren over zijn gereedheid om te werken. En nogmaals, Docker, dat een client-servermodel gebruikt, kan dit niet.

Plannen

We zijn van plan om de opdracht podman generate systemd CONTAINERID toe te voegen, die een systemd-unitbestand genereert voor het beheren van een specifieke opgegeven container. Dit zou moeten werken in zowel root- als rootless-modus voor niet-privilege containers. We hebben zelfs een verzoek gezien om een OCI-compatibele uitvoering van systemd-nspawn te creƫren.

Conclusie

Het draaien van systemd in een container is een heel begrijpelijke behoefte. En dankzij Podman hebben we eindelijk een container-runtime-omgeving die niet in conflict is met systemd, maar het gemakkelijk maakt om te gebruiken.

Bron: habr.com

Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers šŸ”„ Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers | ProHoster