Vi har följt ämnet att använda systemd i containrar under lång tid. Redan 2014 skrev vår säkerhetsingenjör Daniel Walsh en artikel
I den här artikeln kommer vi att visa vad som har förändrats över tiden och hur Podman kan hjälpa oss i denna fråga.
Det finns många anledningar till att köra systemd inuti en behållare, till exempel:
- Multiservicecontainrar – många människor vill dra ut sina multitjänstapplikationer från virtuella maskiner och köra dem i containrar. Det skulle naturligtvis vara bättre att dela upp sådana applikationer i mikrotjänster, men inte alla vet hur man gör detta än eller har helt enkelt inte tid. Därför är det helt logiskt att köra sådana applikationer som tjänster som lanseras av systemd från enhetsfiler.
- Systemd Unit Files – De flesta applikationer som körs i containrar är byggda från kod som tidigare kördes på virtuella eller fysiska maskiner. Dessa applikationer har en enhetsfil som är skriven för dessa applikationer och förstår hur de ska startas. Så det är fortfarande bättre att starta tjänster med stödda metoder, snarare än att hacka din egen init-tjänst.
- Systemd är processledare. Den hanterar tjänster (stänger av, startar om tjänster eller dödar zombieprocesser) bättre än något annat verktyg.
Som sagt, det finns många anledningar till att inte köra systemd i containrar. Det viktigaste är att systemd/journald styr utmatningen av containrar och verktyg som
Podmans ankomst
Vi är glada att kunna rapportera att situationen äntligen har gått framåt. Teamet som ansvarar för att köra containrar på Red Hat bestämde sig för att utveckla
Många människor gör just det.
Min Podman och jag är inte på något sätt emot systembaserade behållare. När allt kommer omkring är Systemd det vanligaste Linux init-undersystemet, och att inte tillåta det att fungera korrekt i behållare innebär att ignorera hur tusentals människor är vana vid att köra behållare.
Podman vet vad man ska göra för att få systemd att fungera korrekt i en container. Den behöver saker som att montera tmpfs på /run och /tmp. Hon gillar att ha den "containeriserade" miljön aktiverad och förväntar sig skrivbehörigheter till sin del av cgroup-katalogen och till mappen /var/log/journald.
När du startar en container där det första kommandot är init eller systemd, konfigurerar Podman automatiskt tmpfs och Cgroups för att säkerställa att systemd startar utan problem. För att blockera detta automatiska startläge, använd alternativet --systemd=false. Observera att Podman endast använder systemd-läge när den ser att den behöver köra ett systemd- eller init-kommando.
Här är ett utdrag ur manualen:
man podman springa
.–systemd=true|false
Kör en container i systemd-läge. Aktiverad som standard.
Om du kör ett systemd- eller init-kommando inuti en container kommer Podman att konfigurera tmpfs-monteringspunkter i följande kataloger:
/run, /run/lock, /tmp, /sys/fs/cgroup/systemd, /var/lib/journal
Standard stoppsignal kommer också att vara SIGRTMIN+3.
Allt detta gör att systemd kan köras i en sluten behållare utan några ändringar.
OBS: systemd försöker skriva till cgroup-filsystemet. SELinux förhindrar dock behållare från att göra detta som standard. För att aktivera skrivning, aktivera den booleska parametern container_manage_cgroup:
setsebool -P container_manage_cgroup sant
Titta nu på hur Dockerfilen ser ut för att köra systemd i en behållare med Podman:
# cat Dockerfile
FROM fedora
RUN dnf -y install httpd; dnf clean all; systemctl enable httpd
EXPOSE 80
CMD [ "/sbin/init" ]
Det är allt.
Nu sätter vi ihop behållaren:
# podman build -t systemd .
Vi säger åt SELinux att tillåta systemd att ändra Cgroups-konfigurationen:
# setsebool -P container_manage_cgroup true
Förresten, många människor glömmer detta steg. Lyckligtvis behöver detta bara göras en gång och inställningen sparas efter omstart av systemet.
Nu startar vi bara behållaren:
# 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.
Det är allt, tjänsten är igång:
$ curl localhost
<html xml_lang="en" lang="en">
…
</html>
OBS: Prova inte detta på Docker! Där behöver du fortfarande dansa med en tamburin för att lansera den här typen av behållare genom demonen. (Ytterligare fält och paket kommer att krävas för att få allt att fungera sömlöst i Docker, eller så måste det köras i en privilegierad behållare. För detaljer, se
Ett par mer coola saker om Podman och systemd
Podman fungerar bättre än Docker i systemd-enhetsfiler
Om behållare behöver startas när systemet startar, kan du helt enkelt infoga lämpliga Podman-kommandon i systemd-enhetsfilen, som startar tjänsten och övervakar den. Podman använder standardmodellen fork-exec. Behållarprocesser är med andra ord barn till Podman-processen, så systemd kan enkelt övervaka dem.
Docker använder en klient-servermodell, och Docker CLI-kommandon kan också placeras direkt i en enhetsfil. Men när Docker-klienten ansluter till Docker-demonen, blir den (klienten) bara ytterligare en process som bearbetar stdin och stdout. Systemd har i sin tur ingen aning om kopplingen mellan Docker-klienten och behållaren som körs under kontroll av Docker-demonen, och därför, inom denna modell, kan systemd i princip inte övervaka tjänsten.
Aktiverar systemd via uttag
Podman hanterar aktivering via uttag korrekt. Eftersom Podman använder gaffel-exec-modellen kan den vidarebefordra socket till dess underordnade containerprocesser. Docker kan inte göra detta eftersom den använder en klient-servermodell.
Varlink-tjänsten som Podman använder för att kommunicera med fjärrklienter till containrar aktiveras faktiskt via en socket. Cockpit-podman-paketet, skrivet i Node.js och en del av cockpitprojektet, tillåter människor att interagera med Podman-behållare via ett webbgränssnitt. Webdemonen som kör cockpit-podman skickar meddelanden till en varlink-socket som systemd lyssnar på. Systemd aktiverar sedan Podman-programmet för att ta emot meddelanden och börja hantera containrar. Aktivering av systemd över en socket eliminerar behovet av en ständigt körande demon vid implementering av fjärr-API:er.
Dessutom utvecklar vi en annan Podman-klient som heter podman-remote, som implementerar samma Podman CLI men anropar varlink för att köra behållare. Podman-remote kan köras ovanpå SSH-sessioner, vilket gör att du säkert kan interagera med behållare på olika maskiner. Med tiden planerar vi att aktivera podman-remote för att stödja MacOS och Windows tillsammans med Linux, så att utvecklare på dessa plattformar kan köra en virtuell Linux-maskin med Podman varlink igång och ha den fulla upplevelsen av att behållare körs på den lokala maskinen.
SD_NOTIFY
Systemd låter dig skjuta upp lanseringen av extratjänster tills den containerservice de kräver startar. Podman kan vidarebefordra SD_NOTIFY-uttaget till den containeriserade tjänsten så att tjänsten meddelar systemd att den är redo att användas. Och återigen, Docker, som använder en klient-server-modell, kan inte göra detta.
I planerna
Vi planerar att lägga till kommandot podman generera systemd CONTAINERID, som kommer att generera en systemd enhetsfil för att hantera en specifik behållare. Detta bör fungera i både rot- och rotlöst läge för oprivilegierade behållare. Vi har till och med sett en begäran om en OCI-kompatibel systemd-nspawn runtime.
Slutsats
Att köra systemd i en container är ett förståeligt behov. Och tack vare Podman har vi äntligen en containerkörning som inte står i konflikt med systemd, men som gör den enkel att använda.
Källa: will.com