Strona używa cookies (ciasteczek). Dowiedz się więcej o celu ich używania i zmianach ustawień. Korzystając ze strony wyrażasz zgodę na używanie cookies, zgodnie z aktualnymi ustawieniami przeglądarki.    X

Poradnik: systemd — cz. 1

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.

r   e   k   l   a   m   a

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


  1. timer - aktywacja zadań oparta o czas (man systemd.timer)
  2. service - coś jak "stare" serwisy/usługi (man systemd.service)
  3. socket - nasłuchiwanie na danym porcie zamiast uruchamianie serwisu. Usługa zostanie uruchomiona po podłączeniu się klienta - coś jak "xinetd"
  4. 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.
  5. path - monitorowanie ścieżki w celu aktywacji jakiegoś zadania (man systemd.path)
  6. scope - grupa procesów. Sesje użytkowników, kontenery, wirtualne maszyny są pogrupowanie w "scope'y" (man systemd.scope)
  7. 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)
  8. automount - auto montowanie filesystemów (man systemd.automount) takich jak: /proc i /sys
  9. mount - montowanie filesystemów (man systemd.mount) takich jak: /boot, swap, /tmp
  10. snapshot - snapshoty nie są konfigurowane przez pliki. Są dynamicznie (systemctl snapshot) zapisywanym stanem procesów. (man systemd.snapshot)
  11. device - pliki urządzeń (man systemd.device)
  12. 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  

linux porady

Komentarze