Kjører systemd i en container

Vi har fulgt med på temaet bruk av systemd i containere i lang tid. Tilbake i 2014 skrev vår sikkerhetsingeniør Daniel Walsh en artikkel Kjører systemd i en Docker Container, og et par år senere - en annen, som ble kalt Kjører systemd i en ikke-privilegert beholder, der han uttalte at situasjonen ikke hadde blitt mye bedre. Spesielt skrev han at "dessverre, selv to år senere, hvis du googler "Docker system", er det første som dukker opp den samme gamle artikkelen hans. Så det er på tide å endre noe." I tillegg har vi allerede snakket om konflikt mellom Docker og systemd utviklere.

Kjører systemd i en container

I denne artikkelen vil vi vise hva som har endret seg over tid og hvordan Podman kan hjelpe oss i denne saken.

Det er mange grunner til å kjøre systemd inne i en beholder, for eksempel:

  1. Multiservice containere – mange mennesker ønsker å trekke multitjenesteapplikasjonene sine ut av virtuelle maskiner og kjøre dem i containere. Det ville selvfølgelig være bedre å dele opp slike applikasjoner i mikrotjenester, men ikke alle vet hvordan man gjør dette ennå eller har rett og slett ikke tid. Derfor gir det perfekt mening å kjøre slike applikasjoner som tjenester lansert av systemd fra enhetsfiler.
  2. Systemd-enhetsfiler – De fleste applikasjoner som kjører inne i containere er bygget fra kode som tidligere kjørte på virtuelle eller fysiske maskiner. Disse applikasjonene har en enhetsfil som er skrevet for disse applikasjonene og forstår hvordan de skal startes. Så det er fortsatt bedre å starte tjenester ved å bruke støttede metoder, i stedet for å hacke din egen init-tjeneste.
  3. Systemd er prosessleder. Den administrerer tjenester (stenger ned, starter tjenester på nytt eller dreper zombieprosesser) bedre enn noe annet verktøy.

Når det er sagt, er det mange grunner til ikke å kjøre systemd i containere. Den viktigste er at systemd/journald kontrollerer produksjonen av containere, og verktøy som Kubernetes eller openshift forventer at containere skriver logg direkte til stdout og stderr. Derfor, hvis du skal administrere containere gjennom orkestreringsverktøy som de som er nevnt ovenfor, bør du seriøst vurdere å bruke systembaserte containere. I tillegg har Docker- og Moby-utviklere ofte vært sterkt imot å bruke systemd i containere.

The Coming of Podman

Vi er glade for å kunne rapportere at situasjonen endelig har beveget seg fremover. Teamet ansvarlig for å kjøre containere på Red Hat bestemte seg for å utvikle din egen containermotor. Han fikk et navn Podman og tilbyr samme kommandolinjegrensesnitt (CLI) som Docker. Og nesten alle Docker-kommandoer kan brukes i Podman på samme måte. Vi gjennomfører ofte seminarer, som nå heter Bytter Docker til Podman, og det aller første lysbildet krever skriving: alias docker=podman.

Mange mennesker gjør dette.

Min Podman og jeg er på ingen måte imot systembaserte containere. Tross alt er Systemd det mest brukte Linux init-undersystemet, og å ikke la det fungere ordentlig i containere betyr å ignorere hvordan tusenvis av mennesker er vant til å kjøre containere.

Podman vet hva han skal gjøre for å få systemd til å fungere ordentlig i en container. Den trenger ting som å montere tmpfs på /run og /tmp. Hun liker å ha det "containerized" miljøet aktivert og forventer skrivetillatelser til sin del av cgroup-katalogen og til /var/log/journald-mappen.

Når du starter en container der den første kommandoen er init eller systemd, konfigurerer Podman automatisk tmpfs og Cgroups for å sikre at systemd starter uten problemer. For å blokkere denne automatiske startmodusen, bruk --systemd=false-alternativet. Vær oppmerksom på at Podman bare bruker systemd-modus når den ser at den trenger å kjøre en systemd- eller init-kommando.

Her er et utdrag fra manualen:

mann podman kjøre
...

–systemd=true|false

Kjøre en container i systemd-modus. Aktivert som standard.

Hvis du kjører en systemd- eller init-kommando inne i en container, vil Podman konfigurere tmpfs-monteringspunkter i følgende kataloger:

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

Standard stoppsignal vil også være SIGRTMIN+3.

Alt dette lar systemd kjøre i en lukket beholder uten noen endringer.

MERK: systemd prøver å skrive til cgroup-filsystemet. Imidlertid forhindrer SELinux containere fra å gjøre dette som standard. For å aktivere skriving, aktiver den boolske parameteren container_manage_cgroup:

setsebool -P container_manage_cgroup true

Se nå på hvordan Dockerfile ser ut for å kjøre systemd i en container ved hjelp av Podman:

# cat Dockerfile

FROM fedora

RUN dnf -y install httpd; dnf clean all; systemctl enable httpd

EXPOSE 80

CMD [ "/sbin/init" ]

Det er alt.

Nå monterer vi beholderen:

# podman build -t systemd .

Vi ber SELinux å tillate systemd å endre Cgroups-konfigurasjonen:

# setsebool -P container_manage_cgroup true

Forresten, mange glemmer dette trinnet. Heldigvis trenger dette bare å gjøres én gang, og innstillingen lagres etter omstart av systemet.

Nå starter vi bare beholderen:

# 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 oppe og går:

$ curl localhost

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

…

</html>

MERK: Ikke prøv dette på Docker! Der må du fortsatt danse med en tamburin for å lansere slike beholdere gjennom demonen. (Ytterligere felt og pakker vil være nødvendig for å få alt til å fungere sømløst i Docker, eller det må kjøres i en privilegert container. For detaljer, se artikkel.)

Et par kule ting til om Podman og systemd

Podman fungerer bedre enn Docker i systemd-enhetsfiler

Hvis beholdere må startes når systemet starter opp, kan du ganske enkelt sette inn de riktige Podman-kommandoene i systemd-enhetsfilen, som vil starte tjenesten og overvåke den. Podman bruker standard gaffel-exec-modellen. Beholderprosesser er med andre ord barn av Podman-prosessen, så systemd kan enkelt overvåke dem.

Docker bruker en klient-server-modell, og Docker CLI-kommandoer kan også plasseres direkte i en enhetsfil. Imidlertid, når Docker-klienten kobles til Docker-demonen, blir den (klienten) bare en annen prosess som behandler stdin og stdout. Systemd har på sin side ingen anelse om forbindelsen mellom Docker-klienten og containeren som kjører under kontroll av Docker-demonen, og derfor, innenfor denne modellen, kan systemd fundamentalt sett ikke overvåke tjenesten.

Aktiverer systemd via socket

Podman håndterer aktivering via stikkontakt korrekt. Fordi Podman bruker gaffel-exec-modellen, kan den videresende sokkelen til sine underordnede beholderprosesser. Docker kan ikke gjøre dette fordi den bruker en klient-server-modell.

Varlink-tjenesten som Podman bruker for å kommunisere med eksterne klienter til containere, aktiveres faktisk via en socket. Cockpit-podman-pakken, skrevet i Node.js og en del av cockpitprosjektet, lar folk samhandle med Podman-beholdere gjennom et nettgrensesnitt. Webdemonen som kjører cockpit-podman sender meldinger til en varlink-kontakt som systemd lytter på. Systemd aktiverer deretter Podman-programmet for å motta meldinger og begynne å administrere containere. Aktivering av systemd over en socket eliminerer behovet for en konstant kjørende daemon når du implementerer eksterne APIer.

I tillegg utvikler vi en annen Podman-klient kalt podman-remote, som implementerer den samme Podman CLI men kaller varlink for å kjøre containere. Podman-remote kan kjøre på toppen av SSH-økter, slik at du kan samhandle sikkert med containere på forskjellige maskiner. Over tid planlegger vi å aktivere podman-remote for å støtte MacOS og Windows sammen med Linux, slik at utviklere på disse plattformene kan kjøre en virtuell Linux-maskin med Podman varlink kjørende og ha den fulle opplevelsen av at containere kjører på den lokale maskinen.

SD_NOTIFY

Systemd lar deg utsette lanseringen av hjelpetjenester til den containeriserte tjenesten de trenger starter. Podman kan videresende SD_NOTIFY-kontakten til den containeriserte tjenesten slik at tjenesten varsler systemd at den er klar til drift. Og igjen, Docker, som bruker en klient-server-modell, kan ikke gjøre dette.

I planene

Vi planlegger å legge til kommandoen podman generer systemd CONTAINERID, som vil generere en systemd enhetsfil for å administrere en spesifisert beholder. Dette skal fungere i både rot- og rotløs-modus for uprivilegerte beholdere. Vi har til og med sett en forespørsel om en OCI-kompatibel systemd-nspawn kjøretid.

Konklusjon

Å kjøre systemd i en container er et forståelig behov. Og takket være Podman har vi endelig en containerkjøringstid som ikke er i konflikt med systemd, men som gjør den enkel å bruke.

Kilde: www.habr.com

Legg til en kommentar