Od dawna obserwujemy temat użycia systemd w kontenerach. Już w 2014 roku nasz inżynier ds. bezpieczeństwa Daniel Walsh napisał artykuł , a kilka lat później – inny, zatytułowany , w którym stwierdził, że sytuacja nie bardzo się poprawiła. Zauważył, że „niestety, nawet dwa lata później, jeśli wpiszesz w Google «Docker system», to na pierwszym miejscu wyskakuje znów jego stary artykuł. To oznacza, że pora coś zmienić”. Ponadto, wspomnieliśmy już wcześniej o .
W tym artykule pokażemy, co się zmieniło od tego czasu i jak może nam w tym pomóc Podman.
Istnieje wiele powodów, dla których warto uruchamiać systemd w kontenerze, takich jak:
- Kontenery multiservice – wielu chce wydobyć swoje aplikacje multiservice z maszyn wirtualnych i uruchamiać je w kontenerach. Lepiej byłoby, oczywiście, podzielić te aplikacje na mikroserwisy, ale nie wszyscy potrafią to zrobić lub po prostu nie mają na to czasu. Dlatego uruchamianie takich aplikacji jako usług zarządzanych przez systemd z plików jednostki ma sens.
- Pliki jednostek Systemd – większość aplikacji działających w kontenerach składa się z kodu, który wcześniej działał na maszynach wirtualnych lub fizycznych. Te aplikacje mają plik jednostki, który był przygotowany dla tych aplikacji i wie, jak je uruchomić. Dlatego lepiej uruchamiać usługi za pomocą wspieranych metod, zamiast łamać swoją własną usługę init.
- Systemd to menedżer procesów. Zarządza usługami (kończy pracę, ponownie uruchamia usługi lub zabija procesy zombie) lepiej niż jakiekolwiek inne narzędzie.
Jednak istnieje również wiele powodów, dla których nie warto uruchamiać systemd w kontenerach. Głównym powodem jest to, że systemd/journald kontroluje wyjście kontenerów, podczas gdy narzędzia takie jak lub zakładają, że kontenery będą pisać logi bezpośrednio do stdout i stderr. Dlatego, jeśli zamierzasz zarządzać kontenerami za pomocą narzędzi orkiestracyjnych wymienionych powyżej, musisz poważnie przemyśleć kwestię użycia kontenerów opartych na systemd. Ponadto, deweloperzy Docker i Moby często byli stanowczo przeciwni używaniu systemd w kontenerach.
Przybycie Podmana
Z radością informujemy, że sytuacja w końcu ruszyła z martwego punktu. Zespół odpowiedzialny w Red Hat za uruchamianie kontenerów postanowił opracować . Otrzymał on nazwę i oferuje ten sam interfejs wiersza poleceń (CLI) co Docker. Praktycznie wszystkie polecenia Docker można również używać w Podmanie. Często organizujemy seminaria, które teraz nazywają się , a pierwszy slajd zachęca do wpisania: alias docker=podman.
Wielu tak właśnie robi.
My, używając Podmana, w żadnym wypadku nie jesteśmy przeciwni kontenerom opartym na systemd. W końcu systemd jest najczęściej używanym init-systemem w Linuxie, a brak normalnego działania w kontenerach oznacza ignorowanie tego, jak tysiące ludzi przyzwyczaiły się uruchamiać kontenery.
Podman wie, co zrobić, aby systemd działał poprawnie w kontenerze. Potrzebuje takich rzeczy jak montowanie tmpfs w /run i /tmp. Lubi, gdy środowisko 'kontenerowe' jest włączone i oczekuje praw do zapisu w swojej części katalogu cgroup oraz w folderze /var/log/journald.
Przy uruchamianiu kontenera, w którym pierwszym poleceniem jest init lub systemd, Podman automatycznie konfiguruje tmpfs i cgroups, aby uruchomienie systemd przebiegło bez problemów. Aby zablokować tryb automatycznego uruchamiania, używa się opcji --systemd=false. Zauważ, że Podman używa trybu systemd tylko wtedy, gdy widzi, że należy wykonać polecenie systemd lub init.
Oto fragment z podręcznika:
man podman run
…--systemd=true|false
Uruchomienie kontenera w trybie systemd. Domyślnie włączony.
Jeśli w kontenerze wykonywane jest polecenie systemd lub init, Podman skonfiguruje punkty montowania tmpfs w następujących katalogach:
/run, /run/lock, /tmp, /sys/fs/cgroup/systemd, /var/lib/journal
Domyślnie sygnałem zatrzymania będzie także SIGRTMIN+3.
To wszystko pozwala systemd działać w zamkniętym kontenerze bez jakichkolwiek modyfikacji.
UWAGA: systemd próbuje zapisać w systemie plików cgroup. Jednak SELinux domyślnie zabrania kontenerom tego robić. Aby zezwolić na zapis, włącz logiczny parametr container_manage_cgroup:
setsebool -P container_manage_cgroup true
Teraz zobacz, jak wygląda Dockerfile do uruchomienia systemd w kontenerze przy użyciu Podmana:
# cat Dockerfile
FROM fedora
RUN dnf -y install httpd; dnf clean all; systemctl enable httpd
EXPOSE 80
CMD [ "/sbin/init" ]
I to wszystko.
Teraz zbierz kontener:
# podman build -t systemd .
Mówimy SELinux, aby zezwolił systemd na modyfikację konfiguracji cgroups:
# setsebool -P container_manage_cgroup true
Wiele osób zapomina o tym kroku. Na szczęście wystarczy to zrobić tylko raz, a konfiguracja zostaje zapisana 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.
Gotowe, usługa uruchomiona i działa:
$ curl localhost
<html xml_lang="en" lang="en">
…
</html>
UWAGA: Nie próbujcie powtarzać tego na Dockerze! Nadal potrzebne są skomplikowane zabiegi, aby uruchomić tego rodzaju kontenery przez demona. (Będą potrzebne dodatkowe pola i pakiety, aby wszystko działało bezproblemowo w Dockerze, lub trzeba będzie uruchomić w kontenerze z uprawnieniami. Szczegóły w .)
Kilka fajnych rzeczy o Podmanie i systemd
Podman działa lepiej niż Docker w jednostkach systemd
Jeśli kontenery muszą być uruchamiane przy rozruchu systemu, wystarczy po prostu wstawić odpowiednie polecenia Podmana do pliku jednostki systemd, a ten uruchomi usługę i będzie ją monitorować. Podman używa standardowego modelu rozgałęzania przy wykonywaniu (fork-exec). Innymi słowy, procesy kontenerowe są procesami podrzędnymi względem procesu Podmana, więc systemd łatwo może je monitorować.
Docker używa modelu klient-serwer, a polecenia CLI Dockera można również umieszczać bezpośrednio w pliku jednostki. Jednak po tym jak klient Dockera łączy się z demonem Dockera, staje się po prostu kolejnym procesem, który przetwarza stdin i stdout. Z kolei systemd nie ma pojęcia o relacji między klientem Dockera a kontenerem działającym pod zarządem demona Dockera, dlatego w tym modelu systemd zasadniczo nie może monitorować usługi.
Aktywacja systemd przez gniazdo
Podman prawidłowo obsługuje aktywację przez gniazdo. Ponieważ Podman używa modelu fork-exec, może przekazywać gniazdo swoim podrzędnym procesom kontenerowym. Docker nie potrafi tego zrobić, ponieważ używa modelu klient-serwer.
Usługa varlink, którą Podman wykorzystuje do interakcji zdalnych klientów z kontenerami, tak naprawdę jest uruchamiana poprzez gniazdo. Pakiet cockpit-podman, napisany w Node.js i wchodzący w skład projektu cockpit, umożliwia użytkownikom interakcję z kontenerami Podman przez interfejs webowy. Demon webowy, na którym działa cockpit-podman, wysyła komunikaty do gniazda varlink, które jest nasłuchiwane przez systemd. Następnie systemd uruchamia program Podman, aby odbierać komunikaty i zacząć zarządzać kontenerami. Aktywacja systemd przez gniazdo umożliwia obejście konieczności posiadania stale działającego demona w realizacji zdalnych API.
Dodatkowo, opracowujemy innego klienta dla Podmana nazwanego podman-remote, który implementuje ten sam interfejs CLI Podman, ale wywołuje varlink do uruchamiania kontenerów. Podman-remote może działać w sesjach SSH, co pozwala na bezpieczną interakcję z kontenerami na różnych maszynach. Z czasem planujemy wprowadzić podman-remote do wsparcia MacOS i Windows obok Linuxa, aby deweloperzy na tych platformach mogli uruchomić maszynę wirtualną Linuxa z działającym Podman varlink i mieć pełne wrażenie, że kontenery działają na lokalnej maszynie.
SD_NOTIFY
Systemd pozwala opóźnić uruchamianie usług pomocniczych do momentu, aż wystartuje wymagany przez nie kontenerowy serwis. Podman może przepuścić gniazdo SD_NOTIFY do kontenerowego serwisu, aby ten serwis powiadomił systemd o gotowości do pracy. Ponownie, Docker, korzystający z modelu klient-serwer, nie potrafi tego zrobić.
Plany
Planujemy dodać polecenie podman generate systemd CONTAINERID, które będzie generować jednostkę systemd do zarządzania określonym kontenerem. Powinno to działać zarówno w trybie root-, jak i rootless dla nieuprzywilejowanych kontenerów. Nawet widzieliśmy zapytanie o stworzenie zgodnego z OCI środowiska wykonawczego systemd-nspawn.
Podsumowanie
Uruchomienie systemd w kontenerze to całkowicie zrozumiała potrzeba. Dzięki Podmanowi wreszcie mamy środowisko uruchomieniowe kontenerów, które nie jest w konflikcie z systemd, a wręcz ułatwia jego użycie.
Źródło: habr.com
