We volgen het onderwerp van het gebruik van systemd in containers al een hele tijd. In 2014 schreef onze beveiligingsingenieur Daniel Walsh een artikel
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:
- 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.
- 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.
- 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
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
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