Od dłuższego czasu obserwujemy temat wykorzystania 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 się nie poprawiła. W szczególności pisał, że „niestety, nawet dwa lata później, jeśli wpiszesz w Google 'Docker system', jako pierwszy artykuł pojawia się jego stary tekst. Oznacza to, że czas na zmiany”. Ponadto, kiedyś opowiadaliśmy o .
W tym artykule pokażemy, co się zmieniło od tego czasu i jak Podman może nam w tym pomóc.
Istnieje wiele powodów, dla których warto uruchamiać systemd wewnątrz kontenera, takich jak:
- Kontejnery wieloserwisowe Wiele osób chce przenieść swoje aplikacje wielousługowe z maszyn wirtualnych do kontenerów. Oczywiście, najlepiej byłoby rozbić takie aplikacje na mikrousługi, ale nie wszyscy jeszcze umieją to robić lub po prostu brakuje na to czasu. Dlatego uruchamianie takich aplikacji jako usług systemd z plików jednostkowych ma sens.
- Pliki jednostkowe Systemd Większość aplikacji działających w kontenerach składa się z kodu, który wcześniej był uruchamiany na maszynach wirtualnych lub fizycznych. Takie aplikacje mają plik jednostkowy, który został napisany dla tych aplikacji i wie, jak je uruchomić. Zatem usługi najlepiej jest uruchamiać dzięki wspieranym metodom, zamiast łamać 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 wiele powodów, dla których nie powinno się uruchamiać systemd w kontenerach. Głównym powodem jest to, że systemd/journald kontroluje wyjście kontenerów, a narzędzia takie jak или zakładają, że kontenery będą pisać logi bezpośrednio do stdout i stderr. Dlatego, jeśli zamierzają Państwo zarządzać kontenerami za pomocą narzędzi orkiestracyjnych, jak opisano powyżej, warto poważnie rozważyć wykorzystanie kontenerów opartych na systemd. Ponadto, programiści Docker i Moby często byli zdecydowanymi przeciwnikami używania systemd w kontenerach.
Nadchodzi Podman
Z przyjemnością informujemy, że sytuacja w końcu ruszyła z miejsca. Zespół odpowiedzialny w Red Hat za uruchamianie kontenerów postanowił opracować . Otrzymał nazwę i oferuje ten sam interfejs wiersza poleceń (CLI), co Docker. Większość poleceń Docker można również używać w Podman. Często organizujemy warsztaty, które nazywają się , a pierwszy slajd wzywa do wpisania: alias docker=podman.
Wielu tak właśnie robi.
My, z naszym Podmanem, w żadnym wypadku nie jesteśmy przeciwni kontenerom opartym na systemd. W końcu systemd jest najczęściej używany jako podsystem init w Linuksie, a nie pozwolenie mu na normalne działanie w kontenerach oznacza ignorowanie tego, jak tysiące ludzi przyzwyczaiły się uruchamiać kontenery.
Podman wie, co trzeba zrobić, aby systemd działał prawidłowo 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.
Podczas uruchamiania kontenera, w którym pierwszą komendą jest init lub systemd, Podman automatycznie konfiguruje tmpfs i Cgroups, aby uruchomienie systemd przebiegało bez problemów. Aby zablokować ten automatyczny tryb uruchamiania, używa się opcji —systemd=false. Zauważ, że Podman używa trybu systemd tylko wtedy, gdy zauważa, że należy wykonać komendę systemd lub init.
Oto fragment z dokumentacji:
man podman run
…–systemd=true|false
Uruchomienie kontenera w trybie systemd. Domyślnie włączone.
Jeśli w kontenerze wykonywana jest komenda systemd lub init, Podman skonfiguruje punkty montowania tmpfs w następujących katalogach:
/run, /run/lock, /tmp, /sys/fs/cgroup/systemd, /var/lib/journal
Jako sygnał zatrzymania domyślnie będzie używany również SIGRTMIN+3.
To wszystko pozwala systemd działać w zamkniętym kontenerze bez jakichkolwiek modyfikacji.
UWAGA: systemd próbuje zapisać dane w systemie plików cgroup. Jednak SELinux domyślnie zabrania kontenerom tego robić. Aby zezwolić na zapis, włącz parametry logiczne container_manage_cgroup:
setsebool -P container_manage_cgroup true
Zobacz, jak wygląda Dockerfile do uruchamiania 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" ]
To wszystko.
Teraz budujemy kontener:
# podman build -t systemd .
Mówimy SELinuxowi, aby pozwolił systemd modyfikować konfigurację Cgroups:
# setsebool -P container_manage_cgroup true
Wiele osób o tym kroku zapomina. Na szczęście wystarczy to zrobić tylko raz, a konfiguracja zostanie zachowana 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.
Wszystko, usługa uruchomiona i działa:
$ curl localhost
<html xml_lang="en" lang="en">
…
</html>
UWAGA: Nie próbuj tego na Dockerze! Wciąż wymagane są sztuczki, aby uruchomić takie kontenery przez demona. (Będą potrzebne dodatkowe pola i pakiety, aby wszystko działało bezproblemowo w Dockerze, lub trzeba będzie uruchamiać w kontenerze z uprawnieniami. Szczegóły w .)
Jeszcze kilka fajnych rzeczy o Podman i systemd
Podman działa lepiej niż Docker w plikach jednostek systemd
Jeśli kontenery mają być uruchamiane podczas uruchamiania systemu, wystarczy wstawić odpowiednie polecenia Podman do pliku jednostki systemd, który uruchomi usługę i będzie ją monitorować. Podman wykorzystuje standardowy model fork-exec. Innymi słowy, procesy kontenerowe są podrzędne w stosunku do procesu Podmana, dlatego systemd łatwo może je monitorować.
Docker korzysta z modelu klient-serwer, a polecenia CLI Dockera również można umieszczać bezpośrednio w pliku jednostki. Jednak po nawiązaniu połączenia klienta Dockera z demonem Dockera, (klient) staje się po prostu kolejnym procesem obsługującym stdin i stdout. Systemd nie ma pojęcia o połączeniu między klientem Dockera a kontenerem działającym pod kontrolą demona Dockera, więc w ramach tego modelu systemd zasadniczo nie może monitorować usługi.
Aktywacja systemd przez gniazdo
Podman poprawnie obsługuje aktywację przez gniazdo. Ponieważ Podman korzysta z modelu fork-exec, może przekazywać gniazdo swoim podrzędnym procesom kontenerowym. Docker nie potrafi tego zrobić, ponieważ korzysta z modelu klient-serwer.
Usługa varlink, której Podman używa do komunikacji zdalnych klientów z kontenerami, jest aktywowana poprzez gniazdo. Pakiet cockpit-podman, napisany w Node.js i część projektu cockpit, pozwala użytkownikom na interakcję z kontenerami Podman za pośrednictwem interfejsu webowego. Demon webowy, na którym działa cockpit-podman, wysyła wiadomości do gniazda varlink, które jest monitorowane przez systemd. Następnie systemd uruchamia program Podman, aby odbierać wiadomości i zacząć zarządzać kontenerami. Aktywacja systemd poprzez gniazdo pozwala na zredukowanie potrzeby stałego działania demona w realizacji zdalnych interfejsów API.
Opracowujemy także innego klienta dla Podmana o nazwie podman-remote, który realizuje ten sam interfejs CLI Podmana, ale wywołuje varlink do uruchamiania kontenerów. Podman-remote może działać na sesjach SSH, co umożliwia bezpieczną interakcję z kontenerami na różnych maszynach. Z biegiem czasu planujemy wprowadzenie podman-remote dla systemów MacOS i Windows obok Linuksa, aby programiści na tych platformach mogli uruchomić wirtualną maszynę Linux z działającym Podmanem varlink i mieć pełne wrażenie, że kontenery działają na lokalnej maszynie.
SD_NOTIFY
Systemd pozwala opóźnić uruchomienie usług pomocniczych do momentu, w którym uruchomi się wymagany kontenerowy serwis. Podman może przekazać gniazdo SD_NOTIFY do kontenerowego serwisu, aby ten serwis powiadomił systemd o swoim gotowości do pracy. I znowu, Docker, korzystający z modelu klient-serwer, nie potrafi tego zrobić.
W planach
Planujemy dodać polecenie podman generate systemd CONTAINERID, które będzie generować plik jednostki systemd do zarządzania konkretnym kontenerem. Powinno to działać zarówno w trybie root, jak i w trybie bezuprawnieniowym dla kontenerów nieuprzywilejowanych. Zauważyliśmy nawet zapytania o stworzenie zgodnego ze standardem OCI środowiska wykonawczego systemd-nspawn.
Podsumowanie
Uruchamianie systemd w kontenerze to całkowicie zrozumiała potrzeba. Dzięki Podmanowi w końcu mamy środowisko uruchamiania kontenerów, które nie wchodzi w konflikt z systemd, a wręcz umożliwia jego łatwe wykorzystanie.
Źródło: habr.com
