Moim celem jest stworzenie PRAKTYCZNEGO podręcznika skierowanego do administratorów.
Wstęp
Uwagi na temat użytego języka:
- nie chcę tłumaczyć angielskich nazw własnych na język polski, bo nie pomaga to w zrozumieniu przedmiotu
- jest to tekst skierowany do adminów, którzy na co dzień czytają dokumentacje po angielsku - oni mi wybaczą
- czy to jest normalne aby angielskie słowa odmieniać przez polskie przypadki - niestety tak :)
Co to jest systemd?
- wikipedia
- menadżer systemu i usług
- zastępuje rozwiązania takie jak: SysVinit, upstart
- podstawową jednostką organizacyjną jest "unit"
- w unitach można zdefiniować zależności między nimi
Mówiąć o systemach Unix/Linux zwykło się twierdzić, że "wszystko jest plikiem". Myśląc o systemd możemy myśleć, że "wszystko jest unitem".
Skąd się biorą te unity?
- z pakietów/paczek (rpm, deb, ...)
- unity mogą być utworzone/modyfikowane przez administratora
- unity mogą być utworzone/modyfikowane przez użytkowników
- unity również generowane są dynamicznie (generatory)
Jakie dystrybucje używają systemd?
Praktycznie większość: Arch Linux, Fedora, Debian, Ubuntu itd. W opozycji do nich trwają: Gentoo i Slackware. Systemd jest obecny w dwóch najważniejszych dystrybucjach klasy "enterprise": RHEL7 i SLES12.
Notacja
Jeśli używam nawiasów '[opcja]' znaczy, opcja ta może ale nie musi występować - jest opcjonalna. Czyli w poniższym poleceniu
# systemctl [list-units]
mogę, ale nie muszę użyć opcji "list-units".
Jeśli używam '{opcja_1|opcja_2|opcja_3}', to dokładnie jedna ze zbioru opcji MUSI wystąpić. Czyli w poniższym poleceniu
# systemd-tmpfiles {--clean|--create|--remove} /path/to/filename.conf
oznacza, że musisz użyć jednej z opcji: "--clean", "--create", "--remove":
# systemd-tmpfiles --clean /path/to/filename.conf
# systemd-tmpfiles --create /path/to/filename.conf
# systemd-tmpfiles --remove /path/to/filename.conf
Wersje
Różne wersje systemd w różnych dystrybucjach, czyli różna funkcjonalność.
Wersje serwerowe (RHEL7, SLES12) zawierają starsze wersje i pewnie część funkcjonalności, omawiana w tym poradniku, będzie niedostępna. W dystrybucjach bardziej "desktopowych": Arch Linux, Fedora - systemd powinien być bardziej na czasie...
Źródła
Lennart Poettering Blog
freedesktop.org
Arch Linux Wiki
Digital Ocean
YouTube
Structural and semantic deficiencies in the systemd architecture for r...
A history of modern init systems (1992-2015)
Unity
Wszystkie procesy działające w systemie są procesami potomnymi "systemd init process". (PID=1)
$ ps -q 1 -o pid,comm,command
PID COMMAND COMMAND
1 systemd /sbin/init
Ten fakt ma duże znaczenie dla administratorów, gdyż działanie całego systemu zależy od tego, jak działa systemd.
Wstęp
Lokalizacje: (man systemd.unit)
/etc/systemd/system/*
/run/systemd/system/*
/usr/lib/systemd/system/*
$XDG_CONFIG_HOME/systemd/user/*
$HOME/.config/systemd/user/*
/etc/systemd/user/*
/run/systemd/user/*
/usr/lib/systemd/user/*
- pliki konfiguracyjne unitów "systemowych" - pochodzące z pakietów instalacyjnych - znajdują się tu: /usr/lib/systemd/system/
- jeśli chcesz zmodyfikować unit z /usr/lib/systemd/system/, to ... zostaw go w spokoju. Zamiast tego utwórz nowy w /etc/systemd/system/
- jeśli chcesz utworzyć własny "systemowy" unit, umieść go tu: /etc/systemd/system/
- konfiguracja globalna użytkowników (pochodząca z pakietów): /usr/lib/systemd/user/
- konfiguracja globalna użytkowników (modyfikacja tych z pakietów i własna twórczość): /etc/systemd/user/
- konfiguracja indywidualna użytkownika: $HOME/.config/systemd/user/
Nie modyfikuj plików unitów z /usr.
Zawsze plik unitu z /etc ma pierwszeństwo przed tym z /usr.
Rodzaje unitów
- timer - aktywacja zadań oparta o czas (man systemd.timer)
- service - coś jak "stare" serwisy/usługi (man systemd.service)
- socket - nasłuchiwanie na danym porcie zamiast uruchamianie serwisu. Usługa zostanie uruchomiona po podłączeniu się klienta - coś jak "xinetd"
- target - trochę, jak runlevele, ale tylko trochę (man systemd.target). Target grupuje unity w logiczną funkcjonalność; można aktywować wiele targetów w tym samym czasie, ale jeden ustawiamy jako domyślny.
- path - monitorowanie ścieżki w celu aktywacji jakiegoś zadania (man systemd.path)
- scope - grupa procesów. Sesje użytkowników, kontenery, wirtualne maszyny są pogrupowanie w "scope'y" (man systemd.scope)
- slice - hierarchicznie pogrupowane unity "scope" i "service" (man systemd.slice). Jest to sposób na "partycjonowanie" dostępnych zasobów. Domyślnie cały system ("root slice") jest podzielony na trzy partycje:
- system (usługi systemowe)
- machine (maszyny wirtualne i kontenery)
- user (sesje użytkowników)
- automount - auto montowanie filesystemów (man systemd.automount) takich jak: /proc i /sys
- mount - montowanie filesystemów (man systemd.mount) takich jak: /boot, swap, /tmp
- snapshot - snapshoty nie są konfigurowane przez pliki. Są dynamicznie (systemctl snapshot) zapisywanym stanem procesów. (man systemd.snapshot)
- device - pliki urządzeń (man systemd.device)
- busname - (tylko gdy system używa "kdbus" ten typ ma zastosowanie) Kdbus ma w przyszłości zastąpić D-Bus. Systemd ma generator, który na podstawie klasycznej aktywacji szyny dbus1 generuje unitu typu "service" i "busname". Serwis "busname" działa "podobnie" jak "socket" - czeka na próbę aktywacji szyny "po nazwie" i uruchamia usługę "service", przypisaną do tej szyny.
Service / Podstawowe polecenia
Na przykładzie unitów typu "service" - usług/serwisów - poznamy podstawowe polecenia przydatne w codziennej pracy administratora.
Wylistowanie typów unitów:
# systemctl -t help
"Standardowe" opcje unitów (trochę jak stare polecenie "service"):
# systemctl {start|stop|status|restart|reload} name.type
Permanentne włączanie i wyłączanie - trochę podobne do "chkconfig on/off":
# systemctl {enable|disable} name.type
Kombinacja disable-enable:
# systemctl reenable name.type
Domyślny typ unitu, to "service".
Zatem dwa poniższe polecenia są równoważne:
# systemctl start sshd.service
# systemctl start sshd
Sprawdzenie statusu unitu:
# systemctl status sshd
* sshd.service - OpenSSH Daemon
Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: disabled)
Active: active (running) since Thu 2015-10-01 14:17:59 CEST; 1min 12s ago
Main PID: 29299 (sshd)
CGroup: /system.slice/sshd.service
`-29299 /usr/bin/sshd -D
Oct 01 14:17:59 archer.local systemd[1]: Started OpenSSH Daemon.
Oct 01 14:17:59 archer.local sshd[29299]: Server listening on 0.0.0.0 port 22.
Oct 01 14:17:59 archer.local sshd[29299]: Server listening on :: port 22.
Oct 01 14:18:33 archer.local systemd[1]: Started OpenSSH Daemon.
"Loaded":
- loaded - plik unitu znaleziony i używany- dodatkowo: plik źródłowy unitu, stan po restarcie (enable/disable/static), predefiniowany stan po restarcie (enable/disable)
- not-found - pliku unitu nie znaleziono
"Static" znaczy, że unit może być uruchomiony - w uproszczeniu - przez system i nie może być uruchomiony "ręcznie" przez administratora. Stan predefiniowany, czyli domyślny stan po instalacji pakietu z oprogramowaniem.
"Active":
- active - działa
- running - proces jest uruchomiony
- exited - zakończony sukcesem
- waiting - czeka na "event"
- inactive(dead) - nie działa, pytanie: dlaczego :)
Sprawdzenie statusu unitu, podając PID procesu lub jednego z procesów potomnych:
# systemctl status PID
Zapytanie "czy wystartowano", "czy włączono" daną usługę/unit:
# systemctl is-active name.type
# systemctl is-enable name.type
Wylistowanie załadowanych unitów:
# systemctl [list-units]
Wylistowanie wszystkich unitów (także tych wynikających z zależności, ale niezainstalowanych):
# systemctl [list-units] --all
Wylistownie załadowanych serwisów:
# systemctl [list-units] --type=service
# systemctl [list-units] -t service
Wylistowanie wszystkich serwisów (również tych, są zdefiniowane jako zależności między unitami, a nie są zainstalowane lub zdefiniowane):
# systemctl [list-units] -t service --all
Wylistowanie niepoprawnie działających unitów:
# systemctl --failed
# systemctl --all --failed
# systemctl --all --type=error
# systemctl --all --type=not-found
Wylistowanie wszystkich "trefnych" unitów:
# systemctl --all --failed --type=error --type=not-found --no-legend
Wylistowanie załadowanych unitów jednego, konkretnego typu:
# systemctl -t {service|socket|busname|target|snapshot|device|mount|automount|swap|timer|path|slice|scope}
Jeśli zmienimy konfiguracja unitów (zawartość plików unitów, ale również plików konfiguracyjnych takich jak: /etc/fstab, na podstawie których systemd generuje unity), to należy poinformować o tym systemd:
# systemctl daemon-reload
Permanentne wyłączenie unitu (głównie serwisów): (mocniejsze niż "disable", bo ani ręcznie, ani jako zależność unit ten nie zostanie uruchomiony):
# systemctl mask name.type
Wyłączenie "maskowania":
# systemctl unmask name.type
Wylistowanie zamaskowanych unitów:
# systemctl list-unit-files | awk '$2 == "masked" {print $1}'
Wylistowanie wszystkich plików unitów (trochę podobne do "chkconfig --list"):
# systemctl list-unit-files --all
UNIT FILE STATE
(...)
user.slice static
avahi-daemon.socket enabled
dbus.socket static
dm-event.socket static
docker.socket enabled
git-daemon.socket disabled
krb5-kpropd.socket disabled
libvirtd.socket enabled
lircd.socket disabled
lvm2-lvmetad.socket static
(...)
"State":
- enabled - włączony, po restarcie systemu zostanie włączony
- disabled- wyłączony, po restarcie systemu nie zostanie włączony, chyba że inny unit tego wymaga...
- static- może być uruchomiony, jeśli wymaga tego inny unit, ale nie może być uruchomiony przez administratora lub użytkownika
- masked- wyłączony permanentnie
Wylistowanie unitów wymaganych przez dany unit:
# systemctl list-dependencies name.type
Wymuszenie zatrzymania unitu, który "zawisł" ( i/lub ExecStop= nie działa ). Możemy wysłać do wszystkich procesów sygnał:
# systemctl kill [-s [SIG]KILL] [--kill-who=username] name.type
No ale jak taki unit typu "service" wygląda od środka?
Najprostszy wygląda tak:
[Service]
ExecStart=/path/to/application
"Prawdziwy" serwis wygląda tak (sshd.service):
[Unit]
Description=OpenSSH Daemon
Wants=sshdgenkeys.service
After=sshdgenkeys.service
After=network.target
[Service]
ExecStart=/usr/bin/sshd -D
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=always
[Install]
WantedBy=multi-user.target
W wielkim skrócie:
- Sekcja [Unit] opisuje meta informacje i zależności
- Sekcja [Service] opisuje co i jak ma być uruchomione
- Sekcja [Install] opisuje do jakiego targetu będzie dołączona ta usługa po jej włączeniu
Więcej powiemy na ten temat w rozdziale poświęconym tworzeniu własnych unitów.
Target
Target, czyli pewna funkcjonalność zdefiniowana przez grupę usług i innych targetów.
Podczas uruchamiania systemu celem jest "osiągnięcie" domyślnego targetu.
Nie mylić targetu z "runlevelem".
Jaki jest domyślny target?
# systemctl get-default
Jak zmienić domyślny target?
# systemctl set-default name.target
Lista wszystkich targetów:
# systemctl --all -t target
Wylistowanie targetów wymaganych przez konkretny target:
# systemctl list-dependencies multi-user.target | grep '.target$'
multi-user.target
+-basic.target
| +-paths.target
| +-slices.target
| +-sockets.target
| +-sysinit.target
| | +-cryptsetup.target
| | +-local-fs.target
| | +-swap.target
| +-timers.target
+-getty.target
+-remote-fs.target
Kiedyś w dystrybucjach z rodziny RHEL/Fedora "runlevel 3" oznaczał, że serwer jest w pełni funkcjonalny, a "runlevel 5" dodatkowo miał włączone środowisko graficzne.
Domyślny "runlevel" określony był w pliku /etc/inittab. Obecnie podobną funkcjonalność można uzyskać ustawiając domyślny target, albo na "multi-user.target", albo na "graphical.target".
Zmiana "stanu" systemu jest możliwa poprzez włączenie/wyłączenia "targetu".
Aby wystartować system w innym targecie niż domyślny, ustaw zmienną "systemd.unit=" w programie ładującym (grub, grub2, lilo,...) podczas uruchamiania systemu.
Wymuszenie osiągnięcia domyślnego targetu:
# systemctl default
# systemctl isolate default.target
Target "rescue" przydaje się do naprawy systemu i można go wymusić przy starcie systemu. Jego celem jest załadowanie minimalnego zestawu usług:
# systemctl rescue
# systemctl isolate rescue.target
Target "emergency" również służy głównie do naprawy systemu i można go wymusić przy starcie systemu. Po załadowaniu jądra i jego "ramdysku" wyszukana zostaje partycja główna "/" i zamontowana w trybie "tylko do odczytu". Na tym etapie przejmujemy kontrolę nad systemem:
# systemctl emergency
# systemctl isolate emergency.target
Przygotowanie systemu do wyłączenia zasilania:
# systemctl halt
# systemctl start halt.target --irreversible [--force [--force]]
Wyłączenie systemu razem z zasilaniem:
# systemctl poweroff
# systemctl start poweroff.target --irreversible [--force [--force]]
Restart systemu:
# systemctl reboot
# systemctl start reboot.target --irreversible [--force]
"Usypianie":
# systemctl suspend
# systemctl start suspend.target
"Hibernacja":
# systemctl hibernate
# systemctl start hibernate.target
Połączenie "usypiania" z "hibernacją":
# systemctl hybrid-sleep
# systemctl start hybrid-sleep.target
Socket
Pytanie: Czy aplikacja (sieciowa) musi być uruchomiona przy starcie, czy też dopiero wtedy, kiedy jest potrzebna?
Oto sshd.socket:
[Unit]
Description=SSH Socket for Per-Connection Servers
[Socket]
ListenStream=22
Accept=yes
[Install]
WantedBy=sockets.target
Domyślnie "socket" uruchamia "service" o tej samej nazwie.
Teraz zamiast używać sshd.service możemy użyć sshd.socket:
# systemctl stop sshd
# systemctl disable sshd
# systemctl enable sshd.socket
# systemctl start sshd.socket
Od tej chwili to systemd nasłuchuje na porcie :22 w oczekiwaniu na połączenie.
(Tak naprawdę to sshd.socket nie uruchomi bezpośrednio usługi sshd.service, tylko "template" sshd@.service - wszystko przez opcję "Accept=yes" - o "template'ach" będzie później...)
Timer
Timer jest odpowiedzialny za uruchomienie usługi w określonym czasie lub/i o określonym interwale.
Domyślnie "timer" uruchamia "service" o tej samej nazwie.
Przykładowo:
# cat /usr/lib/systemd/system/systemd-tmpfiles-clean.timer
(...)
[Timer]
OnBootSec=15min
OnUnitActiveSec=1d
Timer systemd-tmpfiles-clean.timer uruchamia usługę systemd-tmpfiles-clean.service:
- 15 minut po uruchomieniu serwera
- po pierwszym uruchomieniu cyklicznie co jedną dobę
Inne przydatne opcje:
- OnActiveSec= - od momentu aktywacji timera
- OnBootSec= - od uruchomienia serwera
- OnStartupSec= - od pierwszego uruchomienia serwera
- OnUnitActiveSec= - od ostatniej aktywacji timera
- OnUnitInactiveSec= - od ostatniej dezaktywacji timera
- OnCalendar= - cykliczność - podobnie do usługi CRON
- AccuracySec= - dopuszczalne opóźnienie aktywacji
- Unit= - jeśli chcesz uruchomić usługę o innej nazwie
Specyfikacja czasu
(man systemd.time)
Poniższe informacje dotyczą całego systemd, czyli również journald.
Jednostki czasu:
- usec, us
- msec, ms
- seconds, second, sec, s
- minutes, minute, min, m
- hours, hour, hr, h
- days, day, d
- weeks, week, w
- months, month
- years, year, y
Bez określenia (domyślnie) jednostki czasu: 50 znaczy 50 sekund.
Można łączyć, np: "2min 200ms".
Cykliczność: "minutely", "hourly", "daily", "monthly", "weekly", "yearly", "quarterly", "semiannually".
Znacznik czasu "timestamp" ma postać: "DayOfWeek YYYY-MM-DD HH:MM:SS": np:
Uwaga:
- * = dowolna wartość
- a/b = a, a+b, a+2*b, a+3*b,...
# "Podobnie" jak dla usługi CROND
# skrót › rozwinięcie
Sat,Thu,Mon-Wed,Sat-Sun › Mon-Thu,Sat,Sun *-*-* 00:00:00
Mon,Sun 12-*-* 2,1:23 › Mon,Sun 2012-*-* 01,02:23:00
Wed *-1 › Wed *-*-01 00:00:00
Wed-Wed,Wed *-1 › Wed *-*-01 00:00:00
Wed, 17:48 › Wed *-*-* 17:48:00
Wed-Sat,Tue 12-10-15 1:2:3 › Tue-Sat 2012-10-15 01:02:03
*-*-7 0:0:0 › *-*-07 00:00:00
10-15 › *-10-15 00:00:00
monday *-12-* 17:00 › Mon *-12-* 17:00:00
Mon,Fri *-*-3,1,2 *:30:45 › Mon,Fri *-*-01,02,03 *:30:45
12,14,13,12:20,10,30 › *-*-* 12,13,14:10,20,30:00
mon,fri *-1/2-1,3 *:30:45 › Mon,Fri *-01/2-01,03 *:30:45
03-05 08:05:40 › *-03-05 08:05:40
08:05:40 › *-*-* 08:05:40
05:40 › *-*-* 05:40:00
Sat,Sun 12-05 08:05:40 › Sat,Sun *-12-05 08:05:40
Sat,Sun 08:05:40 › Sat,Sun *-*-* 08:05:40
2003-03-05 05:40 › 2003-03-05 05:40:00
2003-03-05 › 2003-03-05 00:00:00
03-05 › *-03-05 00:00:00
hourly › *-*-* *:00:00
daily › *-*-* 00:00:00
monthly › *-*-01 00:00:00
weekly › Mon *-*-* 00:00:00
yearly › *-01-01 00:00:00
annually › *-01-01 00:00:00
*:2/3 › *-*-* *:02/3:00
Przykład 1: (każdego roku, 5 stycznia o północy)
*-01-05 › *-01-05 00:00:00
Przykład 2: (każdego roku, 5 marca o północy i co dwa miesiące: 5 maja o północy, 5 lipca o północy,...)
*-01/2-05 › *-01/2-05 00:00:00
Czas względny:
# Załóżmy, że aktualny data to: 2012-11-23 18:15:22
+3h30min › Fri 2012-11-23 21:45:22
-5s › Fri 2012-11-23 18:15:17
11min ago › Fri 2012-11-23 18:04:22
11min left › Fri 2012-11-23 18:26:22
UTC:
@1395716396 › Tue 2014-03-25 03:59:56
Podsumowanie
Przedstawiłem podstawowe zagadnienia związane z systemd oraz omówiłem krótko podstawowe typy unitów.
W następnych częściach: journald, nspawn, networkd, generatory...
Część następna