Systemd bez ściemy: kombajn, który przejął Linuksa (czy tego chcesz, czy nie)

czarnaowca.it 22 godzin temu

www.czarnaowca.it

Jeśli siedzisz w Linuksie dłużej niż kilka lat, na pewno pamiętasz jedną z największych świętych wojen w historii open source. Kiedy systemd wchodziło na salony i zaczynało wypychać starego, poczciwego SysVinita z kolejnych dystrybucji, fora zapłonęły. Krzyczano o zdradzie filozofii Uniksa („rób jedną rzecz i rób ją dobrze”), o binarnym potworze, który pożera system od środka, a Lennart Poettering stał się dla części społeczności wrogiem publicznym numer jeden.

Kurz jednak opadł, minęła ponad dekada i rzeczywistość zweryfikowała wszystko. Dziś systemd jest absolutnym standardem na większości serwerów i desktopów — od Debiana i Ubuntu, przez RHEL-owate, aż po Archa. I szczerze? Jako ktoś, kto pamięta debugowanie kilkusetlinijkowych skryptów startowych w Bashu, w których brak jednej spacji potrafił położyć usługę na produkcji, wcale za starymi czasami nie tęsknię.

Rozłóżmy ten kombajn na części pierwsze: czym tak naprawdę jest, gdzie trzyma swoje graty, jak go używać na co dzień i co masz do wyboru, jeżeli mimo wszystko chcesz iść pod prąd.

Czym adekwatnie jest systemd?

W największym skrócie: to menedżer systemu i usług, który startuje jako pierwszy proces w przestrzeni użytkownika — słynny PID 1. Kiedy jądro Linuksa (kernel) ogarnie już sprzęt i zamontuje główny system plików, przekazuje pałeczkę właśnie jemu. Zadaniem PID 1 jest podniesienie całej reszty systemu i pilnowanie, żeby to wszystko nie rozpadło się w trakcie działania.

Stare systemy init (jak SysVinit) działały boleśnie liniowo. Skrypty odpalały się jeden po drugim w kolejności alfabetycznej (stąd te wszystkie potworki w stylu S01costam, S02cosinnego). jeżeli baza danych startowała wolno, cały proces bootowania czekał. Co gorsza, śledzenie procesów opierało się na plikach .pid. jeżeli proces potomny zrobił tzw. double-fork (standardowa sztuczka demonów w Uniksie), stary init tracił nad nim kontrolę. Chciałeś ubić usługę? Cóż, główny proces ginął, a pięć sierot wisiało w tle i dalej trzymało port.

Systemd podeszło do tematu zupełnie inaczej, podglądając sporo rozwiązań z macOS-owego launchd oraz solarisowego SMF:

  • Równoległy start i graf zależności — usługi opisujesz deklaratywnie w prostych plikach INI-podobnych. Mówisz systemowi: „ta aplikacja potrzebuje sieci i bazy danych”. Systemd samo buduje drzewo zależności i odpala wszystko, co się da, równolegle.
  • Cgroups (Control Groups) — zamiast wierzyć na słowo plikom tekstowym z numerem PID, systemd zamyka każdą usługę w osobnej grupie kontrolnej jądra (cgroup). choćby jeżeli proces rozwidli się pięćdziesiąt razy, przez cały czas siedzi w tej samej klatce. Kiedy wydajesz polecenie stop, systemd bezlitośnie czyści całą grupę. Żaden proces-zombie się nie wywinie.
  • Aktywacja gniazd (Socket Activation) — systemd może samo otworzyć port sieciowy lub gniazdo uniksowe i nasłuchiwać na nim ruchu. Sama usługa (np. demon SSH albo kontener) choćby nie musi działać w tle — zostanie odpalona dopiero w ułamku sekundy, gdy faktycznie przyjdzie pierwszy pakiet.

Ekosystem, czyli macki ośmiornicy

Powód, dla którego puryści tak bardzo nienawidzą systemd, leży w nazwie. To nie jest pojedynczy program, tylko cały zestaw narzędzi, które przejęły zarządzanie prawie każdym aspektem współczesnego Linuksa. Kiedy instalujesz systemd, w pakiecie dostajesz całą świtę demonów:

  • systemd-journald — centralny system logowania. Zrywa z tradycyjnymi plikami tekstowymi w /var/log/ na rzecz plików binarnych. Brzmi jak herezja (bo nie przelecisz pliku bezpośrednio grepem), ale w zamian dostajesz zindeksowane logi z metadanymi. Możesz jednym poleceniem wyciągnąć logi konkretnej usługi z przedziału czasowego między 14:00 a 14:15 z przedwczorajszego uruchomienia systemu, przefiltrowane tylko po błędach krytycznych.
  • systemd-networkd oraz systemd-resolved — narzędzia do konfiguracji sieci i lokalny resolver DNS (tak, to ten kolega, który nasłuchuje na 127.0.0.53:53 i czasem przyprawia o ból głowy, gdy stawiasz własnego Dnsmasqa albo Pi-hole’a bez zmiany konfiguracji).
  • systemd-timers — bezpośredni konkurent starego, dobrego crona. Timery to po prostu jednostki, które odpalają odpowiadające im pliki .service. Mają ogromną przewagę nad cronem: ich wyjście z automatu wpada do journala, mogą zależeć od innych usług (np. odpal backup dopiero, gdy zamontuje się zasób sieciowy), a jeżeli serwer był wyłączony w momencie planowanego zadania, timer z flagą Persistent=true nadrobi zaległości zaraz po starcie.
  • systemd-logind — zarządza sesjami użytkowników, obsługuje przycisk zasilania, zamykanie klapy laptopa i przydzielanie uprawnień do urządzeń bez konieczności siedzenia na koncie roota.
  • systemd-udevd — zarządza urządzeniami w /dev/, ładuje moduły jądra przy podpięciu sprzętu i ustawia reguły dostępu (dawny samodzielny projekt udev został wchłonięty lata temu).
  • systemd-timesyncd — lekki klient NTP. Nie zastąpi pełnego serwera czasu, ale do utrzymania zegara w ryzach na zwykłej maszynie wystarcza w zupełności.
  • systemd-boot — prosty, piekielnie szybki bootloader dla systemów UEFI, stanowiący świetną alternatywę dla przeładowanego GRUB-a.
  • systemd-nspawn — często nazywany „chrootem na sterydach”. Pozwala odpalać lekkie kontenery systemowe bez używania Dockera czy LXC.

I to przez cały czas nie wszystko, bo w ekosystemie siedzą jeszcze rzeczy takie jak systemd-homed (przenośne katalogi domowe), systemd-cryptsetup (obsługa LUKS) czy systemd-oomd (ubijanie procesów przy braku RAM-u w przestrzeni użytkownika).

Typy jednostek (Units) i gdzie to wszystko siedzi

Dla systemd wszystko jest tzw. jednostką (unit). Typ jednostki rozpoznasz po rozszerzeniu pliku konfiguracyjnego:

  • .service — klasyczna usługa/demon (np. nginx.service, postgresql.service).
  • .socket — gniazdo sieciowe lub IPC do aktywacji usług na żądanie.
  • .timer — harmonogram zadań (odpala powiązany plik .service).
  • .mount oraz .automount — punkty montowania (systemd w tle tłumaczy sobie tradycyjny plik /etc/fstab właśnie na jednostki .mount).
  • .target — grupa jednostek, odpowiednik dawnych runleveli (np. multi-user.target to system w trybie tekstowym z siecią, a graphical.target odpala środowisko graficzne).
  • .slice — jednostka służąca do grupowania zasobów i nakładania limitów CPU/RAM dla całych zestawów usług lub użytkowników.

Święta trójca katalogów konfiguracyjnych

Konfiguracja jest podzielona na trzy główne lokalizacje, które mają ścisłą hierarchię ważności (od najniższej do najwyższej):

  1. /usr/lib/systemd/system/ (w starszych układach też /lib/systemd/system/)Tutaj lądują pliki dostarczane przez opiekunów pakietów w Twojej dystrybucji, kiedy robisz apt install albo pacman -S. Złota zasada: nigdy nie edytuj plików w tym katalogu z palca. Przy pierwszej lepszej aktualizacji pakietu Twoje zmiany pójdą w kosmos.
  2. /run/systemd/system/Jednostki wygenerowane dynamicznie w trakcie działania systemu (w RAM-ie). Znikają po restarcie.
  3. /etc/systemd/system/Królestwo administratora. Wszystko, co wrzucisz tutaj, ma najwyższy priorytet i nadpisuje pliki z /usr/lib/. To tutaj tworzysz własne usługi i tutaj lądują dowiązania symboliczne (symlinki), gdy włączasz usługę przy starcie systemu.

Jak modyfikować usługi jak człowiek, a nie jak jaskiniowiec?

Częsty błąd: ktoś chce zmienić jedną flagę w usłudze systemowej, więc kopiuje cały plik z /usr/lib/systemd/system/usluga.service do /etc/systemd/system/ i tam go edytuje. Działa? Działa. Problem pojawia się rok później, gdy aktualizacja dystrybucji zmienia architekturę usługi w /usr/lib/, a Twój skopiowany plik w /etc/ całkowicie ją przysłania i usługa przestaje wstawać.

Zamiast tego używa się tzw. drop-in files (nakładek). Klepiesz w terminalu:

systemctl edit nginx.service

Systemd automatycznie utworzy katalog /etc/systemd/system/nginx.service.d/ i otworzy w edytorze pusty plik override.conf. Wpisujesz tam tylko to, co chcesz zmienić (np. limit pamięci albo zmienną środowiskową). Reszta konfiguracji jest bezpiecznie dziedziczona z pliku paczkowego. jeżeli mimo wszystko musisz podejrzeć lub nadpisać absolutnie cały plik, używasz flagi --full.

Mięso, czyli komendy z codziennej pracy

Poniżej zestaw narzędzi, które załatwiają 95% codziennej roboty przy serwerach.

Zarządzanie usługami (systemctl)

W najnowszych wersjach nie musisz choćby dopisywać końcówki .service — systemd domyśli się, o co chodzi.

# Podstawy: uruchomienie, zatrzymanie, restart systemctl start nginx systemctl stop nginx systemctl restart nginx # Przeładowanie samej konfiguracji bez ubijania procesu (jeśli usługa to wspiera) systemctl reload nginx # Włączenie usługi przy starcie systemu + odpalenie jej od razu (oszczędza klepania dwóch komend) systemctl enable --now nginx # Wyłączenie autostartu i zatrzymanie usługi w jednym kroku systemctl disable --now nginx # Szybki podgląd statusu, PID-ów, zużycia pamięci i ostatnich linijek logów systemctl status nginx # Przeładowanie konfiguracji samego systemd (obowiązkowe po manualnej edycji plików .service!) systemctl daemon-reload

Gdy coś pójdzie nie tak albo chcesz zrobić porządek:

# Pokaż wszystkie usługi, które wyłożyły się przy starcie lub w trakcie pracy systemctl --failed # Lista wszystkich aktywnych usług w systemie systemctl list-units --type=service --state=running # Lista aktywnych timerów (widać kiedy ostatnio ruszyły i kiedy ruszą ponownie) systemctl list-timers # Zablokowanie usługi na amen (tworzy symlink do /dev/null — choćby inna usługa ani manualne 'start' jej nie podniesie) systemctl mask cups systemctl unmask cups # Podgląd ostatecznej konfiguracji usługi (po sklejeniu pliku bazowego i wszystkich override'ów) systemctl cat nginx

Przekopywanie logów (journalctl)

Koniec z zastanawianiem się, czy dana aplikacja pluje błędami do /var/log/syslog, /var/log/messages czy własnego podkatalogu.

# Logi konkretnej usługi (-u) z podglądem na żywo (-f, działa jak tail -f) journalctl -u nginx -f # Skok od razu na sam koniec logów z rozwinięciem dodatkowych informacji o błędach journalctl -xeu nginx # Logi z konkretnego przedziału czasowego journalctl -u postgresql --since "2026-10-20 12:00:00" --until "1 hour ago" # Pokaż wyłącznie błędy (priorytet err i wyższe: crit, alert, emerg) journalctl -p err -b # Logi z poprzedniego uruchomienia systemu (zbawienne, gdy serwer zaliczył twardy reset) journalctl -b -1 # Logi samego jądra (odpowiednik dmesg) journalctl -k # Odchudzanie logów: zostaw tylko ostatnie 500 MB albo logi z ostatnich 7 dni journalctl --vacuum-size=500M journalctl --vacuum-time=7d

Diagnostyka i wydajność (systemd-analyze)

Gdy system wstaje podejrzanie długo albo piszesz własny plik .service i chcesz sprawdzić, czy nie narobiłeś w nim literówek:

# Podsumowanie czasu startu (firmware + loader + kernel + userspace) systemd-analyze # Lista usług posortowana od tej, która najbardziej opóźniła start systemu systemd-analyze blame # Drzewo ścieżki krytycznej (pokazuje co na co czekało podczas bootowania) systemd-analyze critical-chain # Walidacja składni własnego pliku jednostki systemd-analyze verify /etc/systemd/system/moja-apka.service # Audyt bezpieczeństwa usług (ocenia jak bardzo otwarta na ataki jest konfiguracja danej usługi) systemd-analyze security nginx.service

Alternatywy — dla tych, co wolą prostotę

Mimo iż systemd wygrało rynek, świat Linuksa przez cały czas daje wybór. Istnieją dystrybucje (oraz zastosowania, takie jak lekkie kontenery czy systemy wbudowane), w których wielki kombajn jest po prostu zbędny. Co mamy na drugiej szali?

1. OpenRC

Najpopularniejsza, klasyczna alternatywa, wywodząca się z Gentoo i używana domyślnie m.in. w Alpine Linux (dlatego tak często spotkasz ją w obrazach dockerowych) oraz jako opcja w Artixie czy Devuanie.

Technicznie rzecz biorąc, OpenRC nie jest choćby samym procesem PID 1 — to system zarządzania usługami, który współpracuje z prostym procesem init (zazwyczaj tym z sysvinit lub busybox). Korzysta ze skryptów powłoki, ale robi to w cywilizowany sposób: obsługuje zależności, równoległy start i cgroups, nie próbując przy tym przejmować kontroli nad Twoim DNS-em i zegarem systemowym.

2. runit

Domyślny system init w Void Linux (dostępny też w Artixie i antyX). Prawdziwy majstersztyk minimalizmu. Cały kod źródłowy jest malutki, prosty jak budowa cepa i robi dokładnie dwie rzeczy: startuje system oraz pilnuje procesów (supervision).

Jeśli usługa padnie, runit podnosi ją natychmiast. Konfiguracja usługi to dosłownie kilkulinijkowy skrypt wykonywalny run. Dzięki temu Void Linux ze skonfigurowanym runit potrafi wstać do pulpitu szybciej, niż monitor zdąży wybudzić się ze stanu czuwania.

3. s6 (oraz s6-rc)

Bardzo ceniony w świecie kontenerów i wśród hardkorowych sysadminów zestaw narzędzi stworzony przez Laurenta Bercota. Składa się z małych, niezależnych binarek, które ściśle realizują filozofię Uniksa. Zapewnia pancerny nadzór nad procesami (bez polegania na plikach PID) oraz błyskawiczne potoki logowania (s6-log). Próg wejścia jest wyższy niż w przypadku runit czy systemd, ale stabilność i przewidywalność stoją na najwyższym poziomie.

4. Dinit

Stosunkowo nowy, nowoczesny gracz napisany w C++, który napędza m.in. Chimera Linux. Łączy w sobie dobre pomysły z systemd (prawdziwe zarządzanie zależnościami, deklaratywne pliki konfiguracyjne zamiast skryptów Basha, obsługa usług użytkownika) z lekkością i modularnością runit. Nie wpycha się w zarządzanie siecią czy logami binarnymi — robi wyłącznie to, co do menedżera usług należy.

5. SysVinit

Dziadek, od którego wszystko się zaczęło. Spotkasz go jeszcze w Devuanie czy Slackware. Dziś to już głównie ciekawostka historyczna lub wybór dla ludzi, którzy z powodów ideologicznych nie chcą niczego nowszego. Brak natywnego nadzoru nad procesami, brak prawdziwych zależności i opieranie wszystkiego na tasiemcach w Bashu sprawiają, iż na nowoczesnej produkcji trudno znaleźć dla niego racjonalne uzasadnienie.

Prawda o systemd jest dość prozaiczna: nie musisz kochać każdego modułu, który deweloperzy Red Hata próbują do niego wcisnąć. Sam często wyłączam systemd-resolved, gdy wchodzi mi w paradę, i wcale nie uważam, iż system init powinien zarządzać partycjami czy kontami użytkowników. Ale sam rdzeń — czyli zarządzanie usługami przez systemctl, pisanie prostych plików .service w pięć minut zamiast klepania skryptów startowych przez pół dnia oraz centralne logi w journalctl — ustandaryzował pracę z Linuksem jak nic innego wcześniej. Wchodzisz na serwer z Debianem, Fedorą czy Archem i od razu jesteś w domu. A w codziennej robocie z infrastrukturą to właśnie ta przewidywalność oszczędza najwięcej nerwów.

Idź do oryginalnego materiału