Spouštíme systemd v kontejneru.

Sledujeme téma využívání systemd v kontejnerech už delší dobu. Již v roce 2014 náš bezpečnostní inženýr Daniel Walsh napsal článek Spuštění systemd v kontejnerech Docker, a o pár let později – další, který se jmenoval Spuštění systemd v neprávně privilegiovaném kontejneru, ve kterém konstatoval, že situace se příliš nezměnila. Konkrétně napsal, že "bohužel, i dva roky poté, pokud si vyhledáte 'Docker system', na prvním místě se znovu objeví jeho starý článek. Takže je na čase něco změnit". Kromě toho jsme už mluvili o konfliktu mezi vývojáři Docker a systemd.

Spouštíme systemd v kontejneru.

V tomto článku ukážeme, co se od té doby změnilo a jak nám může v této otázce pomoci Podman.

Existuje mnoho důvodů pro spuštění systemd uvnitř kontejneru, jako například:

  1. Mnohoslužbové kontejnery – mnozí chtějí vyvést své mnohoslužbové aplikace z virtuálních strojů a spouštět je v kontejnerech. Bylo by lepší tyto aplikace rozdělit na mikroservisy, ale ne každý to zatím umí nebo prostě na to nemá čas. Proto má smysl spouštět takové aplikace jako služby řízené pomocí systemd z jednotkových souborů.
  2. Jednotkové soubory Systemd – většina aplikací běžících v kontejnerech je sestavena z kódu, který byl dříve spouštěn na virtuálních nebo fyzických strojích. Tyto aplikace mají jednotkový soubor, který byl napsán pro tyto aplikace a ví, jak je spustit. Služby je tedy lepší spouštět pomocí podporovaných metod, než abychom se pokoušeli hackovat vlastní init službu.
  3. Systemd je správce procesů. Ovládá služby (ukončuje, restartuje služby nebo odstraňuje zombie procesy) lépe než jakýkoli jiný nástroj.

Existuje však i mnoho důvodů, proč systemd v kontejnerech nespouštět. Hlavní důvod spočívá v tom, že systemd/journald kontroluje výstup kontejnerů, a nástroje jako Kubernetes nebo OpenShift předpokládají, že kontejnery budou zapisovat logy přímo do stdout a stderr. Pokud tedy plánujete spravovat kontejnery pomocí orchestračních nástrojů uvedených výše, měli byste pečlivě zvážit otázku použití kontejnerů založených na systemd. Kromě toho byli vývojáři Docker a Moby často proti používání systemd v kontejnerech.

Příchod Podmana

S radostí oznamujeme, že se situace konečně pohnula z mrtvého bodu. Tým zodpovědný v Red Hat za spuštění kontejnerů se rozhodl vyvinout vlastní kontejnerový motor. Ten dostal název Podman a nabízí stejný příkazový řádek (CLI) jako Docker. A prakticky všechny příkazy Dockeru lze používat stejným způsobem v Podmanu. Často pořádáme semináře, které se nyní nazývají Změna Dockeru na Podman, a první slajd vyzývá k napsání: alias docker=podman.

Mnozí to tak také dělají.

My s naším Podmanem rozhodně nemáme nic proti kontejnerům založeným na systemd. Vždyť Systemd je často používán jako init podsystém Linuxu a neumožnit mu správně fungovat v kontejnerech znamená ignorovat způsob, jakým tisíce lidí běžně spouští kontejnery.

Podman ví, co je potřeba, aby systemd správně fungoval v kontejneru. Potřebuje věci, jako je montování tmpfs do /run a /tmp. Má rád, když je aktivní „kontejnerové“ prostředí, a očekává zápisová oprávnění do své části adresáře cgroup a do složky /var/log/journald.

Při spuštění kontejneru, kde je první příkaz init nebo systemd, Podman automaticky nastaví tmpfs a Cgroups, aby spuštění systemd proběhlo bez problémů. K blokování takového automatického režimu spuštění se používá volba —systemd=false. Všimněte si, že Podman používá režim systemd pouze tehdy, když vidí, že je potřeba provést příkaz systemd nebo init.

Zde je výňatek z manuálu:

man podman run
…

–systemd=true|false

Spuštění kontejneru v režimu systemd. Ve výchozím nastavení je zapnuto.

Pokud je uvnitř kontejneru spuštěn příkaz systemd nebo init, Podman nastaví body montování tmpfs v následujících adresářích:

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

Také jako signál pro zastavení se ve výchozím nastavení použije SIGRTMIN+3.

To vše umožňuje systemd fungovat v uzavřeném kontejneru bez jakýchkoli modifikací.

POZNÁMKA: systemd se pokouší provést zápis do souborového systému cgroup. Nicméně SELinux ve výchozím nastavení zakazuje kontejnerům to dělat. Aby bylo povoleno zapisování, aktivujte logickou volbu container_manage_cgroup:

setsebool -P container_manage_cgroup true

Nyní se podívejte, jak vypadá Dockerfile pro spuštění systemd v kontejneru při použití Podman:

# cat Dockerfile

FROM fedora

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

EXPOSE 80

CMD [ "/sbin/init" ]

A to je všechno.

Nyní vytváříme kontejner:

# podman build -t systemd .

Říkáme SELinuxu, aby povolil systemd modifikovat konfiguraci Cgroups:

# setsebool -P container_manage_cgroup true

Mnozí mimochodem zapomínají na tento krok. Naštěstí je třeba to udělat jen jednou a nastavení se po restartu systému uchová.

Nyní jednoduše spustíme kontejner:

# 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.

Hotovo, služba se spustila a funguje:

$ curl localhost

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

…

</html>

POZNÁMKA: Nepokoušejte se to opakovat na Dockeru! Tam stále potřebujete tance s bubnem, abyste spustili takové kontejnerové služby přes démona. (Budou potřeba další pole a balíčky, aby to všechno bezproblémově fungovalo v Dockeru, nebo je třeba spouštět v privilegovaném kontejneru. Podrobnosti viz článku.)

Ještě pár skvělých věcí o Podman a systemd

Podman funguje lépe než Docker v jednotkových souborech systemd

Pokud je potřeba spouštět kontejnery při spuštění systému, stačí do jednotkového souboru systemd vložit odpovídající příkazy Podman, ten spustí službu a bude ji monitorovat. Podman používá standardní model větvení během vykonávání (fork-exec). Jinými slovy, procesy kontejnerů jsou potomky procesu Podman, takže systemd je může snadno monitorovat.

Docker používá model klient-server a příkazy CLI Dockeru lze také umístit přímo do jednotkového souboru. Jakmile se však klient Dockeru připojí k démonu Dockeru, stává se (klient) pouze dalším procesem, který zpracovává stdin a stdout. Na oplátku nemá systemd ponětí o spojení mezi klientem Dockeru a kontejnerem, který běží pod správou démona Dockeru, a proto v rámci tohoto modelu systemd v zásadě nemůže monitorovat službu.

Aktivace systemd přes socket

Podman správně zpracovává aktivaci prostřednictvím socketu. Protože Podman používá model fork-exec, může předávat socket svým podřízeným kontejnerovým procesům. Docker to tak neumí, protože používá model klient-server.

Služba varlink, kterou Podman používá pro interakci vzdálených klientů s kontejnery, se ve skutečnosti aktivuje prostřednictvím socketu. Balík cockpit-podman, napsaný v Node.js a součást projektu cockpit, umožňuje lidem interagovat s kontejnery Podman prostřednictvím webového rozhraní. Webový démon, na kterém běží cockpit-podman, posílá zprávy na varlink-socket, který naslouchá systemd. Poté systemd aktivuje program Podman pro příjem zpráv a začátek správy kontejnerů. Aktivace systemd prostřednictvím socketu umožňuje obejít se bez stále běžícího démona při implementaci vzdálených API.

Kromě toho vyvíjíme dalšího klienta pro Podman nazvaného podman-remote, který implementuje stejný Podman CLI, ale volá varlink pro spuštění kontejnerů. Podman-remote může fungovat na vrcholu SSH seancí, což umožňuje bezpečnou interakci s kontejnery na různých strojích. V průběhu času plánujeme využít podman-remote pro podporu MacOS a Windows vedle Linuxu, aby vývojáři na těchto platformách mohli spouštět virtuální stroj Linux s běžícím Podman varlink a mít úplný pocit, že kontejnery běží na místním stroji.

SD_NOTIFY

Systemd umožňuje odložit spuštění pomocných služeb, dokud nezačne potřebná kontejnerizovaná služba. Podman může předat socket SD_NOTIFY do kontejnerizované služby, aby tato služba informovala systemd o své připravenosti k práci. A znovu Docker, používající model klient-server, takto neumí.

V plánech

Plánujeme přidat příkaz podman generate systemd CONTAINERID, který vygeneruje jednotkový soubor systemd pro správu konkrétního zadaného kontejneru. To by mělo fungovat jak v root-, tak v rootless-režimech pro neprivilegované kontejnery. Dokonce jsme viděli žádost o vytvoření OCI-kompatibilního prostředí pro spuštění systemd-nspawn.

Závěr

Spuštění systemd v kontejneru je zcela pochopitelná potřeba. A díky Podmanu máme konečně prostředí pro spuštění kontejnerů, které neodporuje systemd, ale umožňuje jeho snadné použití.

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster