Vi har længe fulgt emnet om brugen af systemd i containere. Allerede i 2014 skrev vores sikkerhedingeniør Daniel Walsh en artikel , og et par år senere en anden, der hed , hvor han bemærkede, at situationen ikke var blevet meget bedre. Blandt andet skrev han, at "desværre, to år senere, når man googler "Docker system", så dukker hans gamle artikel stadig først op. Det betyder, at det er tid til at ændre noget." Derudover har vi tidligere omtalt en .
I denne artikel vil vi vise, hvad der er sket siden dengang, og hvordan Podman kan hjælpe os i denne sag.
Der er mange grunde til at køre systemd inde i en container, såsom:
- Multitjeneste-containere – mange ønsker at trække deres multitjenesteapplikationer ud af virtuelle maskiner og køre dem i containere. Det ville være bedst at opdele sådanne applikationer i mikrotjenester, men ikke alle har færdighederne til det endnu, eller der er simpelthen ikke tid. Derfor giver det mening at køre sådanne applikationer som tjenester, der startes af systemd fra enhetsfiler.
- Systemd enhetsfiler – de fleste applikationer, der kører inde i containere, er bygget af kode, der tidligere blev kørt på virtuelle eller fysiske maskiner. Disse applikationer har en enhetsfil, som blev skrevet til disse applikationer og ved, hvordan de skal startes. Så tjenester er bedst at starte ved hjælp af understøttede metoder og ikke ved at hacke sin egen init-tjeneste.
- Systemd er en procesmanager. Den håndterer tjenester (stopper, genstarter tjenester eller rydder op i zombie-proceser) bedre end ethvert andet værktøj.
Der er dog også mange grunde til ikke at køre systemd i containere. Den primære grund er, at systemd/journald kontrollerer output fra containerne, mens værktøjer som eller forventer, at containerne skriver logs direkte til stdout og stderr. Derfor, hvis du planlægger at administrere containere gennem orkestreringsværktøjer som nævnt ovenfor, bør du alvorligt overveje spørgsmålet om brugen af containere baseret på systemd. Desuden har udviklerne af Docker og Moby ofte været skarpt imod brugen af systemd i containere.
Ankomsten af Podman
Vi er glade for at meddele, at situationen endelig er rykket fremad. Holdet ansvarligt for containerlancering hos Red Hat har besluttet at udvikle . Den har fået navnet og tilbyder det samme kommandolinjegrænseflade (CLI) som Docker. Og næsten alle Docker-kommandoer kan bruges på samme måde i Podman. Vi holder ofte seminarer, som nu hedder , og det første slide opfordrer til at skrive: alias docker=podman.
Mange gør netop dette.
Vi er slet ikke imod systemd-baserede containere med vores Podman. For systemd bruges oftest som init-system i Linux, og at nægte det at fungere korrekt i containere betyder at ignorere, hvordan tusinder af mennesker er vant til at køre containere.
Podman ved, hvad der skal gøres, for at systemd fungerer korrekt i en container. Det har brug for ting som at montere tmpfs på /run og /tmp. Det kan godt lide, når 'container'-miljøet er aktiveret, og det venter på skrivetilladelser til sin del af cgroup-kataloget og mappen /var/log/journald.
Når en container startes, hvor den første kommando er init eller systemd, konfigurerer Podman automatisk tmpfs og Cgroups for at sikre, at opstarten af systemd forløber uden problemer. For at blokere for denne automatisk opstartsmetode, anvendes indstillingen —systemd=false. Bemærk, at Podman kun bruger systemd-tilstand, når det ser, at der skal udføres en systemd- eller init-kommando.
Her er et uddrag fra manualen:
man podman run
…–systemd=true|false
Start af containeren i systemd-tilstand. Som standard er det aktiveret.
Hvis en systemd- eller init-kommando udføres inde i containeren, vil Podman konfigurere tmpfs-monteringspunkter i følgende kataloger:
/run, /run/lock, /tmp, /sys/fs/cgroup/systemd, /var/lib/journal
Desuden vil SIGRTMIN+3 som standard blive brugt som stop-signal.
Alt dette gør det muligt for systemd at fungere i en aflukket container uden modificationer.
BEMÆRKNING: systemd forsøger at skrive til cgroup filsystemet. Men SELinux forhindrer som standard containere i at gøre dette. For at tillade skrivning, skal den logiske parameter container_manage_cgroup aktiveres:
setsebool -P container_manage_cgroup true
Nu kan vi se, hvordan Dockerfile ser ud for at starte systemd i en container ved hjælp af Podman:
# cat Dockerfile
FROM fedora
RUN dnf -y install httpd; dnf clean all; systemctl enable httpd
EXPOSE 80
CMD [ "/sbin/init" ]
Det er alt.
Nu samler vi containeren:
# podman build -t systemd .
Vi beder SELinux om at tillade systemd at ændre konfigurationen af Cgroups:
# setsebool -P container_manage_cgroup true
Mange glemmer i øvrigt dette skridt. Heldigvis er det nok at gøre dette én gang, og indstillingen gemmes efter genstart af systemet.
Nu starter vi blot containeren:
# 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 er det, tjenesten er startet og kører:
$ curl localhost
<html xml_lang="en" lang="en">
…
</html>
BEMÆRKNING: Forsøg ikke at gøre dette på Docker! Der kræves stadig en del arbejde for at køre sådanne containere via dæmonen. (Yderligere felter og pakker er nødvendige for at få dette til at køre problemfrit i Docker, eller det skal køres i en privilegeret container. Se nærmere i .)
Et par flere fede ting om Podman og systemd
Podman fungerer bedre end Docker i systemd enheds-filer
Hvis containere skal startes ved systemopstart, kan du blot indsætte de relevante Podman-kommandoer i systemd enheds-filen, som vil starte tjenesten og overvåge den. Podman bruger en standard fork-exec model ved udførelse. Med andre ord er containerprocesserne børn af Podman-processen, så systemd kan nemt overvåge dem.
Docker bruger en klient-server model, og Docker CLI-kommandoer kan også placeres direkte i enheds-filen. Men efter at Docker-klienten opretter forbindelse til Docker-dæmonen, bliver den (klienten) blot en anden proces, der håndterer stdin og stdout. I sin tur har systemd ingen idé om forbindelsen mellem Docker-klienten og containeren, der kører under Docker-dæmonen, og derfor kan systemd principielt ikke overvåge tjenesten under denne model.
Aktivering af systemd gennem socket
Podman håndterer korrekt aktivering via socket. Da Podman bruger fork-exec modellen, kan det videregive socket til sine underliggende containerprocesser. Docker kan ikke gøre dette, da det bruger klient-server modellen.
Varlink-tjenesten, som Podman bruger til at interagere med fjerntilsluttede klienter til containere, aktiveres faktisk via en socket. Cockpit-podman-pakken, der er skrevet i Node.js og en del af cockpit-projektet, gør det muligt for folk at interagere med Podman-containere gennem et webinterface. Webdæmonen, der kører cockpit-podman, sender beskeder til varlink-socketen, som overvåges af systemd. Herefter aktiverer systemd Podman-programmet for at modtage beskeder og begynde at administrere containere. Aktivering af systemd via socket gør det muligt at undgå en konstant kørende dæmon ved implementeringen af fjerntilgængelige API'er.
Derudover udvikler vi en anden klient til Podman, kaldet podman-remote, som implementerer den samme Podman CLI, men kalder varlink for at starte containere. Podman-remote kan køre over SSH-sessioner, hvilket gør det muligt at interagere sikkert med containere på forskellige maskiner. Over tid planlægger vi at inkludere podman-remote til at understøtte MacOS og Windows sammen med Linux, så udviklere på disse platforme kan køre en Linux-virtuel maskine med fungerende Podman varlink og have en fuld oplevelse af, at containere kører på deres lokale maskine.
SD_NOTIFY
Systemd tillader forsinkelse i opstarten af hjælpeprogrammer, indtil den nødvendige containeriserede tjeneste starter. Podman kan videregive SD_NOTIFY-socketen til den containeriserede tjeneste, så tjenesten kan informere systemd om dens beredskab. Igen er Docker, som bruger en klient-server-model, ikke i stand til dette.
Planer
Vi planlægger at tilføje kommandoen podman generate systemd CONTAINERID, som vil generere en systemd-enhedsfiler til at styre en specifik angiven container. Dette bør fungere både i root- og rootless-tilstande for ikke-privilegerede containere. Vi har endda set en anmodning om at skabe en OCI-kompatibel runtime til systemd-nspawn.
Konklusion
At køre systemd i en container er et forståeligt behov. Og takket være Podman har vi endelig en containerkørselsmiljø, der ikke er i konflikt med systemd, men som gør det nemt at bruge.
Kilde: habr.com
