Systemd in een container draaien

We volgen het onderwerp van het gebruik van systemd in containers al een hele tijd. In 2014 schreef onze beveiligingsingenieur Daniel Walsh een artikel Systemd draaien binnen een Docker Container, en een paar jaar later - nog een, die werd genoemd Systemd uitvoeren in een niet-bevoorrechte container, waarin hij stelde dat de situatie niet veel was verbeterd. In het bijzonder schreef hij dat “helaas, zelfs twee jaar later, als je op “Docker-systeem” googelt, het eerste dat naar boven komt hetzelfde oude artikel is. Het is dus tijd om iets te veranderen.” Bovendien hebben we er al over gesproken conflict tussen Docker en systemd-ontwikkelaars.

Systemd in een container draaien

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

Er zijn veel redenen om systemd in een container uit te voeren, zoals:

  1. Multifunctionele containers – veel mensen willen hun multiservice-applicaties uit virtuele machines halen en in containers draaien. Het zou natuurlijk beter zijn om zulke applicaties op te splitsen in microservices, maar nog niet iedereen weet hoe dat moet of heeft daar eenvoudigweg de tijd niet voor. Daarom is het volkomen logisch om dergelijke applicaties uit te voeren als services die door systemd worden gelanceerd vanuit eenheidsbestanden.
  2. Systemd Unit-bestanden – De meeste applicaties die in containers draaien, zijn opgebouwd uit code die voorheen op virtuele of fysieke machines draaide. Deze applicaties hebben een eenheidsbestand dat voor deze applicaties is geschreven en begrijpt hoe ze moeten worden gestart. Het is dus nog steeds beter om services te starten met behulp van ondersteunde methoden, in plaats van uw eigen init-service te hacken.
  3. Systemd is procesmanager. Het beheert services (sluit services af, start services opnieuw of doodt zombieprocessen) beter dan welk ander hulpmiddel dan ook.

Dat gezegd hebbende, zijn er veel redenen om systemd niet in containers te draaien. De belangrijkste is dat systemd/journald de uitvoer van containers en tools zoals Kubernetes of OpenShift verwacht dat containers het logboek rechtstreeks naar stdout en stderr schrijven. Als u containers gaat beheren via orkestratietools zoals de hierboven genoemde, moet u daarom serieus overwegen om op systemd gebaseerde containers te gebruiken. Bovendien zijn Docker- en Moby-ontwikkelaars vaak sterk gekant tegen het gebruik van systemd in containers.

De komst van Podman

We zijn blij te kunnen melden dat de situatie eindelijk vooruit is gegaan. Het team dat verantwoordelijk is voor het runnen van containers bij Red Hat besloot zich te ontwikkelen uw eigen containermotor. Hij kreeg een naam podman en biedt dezelfde opdrachtregelinterface (CLI) als Docker. En bijna alle Docker-opdrachten kunnen op dezelfde manier in Podman worden gebruikt. We houden vaak seminars, die nu worden genoemd Docker wijzigen in Podman, en de allereerste dia vraagt ​​om schrijven: alias docker=podman.

Veel mensen doen precies dat.

Mijn Podman en ik zijn op geen enkele manier tegen systemd-gebaseerde containers. Systemd is tenslotte het meest gebruikte Linux init-subsysteem, en als je het niet goed laat werken in containers, betekent dit dat je negeert hoe duizenden mensen gewend zijn aan het draaien van containers.

Podman weet wat hij moet doen om systemd goed te laten werken in een container. Het heeft zaken nodig zoals het mounten van tmpfs op /run en /tmp. Ze vindt het prettig als de "gecontaineriseerde" omgeving is ingeschakeld en verwacht schrijfrechten voor haar deel van de cgroup-directory en voor de map /var/log/journald.

Wanneer u een container start waarin het eerste commando init of systemd is, configureert Podman automatisch tmpfs en Cgroups om ervoor te zorgen dat systemd zonder problemen opstart. Om deze automatische startmodus te blokkeren, gebruikt u de --systemd=false optie. Houd er rekening mee dat Podman alleen de systemd-modus gebruikt als hij ziet dat hij een systemd- of init-opdracht moet uitvoeren.

Hier is een fragment uit de handleiding:

man podman rennen
...

–systemd=waar|onwaar

Een container uitvoeren in de systemd-modus. Standaard ingeschakeld.

Als u een systemd- of init-opdracht in een container uitvoert, configureert Podman tmpfs-koppelpunten in de volgende mappen:

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

Het standaard stopsignaal is ook SIGRTMIN+3.

Dit alles zorgt ervoor dat systemd zonder enige aanpassingen in een gesloten container kan draaien.

OPMERKING: systemd probeert naar het cgroup-bestandssysteem te schrijven. SELinux verhindert echter standaard dat containers dit doen. Om schrijven mogelijk te maken, schakelt u de container_manage_cgroup booleaanse parameter in:

setsebool -P container_manage_cgroup waar

Kijk nu hoe het Dockerbestand eruit ziet voor het uitvoeren 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.

Nu monteren we de container:

# podman build -t systemd .

We vertellen SELinux om systemd toe te staan ​​de Cgroups-configuratie te wijzigen:

# setsebool -P container_manage_cgroup true

Trouwens, veel mensen vergeten deze stap. Gelukkig hoeft dit maar één keer te gebeuren en wordt de instelling opgeslagen na het opnieuw opstarten 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.

Dat is alles, de service is actief:

$ curl localhost

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

…

</html>

OPMERKING: Probeer dit niet op Docker! Daar moet je nog met een tamboerijn dansen om dit soort containers door de daemon te lanceren. (Er zijn extra velden en pakketten nodig om dit allemaal naadloos te laten werken in Docker, of het moet worden uitgevoerd in een geprivilegieerde container. Zie voor details статье.)

Nog een paar leuke dingen over Podman en systemd

Podman werkt beter dan Docker in systemd unit-bestanden

Als containers moeten worden gestart wanneer het systeem opstart, kunt u eenvoudig de juiste Podman-opdrachten in het systemd unit-bestand invoegen, waardoor de service wordt gestart en gecontroleerd. Podman gebruikt het standaard vork-exec-model. Met andere woorden: containerprocessen zijn kinderen van het Podman-proces, dus systemd kan ze eenvoudig monitoren.

Docker maakt gebruik van een client-servermodel en Docker CLI-opdrachten kunnen ook rechtstreeks in een eenheidsbestand worden geplaatst. Zodra de Docker-client echter verbinding maakt 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 verbinding tussen de Docker-client en de container die onder de controle van de Docker-daemon draait, en daarom kan systemd binnen dit model de service fundamenteel niet monitoren.

Systeem activeren via socket

Podman verwerkt de activering via socket correct. Omdat Podman het fork-exec-model gebruikt, kan het de socket doorsturen naar de onderliggende containerprocessen. Docker kan dit niet doen omdat het een client-servermodel gebruikt.

De varlink-service die Podman gebruikt om met externe clients naar containers te communiceren, wordt feitelijk geactiveerd via een socket. Met het cockpit-podman-pakket, geschreven in Node.js en onderdeel van het cockpitproject, kunnen mensen via een webinterface communiceren met Podman-containers. De webdaemon waarop Cockpit-podman draait, stuurt berichten naar een varlink-socket waar systemd naar luistert. Systemd activeert vervolgens het Podman-programma om berichten te ontvangen en containers te beheren. Door systemd via een socket te activeren, is er geen constant actieve daemon nodig bij het implementeren van externe API's.

Daarnaast ontwikkelen we een andere Podman-client genaamd podman-remote, die dezelfde Podman CLI implementeert maar varlink aanroept om containers uit te voeren. Podman-remote kan bovenop SSH-sessies worden uitgevoerd, waardoor u veilig kunt communiceren met containers op verschillende machines. In de loop van de tijd zijn we van plan om podman-remote in te schakelen om MacOS en Windows naast Linux te ondersteunen, zodat ontwikkelaars op die platforms een virtuele Linux-machine kunnen draaien terwijl Podman varlink draait en de volledige ervaring hebben dat containers op de lokale machine draaien.

SD_NOTIFY

Met Systemd kunt u de lancering van aanvullende diensten uitstellen totdat de gecontaineriseerde dienst die ze nodig hebben, begint. Podman kan de SD_NOTIFY-socket doorsturen naar de gecontaineriseerde service, zodat de service systemd laat weten dat deze klaar is voor gebruik. En nogmaals, Docker, dat een client-servermodel gebruikt, kan dit niet.

In de plannen

We zijn van plan om de opdracht podman genereren systemd CONTAINERID toe te voegen, die een systemd-eenheidsbestand zal genereren om een ​​specifieke gespecificeerde container te beheren. Dit zou moeten werken in zowel root- als rootless-modi voor containers zonder privileges. We hebben zelfs een verzoek gezien voor een OCI-compatibele systemd-nspawn-runtime.

Conclusie

Het uitvoeren van systemd in een container is een begrijpelijke behoefte. En dankzij Podman hebben we eindelijk een containerruntime die niet conflicteert met systemd, maar die wel gemakkelijk te gebruiken is.

Bron: www.habr.com

Voeg een reactie