Poradnik: systemd — cz. 3
Wstęp
Kontynuacja dwóch poprzednich części: 1 i 2.Uruchamianie poleceń
Już ustaliliśmy, że najprostszy serwis to:
[Service] ExecStart=/usr/local/bin/script.sh
Pytanie: a jeśli potrzebuje uruchomić jakieś polecenie tylko raz, to czy muszę tworzyć plik serwisu? Nie... Tak wygląda polecenie "ls /root" uruchomione bezpośrednio w systemd:
# systemd-run ls /root Running as unit run-18402.service. # systemctl status -l run-18402.service run-18402.service Loaded: not-found (Reason: No such file or directory) Active: inactive (dead) lis 10 14:33:35 archer systemd[1]: Started /usr/bin/ls /root. lis 10 14:33:35 archer ls[18407]: docker.iptables lis 10 14:33:35 archer ls[18407]: lista.org lis 10 14:33:35 archer ls[18407]: lista.txt
Jeden z plusów uruchomienia jakiegoś skryptu lub polecenia jako unitu jest fakt, że możemy teraz korzystać z własności systemd - m.in. przejrzeć log:
# journalctl -u run-18402.service -- Logs begin at wto 2015-06-23 13:50:59 CEST, end at wto 2015-11-10 14:33:35 CET. -- lis 10 14:33:35 archer systemd[1]: Started /usr/bin/ls /root. lis 10 14:33:35 archer ls[18407]: docker.iptables lis 10 14:33:35 archer ls[18407]: lista.org lis 10 14:33:35 archer ls[18407]: lista.txt lis 10 14:33:35 archer ls[18407]: plik lis 10 14:33:35 archer ls[18407]: plik1 lis 10 14:33:35 archer ls[18407]: plik2 lis 10 14:33:35 archer ls[18407]: plik.sh lis 10 14:33:35 archer ls[18407]: yyy.txt
To chyba dobry czas, by powiedzieć sobie parę zdań o journald.
Logowanie - journald
Systemd zawiera usługę odpowiedzialną za zbieranie logów. W systemach Red Hat w celu utrzymania kompatybilności równolegle działa usługa "rsyslog". W Arch Linux możesz spokojnie skupić się na "journald", a dokładnie na usłudze "systemd-journald". Journald przechowuje logi w postaci binarnej i domyślnie są przechowywane w ulotnym katalogu /run, czyli giną podczas restartu maszyny... Możemy równolegle przechowywać je - jak robi Red Hat - w "rsyslogu", albo zrobić tak:
# mkdir /var/log/journal/ # chgrp systemd-journal /var/log/journal/ # chmod 2755 /var/log/journal/ # killall -USR1 systemd-journald
Przeglądamy log poleceniem:
# journalctl
Ostatnie 10 lub N linii:
# journalctl -n [N]
Pokaż logi o priorytecie "err" (priorytety jak w rsyslog):
# journalctl {-p|--priority} err
Monitorowanie logu w trybie ciągłym - coś jak "tail -f":
# journalctl -f
Logi od dnia [do dnia]:
# journalctl --since "2014-02-10 20:30:00" # journalctl --since "2014-02-10 20:30:00" --until "2014-02-11 20:30:00" # journalctl --since {yesterday,today,tomorrow}
Logi w journal nie są "płaskie", jak w rsyslogu. Dodaj opcję "‑o verbose" a zobaczysz, iż wpisy w journald mają postać rekordu:
# journalctl -n 1 -o verbose -- Logs begin at wto 2015-06-23 13:50:59 CEST, end at wto 2015-11-10 14:33:35 CET. -- wto 2015-11-10 14:33:35.842591 CET [s=52fe4d852ffc4d83bd7ba37d30b85d68;i=18b6e;b=4e42413b402a4241b59d6b665776c144;m=11daf8b02b0;t=5242fc1ba8751;x=847c4d27c2cb86c8] _TRANSPORT=syslog _SYSTEMD_SLICE=system.slice _MACHINE_ID=998523018d824208a4de0c4af4f2fbd8 _HOSTNAME=archer _CAP_EFFECTIVE=0 PRIORITY=5 SYSLOG_FACILITY=10 SYSLOG_IDENTIFIER=polkitd _UID=102 _GID=102 _COMM=polkitd _EXE=/usr/lib/polkit-1/polkitd _CMDLINE=/usr/lib/polkit-1/polkitd --no-debug _SYSTEMD_CGROUP=/system.slice/polkit.service _SYSTEMD_UNIT=polkit.service _BOOT_ID=4e42413b402a4241b59d6b665776c144 SYSLOG_PID=569 _PID=569 MESSAGE=Unregistered Authentication Agent for unix-process:18402:122701076 (system bus name :1.270, object path /org/freedesktop/PolicyKit1/AuthenticationAgent, locale pl_PL.utf8) (disconnected from bus) _SOURCE_REALTIME_TIMESTAMP=1447162415842591
Czyli dla każdego wpisu do logu mamy informacje o jego pochodzeniu i kontekscie. Wynik tego polecenia zawiera pola m.in. takie jak: _UID, _GID, _SYSTEMD_SLICE, _PID, _COMM, _EXE, _CMDLINE, _SYSTEMD_CGROUP, _SYSTEMD_UNIT. Można użyć tych pól do zapytań np:
# journalctl _COMM=sshd # journalctl _PID=567 # journalctl _TRANSPORT=kernel # journalctl _SYSTEMD_UNIT=sshd.service
Zapytanie o log danego unitu:
# journalctl -u name.type
Log z ostatniego bootowania:
# journalctl -b [0]
Log z poprzedniego bootowania
# journalctl -b -1
TIP1: Przekazywanie logu na 12‑sty wirtualny terminal:
# cat <<EOF > /etc/systemd/journald.conf.d/fw-tty12.conf [Journal] ForwardToConsole=yes TTYPath=/dev/tty12 MaxLevelConsole=info EOF
TIP2: Jak dobrać się do logów z zamontowanego dysku zewnętrznego?:
# journalctl -D /mnt/var/log/journal -xe
TIP3: Domyślnie polecenie journalctl obcina zbyt długie linie. Można to zmienić: Domyślne parametry pagera "less" to FRSXMK, pomiń "S", aby linie były wyświetlane w całości, np:
# SYSTEMD_LESS=FRXMK journalctl
lub ustaw zmienną środowiskową SYSTEMD_LESS na stałe w /etc/profile[.d] lub ~/.bash_profile:
# export SYSTEMD_LESS=FRXMK
Czas
Serwer czasu, czyli usługa odpowiedzialna za synchronizację czasu na naszym serwerze to teraz "chrony", a nie jak kiedyś "ntp". Zainstaluj "chrony" i uaktualnij plik konfiguracyjny, np: dodając wpisy do pliku:
# grep "^server " /etc/chrony.conf server 0.pl.pool.ntp.org iburst server 1.pl.pool.ntp.org iburst server 2.pl.pool.ntp.org iburst server 3.pl.pool.ntp.org iburst
Następnie możemy uruchomić usługę chrony:
# systemctl enable chronyd # systemctl start chronyd
Weryfikacja poprawności działania usługi chrony:
# chronyc sources -v
Teraz możemy sprawdzić naszą konfigurację systemd:
# timedatectl [status] Local time: wto 2015-11-10 15:16:37 CET Universal time: wto 2015-11-10 14:16:37 UTC RTC time: wto 2015-11-10 14:16:37 Time zone: Europe/Warsaw (CET, +0100) Network time on: yes NTP synchronized: yes RTC in local TZ: no
Plik strefy czasowej jest tu:
# file /etc/localtime /etc/localtime: symbolic link to /usr/share/zoneinfo/Europe/Warsaw
Ustaw strefę:
# timedatectl list-timezones # timedatectl set-timezone Europe/Warsaw
Ustaw czas "ręcznie":
# timedatectl set-time 9:00:00
Włącz/wyłącz synchronizację z NTP:
# timedatectl set-ntp {true|false|0|1|on|off}
Domyślnie Real Time Clock jest ustawiony na UTC ("yes"), ale możesz go przestawić na "localtime" ("no"). Nie wiem, po co, bo wszystkie serwery czasu działają wg UTC.
# timedatectl set-local-rtc {true|false|0|1|on|off}
Locale - personalizacja
Pliki konfiguracyjne:
/etc/locale.conf /etc/vconsole.conf /etc/X11/xorg.conf.d/00-keyboard.conf
Rozpoznanie:
# localectl status System Locale: LANG=pl_PL.utf8 VC Keymap: pl2 X11 Layout: pl X11 Model: pc105 X11 Options: terminate:ctrl_alt_bksp # localectl list-locales | grep -i pl pl_PL pl_PL.iso88592 pl_PL.utf8
Ustawienie polskich "lokali":
# localectl set-locale LANG=pl_PL.utf8
Zmiana ustawień klawiatury "systemowej" (nie X11!!!):
# localectl list-keymaps | grep -i pl # localectl set-keymap pl2
Jeśli jednak chcesz koniecznie ustawić inny układ dla X11 (uwaga: polecenie automatycznie konwertuje i zmienia układ klawiatury systemowej):
# localectl set-x11-keymap pl
Bez konwertowania (tylko X11):
# localectl --no-convert set-x11-keymap pl
Uwaga: Z tego wniosek iż prościej najpierw zmienić ustawienia klawiatury dla X11, potem systemowej.
Hostname
Wg Red Hat: "hostname" to maksymalnie 64 znakowy ciąg znaków. Red Hat rekomenduje aby "hostname" był formatu FQDN (fully-qualified domain name), czyli np: host.example.com, czyli taki, jaki używany jest w usłudze DNS.
Dalsze rekomendacje to: - tylko małe litery (7 bit ASCII) - bez spacji i kropek - użycie "_" też może być problematyczne, szczególnie przy starszych systemach
Polecenie "hostnamectl" ograniczy Cię do: "a‑z", "A‑Z", "0‑9", “‑”, “_”, “.”, a kropka nie może występować na końcu, początku lub obok siebie.
# hostnamectl [status]
Chcesz zmienić "hostname"?:
# hostnamectl set-hostname host.example.com
lub
# echo host.example.com > /etc/hostname # systemctl restart systemd-hostnamed
Pliki tymczasowe
man tmpfiles.d
Systemd posiada podsystem odpowiedzialny za utrzymywanie plików, linków symbolicznych i katalogów tymczasowych.
systemd-tmpfiles-setup
Systemd podczas startu uruchamia usługę "systemd-tmpfiles-setup", która uruchamia polecenie:
/usr/bin/systemd-tmpfiles --create --remove --boot --exclude-prefix=/dev
Opcje:
- --create - tworzy brakujące pliki, katalogi, linki
- --remove - usuwa przeznaczone do usunięcia pliki, katalogi, linki
- --boot - wykonuje operację przeznaczone do wykonania tylko podczas uruchamiania systemu
- --clean - wykonuje "czyszczenie" plików i katalogów
- --exclude-prefix=/dev - pomija wszelkie pliki urządzeń
Polecenie to zaczytuje konfigurację z:
- /usr/lib/tmpfiles.d/*.conf - dostarczone przez pakiet (nie zmieniać!!!)
- /etc/tmpfiles.d/*conf - tam umieszczamy naszą twórczość
Pliki, katalogi i linki zaznaczone do usunięcia, zostają usunięte. Pliki, katalogi i linki zaznaczone do utworzenia zostają stworzone (z niezbędną korektą uprawnień).
systemd-tmpfiles-clean
System może działać długo, więc dodatkowo skonfigurowany jest "timer" systemd-tmpfiles-clean.timer:
[Timer] OnBootSec=15min OnUnitActivateSec=1d
Timer ten 15 minut po uruchomieniu systemu (i następnie raz na dobę) uruchomi usługę o tej samej nazwie: systemd-tmpfiles-clean.service, a usługa ta uruchomi polecenie:
# systemd-tmpfiles --clean
Uwaga: Jak wiadomo mamy czasy: mtime (data modification), ctime (change status) i atime (access). Plik/katalog uznaje się za "przestarzały" jeśli WSZYSTKIE te czasy spełniają tej warunek.
Pliki konfiguracyjne składają się z 6 kolum: "type path mode uid gid age argument"
Type - rodzaje operacji:
- d - stwórz katalog, jeśli go nie ma
- D - stwórz lub wyczyść katalog
- f - stwórz plik
- F - stwórz plik lub go wyczyść
- L - stwórz symlink jeśli nie istnieje
Przykłady:
d /run/systemd/seats 0755 root root - D /home/student 0700 student student 1d L /run/fstablink - root root - /etc/fstab L+ /etc/mtab - - - - ../proc/self/mounts # Unlink the X11 lock files r! /tmp/.X[0-9]*-lock
Opcja z '!' - można uruchomić tylko przy starcie systemu (-‑boot). Bez wykrzyknika uważa się, żę można bezpiecznie wykonywać zadanie kiedykolwiek. Znak "+" oznacza, że jeśli plik/katalog/link istnieje, to zostanie zastąpiony nowym. (uwaga: link potrafi zastąpić plik lub katalog)
Możesz stworzyć własny plik konfiguracyjny i przetestować go poleceniami ("czyszczenie", "tworzenie" lub "usuwanie" plików/katalogów)
# systemd-tmpfiles --clean /etc/tmpfiles.d/your_file.conf # systemd-tmpfiles --create /etc/tmpfiles.d/your_file.conf # systemd-tmpfiles --remove /etc/tmpfiles.d/your_file.conf
Oczywiście, po zmianie konfiguracji należy powiadomić o tym systemd:
# systemctl daemon-reload # systemctl restart systemd-tmpfiles-clean
D-Bus / kdbus
Tu jest dokładny opis, jak działają obie szyny.
D‑bus - mechanizm (szyna) pozwalający na komunikację między procesami (inter-process communication (IPC)) i zdalne wywoływanie procedur (remote procedure call (RPC)) Systemd nie jest już zależny od biblioteki "libdbus". Cała komunikacja z szyną ma miejsce poprzez nową bibliotekę: sd‑bus. Kiedy obsługa kdbus jest włączona (domyślnie jeszcze nie jest - może w 2016 roku) wtedy proces PID=1 konfiguruje szynę systemową i włącza obsługę unitów typu "busname", które mają za zadanie enkapsuować odwołania do kdbus.
Cel jest prosty: - zastąpić d‑bus nową szyną: kdbus - szyna ta ma działać na "wczesnym" etapie uruchamiania systemu
Wylistowanie wszystkich ("unique names" i "well-known names") szyn:
# busctl
Wylistowanie tylko "unikalnych":
# busctl list --unique
Wylistowanie tylko dobrze znanych
# busctl list --acquired
Wylistowanie wszystkich usług w postaci drzewa:
# busctl tree (...) Service org.freedesktop.PolicyKit1: L¦/org L¦/org/freedesktop L¦/org/freedesktop/PolicyKit1 L¦/org/freedesktop/PolicyKit1/Authority Service org.fedoraproject.FirewallD1: L¦/org L¦/org/fedoraproject L¦/org/fedoraproject/FirewallD1 L¦/org/fedoraproject/FirewallD1/config +¦/org/fedoraproject/FirewallD1/config/icmptype - +¦/org/fedoraproject/FirewallD1/config/icmptype/0 (...)
Wylistowanie jednej usługi:
# busctl tree org.freedesktop.login1 L¦/org/freedesktop/login1 +¦/org/freedesktop/login1/seat - +¦/org/freedesktop/login1/seat/seat0 - L¦/org/freedesktop/login1/seat/self +¦/org/freedesktop/login1/session - +¦/org/freedesktop/login1/session/c1 - L¦/org/freedesktop/login1/session/self L¦/org/freedesktop/login1/user +¦/org/freedesktop/login1/user/_1000 L¦/org/freedesktop/login1/user/self
Konkretnie o konkretnej usłudze:
# busctl introspect org.freedesktop.login1 /org/freedesktop/login1/user/_1000 NAME TYPE SIGNATURE RESULT/VALUE FLAGS org.freedesktop.DBus.Introspectable interface - - - .Introspect method - s - org.freedesktop.DBus.Peer interface - - - .GetMachineId method - s - .Ping method - - - org.freedesktop.DBus.Properties interface - - - .Get method ss v - .GetAll method s a{sv} - .Set method ssv - - .PropertiesChanged signal sa{sv}as - - org.freedesktop.login1.User interface - - - .Kill method i - - .Terminate method - - - .Display property (so) "c1" "/org/freedesktop/login1/session... emits-change .GID property u 1000 const .IdleHint property b false emits-change .IdleSinceHint property t 0 emits-change .IdleSinceHintMonotonic property t 0 emits-change .Linger property b false - .Name property s "mb" const .RuntimePath property s "/run/user/1000" const .Service property s "user@1000.service" const .Sessions property a(so) 1 "c1" "/org/freedesktop/login1/sessi... emits-change .Slice property s "user-1000.slice" const .State property s "active" - .Timestamp property t 1438083988241975 const .TimestampMonotonic property t 24245141 const .UID property u 1000 const
Pobranie wartości dowolnego parametru:
# busctl get-property org.freedesktop.login1 /org/freedesktop/login1/user/_1000 org.freedesktop.login1.User Sessions a(so) 1 "c1" "/org/freedesktop/login1/session/c1"
kdbus
Na ten moment kdbus nie jest domyślną szyną systemową, ale możesz wymusić jej użycie dodając w programie ładującym (GRUB) parametr "kdbus=1". Zmodyfikuj w pliku /etc/default/grub zmienną GRUB_CMDLINE_LINUX_DEFAULT dodając "kdbus=1", a następnie uaktualnij konfigurację GRUB poleceniem:
(Arch Linux)# grub-mkconfig -o /boot/grub/grub.cfg
Po restarcie sprawdź, czy opcja ta faktycznie miała zastosowanie:
# cat /proc/cmdline BOOT_IMAGE=/vmlinuz-4.2.0-0.rc5.git3.1.fc24.x86_64 (...) kdbus=1
Upewniamy się, czy mamy (automatycznie) zamontowany specjalny system plików:
# mount | grep kdbus kdbusfs on /sys/fs/kdbus type kdbusfs (rw,nosuid,nodev,noexec,relatime) # ls -al /sys/fs/kdbus/ total 0 dr-xr-xr-x. 2 root root 0 Aug 11 09:21 . drwxr-xr-x. 8 root root 0 Aug 11 09:21 .. dr-xr-xr-x. 2 root root 0 Aug 11 09:21 0-system dr-x------. 2 root root 0 Aug 11 09:25 0-user -rw-rw-rw-. 1 root root 0 Aug 11 09:21 control # ls -al /sys/fs/kdbus/0-system/ total 0 dr-xr-xr-x. 2 root root 0 Aug 11 09:21 . dr-xr-xr-x. 2 root root 0 Aug 11 09:21 .. -rw-rw-rw-. 1 root root 0 Aug 11 09:21 bus # ls -al /sys/fs/kdbus/0-user/ total 0 dr-x------. 2 root root 0 Aug 11 09:25 . dr-xr-xr-x. 2 root root 0 Aug 11 09:21 .. -rw-------. 1 root root 0 Aug 11 09:25 bus
Uwaga: Jeśli kolumna DESCRIPTION (wynik polecenia "busctl") jest niepusta, to używasz kdbus!!! Dodatkowo prawidłowe załadowanie modułu 'kdbus' dodatkowo można zweryfikować potwierdzając istnienie katalogu: /sys/fs/kdbus/0-system
Podsumowanie
Jak widać mówienie o systemd jak o menadżerze usług to "małe" niedomówienie... W następnej części kontenery "nspawn" i zarządzanie siecią "networkd".