Uruchamianie systemu w kontenerze

Temat wykorzystania systemd w kontenerach śledzimy już od dłuższego czasu. W 2014 roku nasz inżynier bezpieczeństwa Daniel Walsh napisał artykuł Uruchamianie systemu w kontenerze Docker, a kilka lat później - kolejny, który tzw Uruchamianie systemd w nieuprzywilejowanym kontenerze, w którym stwierdził, że sytuacja nie uległa znacznej poprawie. W szczególności napisał, że „niestety, nawet dwa lata później, jeśli wpiszesz w Google „system Docker”, pierwszą rzeczą, która się pojawi, jest ten sam stary artykuł. Czas więc coś zmienić.” Ponadto, już o tym rozmawialiśmy konflikt między programistami Dockera i systemd.

Uruchamianie systemu w kontenerze

W tym artykule pokażemy, co zmieniło się na przestrzeni czasu i jak Podman może nam pomóc w tej kwestii.

Istnieje wiele powodów, dla których warto uruchamiać systemd w kontenerze, na przykład:

  1. Kontenery wielousługowe – wiele osób chce wyciągać swoje aplikacje wielousługowe z maszyn wirtualnych i uruchamiać je w kontenerach. Lepiej byłoby oczywiście rozbić takie aplikacje na mikroserwisy, jednak nie każdy jeszcze wie jak to zrobić lub po prostu nie ma czasu. Dlatego uruchamianie takich aplikacji jak usług uruchamianych przez system z plików jednostkowych ma sens.
  2. Pliki jednostek systemowych – Większość aplikacji działających wewnątrz kontenerów jest zbudowana z kodu, który wcześniej działał na maszynach wirtualnych lub fizycznych. Aplikacje te mają plik jednostkowy napisany dla tych aplikacji i rozumiejący, w jaki sposób powinny być uruchamiane. Dlatego nadal lepiej jest uruchamiać usługi przy użyciu obsługiwanych metod, niż hakować własną usługę init.
  3. Systemd jest menedżerem procesów. Zarządza usługami (zamyka, uruchamia ponownie lub zabija procesy zombie) lepiej niż jakiekolwiek inne narzędzie.

To powiedziawszy, istnieje wiele powodów, aby nie uruchamiać systemd w kontenerach. Najważniejszym z nich jest to, że systemd/journald kontroluje dane wyjściowe kontenerów i narzędzi takich jak Kubernetes lub otwarta zmiana oczekuj, że kontenery będą zapisywać dzienniki bezpośrednio na stdout i stderr. Dlatego jeśli zamierzasz zarządzać kontenerami za pomocą narzędzi do orkiestracji, takich jak te wymienione powyżej, powinieneś poważnie rozważyć użycie kontenerów systemowych. Ponadto programiści Docker i Moby często stanowczo sprzeciwiali się używaniu systemd w kontenerach.

Przybycie Podmana

Z radością informujemy, że sytuacja w końcu uległa poprawie. Zespół odpowiedzialny za prowadzenie kontenerów w Red Hat zdecydował się na rozwój własny silnik kontenerowy. Dostał imię Podman i oferuje ten sam interfejs wiersza poleceń (CLI), co Docker. I prawie wszystkich poleceń Dockera można używać w Podmanie w ten sam sposób. Często prowadzimy seminaria, które obecnie nazywają się Zmiana Dockera na Podmana, a już pierwszy slajd wymaga napisania: alias docker=podman.

Wiele osób to robi.

Mój Podman i ja nie jesteśmy w żaden sposób przeciwni kontenerom opartym na systemach. W końcu Systemd jest najczęściej używanym podsystemem inicjującym Linuksa i uniemożliwienie mu prawidłowego działania w kontenerach oznacza ignorowanie przyzwyczajenia tysięcy ludzi do uruchamiania kontenerów.

Podman wie co zrobić, żeby systemd działał poprawnie w kontenerze. Potrzebuje takich rzeczy, jak montowanie tmpfs na /run i /tmp. Lubi mieć włączone środowisko „kontenerowe” i oczekuje uprawnień do zapisu w swojej części katalogu cgroup i folderze /var/log/journald.

Kiedy uruchamiasz kontener, którego pierwszym poleceniem jest init lub systemd, Podman automatycznie konfiguruje tmpfs i Cgroups, aby zapewnić, że systemd uruchomi się bez problemów. Aby zablokować ten tryb automatycznego uruchamiania, użyj opcji --systemd=false. Należy pamiętać, że Podman używa trybu systemowego tylko wtedy, gdy widzi, że musi uruchomić polecenie systemd lub init.

Oto fragment instrukcji:

biegnij podmanem
...

–systemd=prawda|fałsz

Uruchamianie kontenera w trybie systemowym. Domyślnie włączone.

Jeśli uruchomisz polecenie systemd lub init w kontenerze, Podman skonfiguruje punkty podłączenia tmpfs w następujących katalogach:

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

Również domyślnym sygnałem stopu będzie SIGRTMIN+3.

Wszystko to pozwala systemd działać w zamkniętym kontenerze bez żadnych modyfikacji.

UWAGA: systemd próbuje zapisać w systemie plików cgroup. Jednak SELinux domyślnie uniemożliwia kontenerom robienie tego. Aby włączyć zapis, włącz parametr boolowski Container_manage_cgroup:

setsebool -P grupa_zarządzania_kontenerami prawda

Teraz spójrz, jak wygląda plik Dockerfile do uruchamiania systemd w kontenerze za pomocą Podmana:

# cat Dockerfile

FROM fedora

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

EXPOSE 80

CMD [ "/sbin/init" ]

To wszystko.

Teraz montujemy pojemnik:

# podman build -t systemd .

Mówimy SELinuxowi, aby pozwolił systemdowi modyfikować konfigurację Cgroups:

# setsebool -P container_manage_cgroup true

Nawiasem mówiąc, wiele osób zapomina o tym kroku. Na szczęście wystarczy to zrobić tylko raz, a ustawienie zostanie zapisane po ponownym uruchomieniu systemu.

Teraz po prostu uruchamiamy kontener:

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

To wszystko, usługa jest uruchomiona i działa:

$ curl localhost

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

…

</html>

UWAGA: nie próbuj tego na Dockerze! Tam nadal musisz tańczyć z tamburynem, aby wystrzelić tego rodzaju pojemniki przez demona. (Aby to wszystko działało płynnie w Dockerze, wymagane będą dodatkowe pola i pakiety, w przeciwnym razie konieczne będzie uruchomienie w uprzywilejowanym kontenerze. Aby uzyskać szczegółowe informacje, zobacz Artykuł.)

Jeszcze kilka fajnych rzeczy na temat Podmana i systemd

Podman działa lepiej niż Docker w plikach jednostek systemowych

Jeśli kontenery muszą zostać uruchomione podczas uruchamiania systemu, możesz po prostu wstawić odpowiednie polecenia Podmana do pliku jednostki systemowej, co uruchomi usługę i będzie ją monitorować. Podman używa standardowego modelu fork-exec. Innymi słowy, procesy kontenerowe są dziećmi procesu Podmana, więc systemd może je łatwo monitorować.

Docker korzysta z modelu klient-serwer, a polecenia Docker CLI można również umieszczać bezpośrednio w pliku jednostkowym. Jednak gdy klient Dockera połączy się z demonem Dockera, stanie się on (klientem) kolejnym procesem przetwarzającym standardowe i standardowe wyjścia. Z kolei systemd nie ma pojęcia o połączeniu klienta Dockera z kontenerem działającym pod kontrolą demona Dockera i dlatego w ramach tego modelu systemd zasadniczo nie może monitorować usługi.

Aktywacja systemd przez gniazdo

Podman poprawnie obsługuje aktywację poprzez gniazdo. Ponieważ Podman używa modelu fork-exec, może przekazać gniazdo do swoich podrzędnych procesów kontenerowych. Docker nie może tego zrobić, ponieważ używa modelu klient-serwer.

Usługa varlink, której Podman używa do komunikacji ze zdalnymi klientami do kontenerów, jest w rzeczywistości aktywowana poprzez gniazdo. Pakiet Cockpit-Podman, napisany w Node.js i stanowiący część projektu Cockpit, umożliwia interakcję z kontenerami Podman za pośrednictwem interfejsu internetowego. Demon sieciowy uruchamiający kokpit-podman wysyła wiadomości do gniazda varlink, na którym nasłuchuje systemd. Następnie Systemd aktywuje program Podman, aby odbierać wiadomości i rozpocząć zarządzanie kontenerami. Aktywacja systemd przez gniazdo eliminuje potrzebę stale działającego demona podczas implementowania zdalnych interfejsów API.

Dodatkowo pracujemy nad innym klientem Podman o nazwie podman-remote, który implementuje ten sam interfejs CLI Podmana, ale wywołuje varlink do uruchamiania kontenerów. Podman-remote może działać na sesjach SSH, umożliwiając bezpieczną interakcję z kontenerami na różnych maszynach. Z czasem planujemy umożliwić podman-remote obsługę systemów MacOS i Windows obok Linuksa, tak aby programiści na tych platformach mogli uruchomić maszynę wirtualną z systemem Linux z uruchomionym Podman varlink i mieć pełne doświadczenie z tym, że kontenery działają na maszynie lokalnej.

SD_NOTIFY

Systemd umożliwia odroczenie uruchomienia usług pomocniczych do czasu uruchomienia wymaganej przez nie usługi kontenerowej. Podman może przekazać gniazdo SD_NOTIFY do usługi kontenerowej, dzięki czemu usługa powiadomi systemd, że jest gotowa do działania. I znowu Docker, który korzysta z modelu klient-serwer, nie może tego zrobić.

W planach

Planujemy dodać polecenie podman generate systemd CONTAINERID, które wygeneruje plik jednostki systemowej do zarządzania określonym określonym kontenerem. Powinno to działać zarówno w trybie root, jak i bez rootowania dla nieuprzywilejowanych kontenerów. Widzieliśmy nawet prośbę o środowisko wykonawcze systemd-nspawn kompatybilne z OCI.

wniosek

Uruchamianie systemd w kontenerze jest potrzebą zrozumiałą. A dzięki Podmanowi w końcu mamy środowisko wykonawcze kontenerów, które nie koliduje z systemd, ale czyni go łatwym w użyciu.

Źródło: www.habr.com

Dodaj komentarz