Vi har fulgt temaet om bruk av systemd i containere i lang tid. Allerede i 2014 skrev vår sikkerhetsingeniør Daniel Walsh en artikkel , og et par år senere – en annen, som het , hvor han bemerket at situasjonen ikke hadde forbedret seg mye. Blant annet skrev han at «dessverre, selv to år senere, hvis du googler «Docker system», så dukker fortsatt den gamle artikkelen hans opp først. Det betyr at det er på tide å endre noe». I tillegg har vi tidligere snakket om .
I denne artikkelen vil vi vise hva som har endret seg over tid og hvordan Podman kan hjelpe oss med dette.
Det finnes mange grunner til å kjøre systemd inne i en container, for eksempel:
- Multitjenestekontainere – mange ønsker å ta sine multitjenesteapplikasjoner ut av virtuelle maskiner og kjøre dem i containere. Det ville vært best å dele slike applikasjoner opp i mikrotjenester, men ikke alle kan dette eller har tid til det. Derfor gir det mening å kjøre slike applikasjoner som tjenester, som blir startet av systemd fra enhet-filer.
- Systemd enhet-filer – de fleste applikasjoner som kjører inne i containere, er laget av koden som tidligere ble kjørt på virtuelle eller fysiske maskiner. Disse applikasjonene har en enhet-fil som ble skrevet for disse applikasjonene og vet hvordan de skal startes. Så tjenester bør fortsatt kjøres med støttede metoder, i stedet for å hacke sin egen init-tjeneste.
- Systemd er en prosessdistributør. Den håndterer tjenester (stopper, gjenstarter tjenester eller dreper zombie-prosesser) bedre enn noe annet verktøy.
Samtidig er det mange grunner til å ikke kjøre systemd i containere. Den viktigste er at systemd/journald kontrollerer utdataene fra containerne, og verktøy som eller forventes at containerne skriver logger direkte til stdout og stderr. Derfor, hvis du planlegger å administrere containere via orkestreringsverktøy som nevnt ovenfor, må du seriøst vurdere bruken av containere basert på systemd. I tillegg har utviklerne av Docker og Moby ofte vært kraftig imot bruk av systemd i containere.
Ankomsten av Podman
Vi er glade for å kunne meddele at situasjonen endelig har beveget seg fremover. Teamet som er ansvarlig for containerlansering i Red Hat har besluttet å utvikle . Den fikk navnet og tilbyr samme kommandolinjegrensesnitt (CLI) som Docker. Nesten alle Docker-kommandoer kan brukes på samme måte i Podman. Vi holder ofte seminarer som nå kalles , og det første lysbildet oppfordrer til å skrive: alias docker=podman.
Mange gjør nettopp det.
Vi er på ingen måte imot systemd-baserte containere med vår Podman. Systemd brukes ofte som init-system i Linux, og å hindre det i å fungere ordentlig i containere, betyr å ignorere hvordan tusenvis av folk er vant til å kjøre containere.
Podman vet hva som må gjøres for at systemd skal fungere ordentlig i en container. Den trenger ting som å montere tmpfs på /run og /tmp. Den liker når den «container»-miljøet er aktivert, og den forventer skrivetilgang til sin del av cgroup-katalogen og mappen /var/log/journald.
Ved oppstart av en container der init eller systemd er den første kommandoen, konfigurerer Podman automatisk tmpfs og Cgroups slik at oppstarten av systemd går problemfritt. For å blokkere denne automatiske oppstarten brukes alternativet —systemd=false. Merk at Podman bruker systemd-modus bare når den ser at det må utføres en systemd- eller init-kommando.
Her er et utdrag fra manualen:
man podman run
…–systemd=true|false
Kjøre containeren i systemd-modus. Som standard aktivert.
Hvis det kjøres en systemd- eller init-kommando inne i containeren, vil Podman konfigurere tmpfs-monteringspunktene i følgende kataloger:
/run, /run/lock, /tmp, /sys/fs/cgroup/systemd, /var/lib/journal
Som stoppesignal vil SIGRTMIN+3 bli brukt som standard.
Alt dette gjør at systemd fungerer i en lukket container uten noen modifikasjoner.
MERK: systemd prøver å skrive til cgroup-filsystemet. Men SELinux forbyr som standard containere å gjøre dette. For å tillate skriving, aktiver boolsk parameter container_manage_cgroup:
setsebool -P container_manage_cgroup true
Se nå hvordan Dockerfile for oppstart av systemd i containere med Podman ser ut:
# cat Dockerfile
FROM fedora
RUN dnf -y install httpd; dnf clean all; systemctl enable httpd
EXPOSE 80
CMD [ "/sbin/init" ]
Det var det.
Nå bygger vi containeren:
# podman build -t systemd .
Vi ber SELinux om å tillate systemd å modifisere cgroup-konfigurasjonen:
# setsebool -P container_manage_cgroup true
Mange glemmer faktisk dette steg. Heldigvis trenger man bare å gjøre dette én gang, og innstillingene lagres etter systemoppstart.
Nå starter vi bare 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.
Ferdig, tjenesten er startet og virker:
$ curl localhost
<html xml_lang="en" lang="en">
…
</html>
MERK: Ikke prøv å gjenskape dette på Docker! Der trengs fremdeles dansing med tambur for å kjøre slike containere via demon. (Det vil kreve ekstra felt og pakker for at alt dette skal fungere sømløst i Docker, eller må kjøres i en privilegert container. Se detaljer i .)
Et par kule ting om Podman og systemd
Podman fungerer bedre enn Docker i systemd enhetsfiler
Hvis containere skal startes ved systemoppstart, kan du enkelt sette inn de relevante Podman-kommandoene i systemd enhetsfilen, som da vil starte tjenesten og overvåke den. Podman bruker standard kjøremodell (fork-exec). Med andre ord er containerprosessene datterprosesser til Podman-prosessen, noe som gjør at systemd lett kan overvåke dem.
Docker bruker klient-server-modellen, og Docker-cli-kommandoer kan også plasseres rett i enhetsfilen. Men etter at Docker-klienten kobler til Docker-demonen, blir den (klienten) bare en annen prosess som håndterer stdin og stdout. Systemd har derimot ingen forståelse av forbindelsen mellom Docker-klienten og containeren som kjører under Docker-demonen, og dermed kan systemd prinsipielt ikke overvåke tjenesten innenfor denne modellen.
Aktivering av systemd via socket
Podman håndterer socket-aktivering korrekt. Siden Podman bruker fork-exec-modellen, kan den sende socket til sine datterprosess-containere. Docker kan ikke gjøre dette, ettersom den bruker klient-server-modellen.
Varlink-tjenesten som Podman bruker for å muliggjøre interaksjon mellom eksterne klienter og containere, aktiveres faktisk gjennom en socket. Cockpit-podman-pakken, skrevet i Node.js og en del av cockpit-prosjektet, lar folk samhandle med Podman-containere via et webgrensesnitt. Webdaemonen som kjører cockpit-podman sender meldinger til varlink-socketen som overvåkes av systemd. Deretter aktiverer systemd Podman-programmet for å motta meldinger og begynne å administrere containere. Aktivering av systemd via socket gjør det mulig å unngå å ha en konstant kjørende daemon ved implementering av fjern-APIer.
I tillegg utvikler vi en annen klient for Podman kalt podman-remote, som implementerer det samme Podman CLI, men bruker varlink for å starte containere. Podman-remote kan kjøre over SSH-økter, noe som gir sikker interaksjon med containere på forskjellige maskiner. Vi planlegger etter hvert å gjøre podman-remote tilgjengelig for MacOS og Windows i tillegg til Linux, slik at utviklere på disse plattformene kan kjøre en Linux-virtuell maskin med Podman varlink og få følelsen av at containerne kjører lokalt.
SD_NOTIFY
Systemd lar deg forsinke oppstarten av hjelpeprogrammer til det tidspunktet det nødvendige containeriserte tjenesten starter. Podman kan overføre SD_NOTIFY-socketen til den containeriserte tjenesten, slik at tjenesten kan varsle systemd om at den er klar til å arbeide. Igjen, Docker, som bruker klient-server-modellen, kan ikke gjøre dette.
Planene
Vi planlegger å legge til kommandoen podman generate systemd CONTAINERID, som vil generere en systemd-enhetsfil for å administrere en spesifikk spesifisert container. Dette skal fungere både i root- og rootless-modus for ikke-privilegerte containere. Vi har til og med sett forespørselen om å lage en OCI-kompatibel systemd-nspawn-kjøringsmiljø.
Konklusjon
Å kjøre systemd i en container er en helt nødvendig funksjon. Og med Podman har vi endelig fått et containerkjøringsmiljø som ikke er fiendtlig overfor systemd, men lar det brukes enkelt.
Kilde: habr.com
