Kører systemd i en container

Vi har fulgt emnet med at bruge systemd i containere i lang tid. Tilbage i 2014 skrev vores sikkerhedsingeniør Daniel Walsh en artikel Kører systemd i en Docker Container, og et par år senere - en anden, som blev kaldt Kører systemd i en ikke-privilegeret container, hvori han udtalte, at situationen ikke var blevet meget bedre. Især skrev han, at "desværre, selv to år senere, hvis du googler "Docker system", er det første, der kommer op, hans samme gamle artikel. Så det er på tide at ændre noget." Derudover har vi allerede talt om konflikt mellem Docker og systemd udviklere.

Kører systemd i en container

I denne artikel vil vi vise, hvad der har ændret sig over tid, 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:

  1. Multiservice containere – mange mennesker ønsker at trække deres multi-service applikationer ud af virtuelle maskiner og køre dem i containere. Det ville selvfølgelig være bedre at opdele sådanne applikationer i mikrotjenester, men ikke alle ved, hvordan man gør dette endnu, eller har simpelthen ikke tid. Derfor giver det perfekt mening at køre sådanne applikationer som tjenester lanceret af systemd fra enhedsfiler.
  2. Systemd enhedsfiler – De fleste applikationer, der kører inde i containere, er bygget af kode, der tidligere kørte på virtuelle eller fysiske maskiner. Disse applikationer har en enhedsfil, der er skrevet til disse applikationer og forstår, hvordan de skal startes. Så det er stadig bedre at starte tjenester ved hjælp af understøttede metoder i stedet for at hacke din egen init-tjeneste.
  3. Systemd er procesleder. Det administrerer tjenester (lukker, genstarter tjenester eller dræber zombieprocesser) bedre end noget andet værktøj.

Når det er sagt, er der mange grunde til ikke at køre systemd i containere. Den vigtigste er, at systemd/journald styrer output af containere, og værktøjer som f.eks Kubernetes eller OpenShift forventer, at containere skriver log direkte til stdout og stderr. Derfor, hvis du skal administrere containere gennem orkestreringsværktøjer som dem, der er nævnt ovenfor, bør du seriøst overveje at bruge systembaserede containere. Derudover har Docker- og Moby-udviklere ofte været stærkt imod at bruge systemd i containere.

Podmans komme

Vi er glade for at kunne fortælle, at situationen endelig er kommet fremad. Teamet med ansvar for at køre containere hos Red Hat besluttede at udvikle sig din egen containermotor. Han fik et navn Podman og tilbyder den samme kommandolinjegrænseflade (CLI) som Docker. Og næsten alle Docker-kommandoer kan bruges i Podman på samme måde. Vi afholder ofte seminarer, som nu kaldes Skifter Docker til Podman, og det allerførste slide kalder på skrivning: alias docker=podman.

Mange mennesker gør dette.

Min Podman og jeg er på ingen måde imod systembaserede containere. Systemd er trods alt det mest almindeligt anvendte Linux init-undersystem, og at ikke tillade det at fungere korrekt i containere betyder at ignorere, hvordan tusindvis af mennesker er vant til at køre containere.

Podman ved, hvad han skal gøre for at få systemd til at fungere korrekt i en container. Det har brug for ting som at montere tmpfs på /run og /tmp. Hun kan lide at have det "containeriserede" miljø aktiveret og forventer skrivetilladelser til sin del af cgroup-mappen og til mappen /var/log/journald.

Når du starter en container, hvor den første kommando er init eller systemd, konfigurerer Podman automatisk tmpfs og Cgroups for at sikre, at systemd starter uden problemer. Brug indstillingen --systemd=false for at blokere denne automatiske starttilstand. Bemærk venligst, at Podman kun bruger systemd-tilstand, når den ser, at den skal køre en systemd- eller init-kommando.

Her er et uddrag fra manualen:

mand podman løb
...

–systemd=sand|falsk

Kørsel af en container i systemd-tilstand. Aktiveret som standard.

Hvis du kører en systemd- eller init-kommando inde i en container, konfigurerer Podman tmpfs-monteringspunkter i følgende mapper:

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

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

Alt dette gør det muligt for systemd at køre i en lukket beholder uden ændringer.

BEMÆRK: systemd forsøger at skrive til cgroup-filsystemet. SELinux forhindrer dog containere i at gøre dette som standard. For at aktivere skrivning skal du aktivere den booleske parameter container_manage_cgroup:

setsebool -P container_manage_cgroup sand

Se nu på, hvordan Dockerfilen ser ud til at køre 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 beholderen:

# podman build -t systemd .

Vi fortæller SELinux at tillade systemd at ændre Cgroups-konfigurationen:

# setsebool -P container_manage_cgroup true

Forresten glemmer mange mennesker dette trin. Heldigvis skal dette kun gøres én gang, og indstillingen gemmes efter genstart af systemet.

Nu 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 køre:

$ curl localhost

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

…

</html>

BEMÆRK: Prøv ikke dette på Docker! Der skal du stadig danse med en tamburin for at starte den slags beholdere gennem dæmonen. (Yderligere felter og pakker vil være påkrævet for at få det hele til at fungere problemfrit i Docker, eller det skal køres i en privilegeret container. For detaljer, se artiklen.)

Et par flere fede ting om Podman og systemd

Podman fungerer bedre end Docker i systemd enhedsfiler

Hvis containere skal startes, når systemet starter, kan du blot indsætte de relevante Podman-kommandoer i systemd-enhedsfilen, som starter tjenesten og overvåger den. Podman bruger standard gaffel-exec-modellen. Med andre ord er containerprocesser 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 en enhedsfil. Men når Docker-klienten opretter forbindelse til Docker-dæmonen, bliver den (klienten) blot endnu en proces, der behandler stdin og stdout. Til gengæld har systemd ingen idé om forbindelsen mellem Docker-klienten og containeren, der kører under kontrol af Docker-dæmonen, og derfor kan systemd i denne model grundlæggende ikke overvåge tjenesten.

Aktivering af systemd via socket

Podman håndterer aktivering via socket korrekt. Fordi Podman bruger fork-exec-modellen, kan den videresende soklen til sine underordnede containerprocesser. Docker kan ikke gøre dette, fordi det bruger en klient-server-model.

Varlink-tjenesten, som Podman bruger til at kommunikere med fjernklienter til containere, aktiveres faktisk via en socket. Cockpit-podman-pakken, skrevet i Node.js og en del af cockpitprojektet, giver folk mulighed for at interagere med Podman-containere gennem en webgrænseflade. Webdæmonen, der kører cockpit-podman, sender beskeder til en varlink-socket, som systemd lytter til. Systemd aktiverer derefter Podman-programmet for at modtage beskeder og begynde at administrere containere. Aktivering af systemd over en socket eliminerer behovet for en konstant kørende dæmon, når du implementerer eksterne API'er.

Derudover er vi ved at udvikle en anden Podman-klient kaldet podman-remote, som implementerer den samme Podman CLI, men kalder varlink for at køre containere. Podman-remote kan køre oven på SSH-sessioner, hvilket giver dig mulighed for sikkert at interagere med containere på forskellige maskiner. Med tiden planlægger vi at aktivere podman-remote til at understøtte MacOS og Windows sammen med Linux, så udviklere på disse platforme kan køre en virtuel Linux-maskine med Podman varlink kørende og få den fulde oplevelse af, at containere kører på den lokale maskine.

SD_NOTIFY

Systemd giver dig mulighed for at udskyde lanceringen af ​​hjælpetjenester, indtil den containerservice, de har brug for, starter. Podman kan videresende SD_NOTIFY-socket til den containeriserede tjeneste, så tjenesten meddeler systemd, at den er klar til drift. Og igen, Docker, som bruger en klient-server-model, kan ikke gøre dette.

I planerne

Vi planlægger at tilføje kommandoen podman generer systemd CONTAINERID, som vil generere en systemd enhedsfil til at administrere en bestemt container specificeret. Dette bør fungere i både rod- og rodløse tilstande for uprivilegerede containere. Vi har endda set en anmodning om en OCI-kompatibel systemd-nspawn runtime.

Konklusion

At køre systemd i en container er et forståeligt behov. Og takket være Podman har vi endelig en container-runtime, der ikke er i konflikt med systemd, men som gør den nem at bruge.

Kilde: www.habr.com

Tilføj en kommentar