wtorek, 2 grudnia 2014

Pora na Systemd

Wstęp


No i stało się, choć nikt się tego nie spodziewał. Stary, stabilny i sprawdzony SysVinit odchodzi definitywnie do lamusa. Jego miejsce przejmuje bardziej rozbudowany Systemd. Wiele pasjonatów Linuxa wciąż nie może się do tej zmiany przyzwyczaić, choć od oficjalnego wycofania starego SysVinit z Arch Linux mineło już parę ładnych lat. Wszelkie dystrybucje Linux, wydane po dacie 13/10/2012 operają się na nowym systemd.

Oba rowiązania, zarówno SystemVinit, jak i systemd odpowiedzialne są głównie za sterowanie procesami rozruchu systemu oraz usługami.

Przez wiele lat Linux dawał sobię radę idealnie z SysVinit bądź z BSDinit i nie było z tym najmniejszych kłopotów, bo wszystko było optymalnie ogarnięte i zorganizowane. Katalog /etc/rc.d/init.d ze znajdującymi się w nim skryptami usług, jak również i inne katalogi, w których znajdowały się symboliczne powiązania do skryptów usług, świetnie pełniły swoje role. Narzędzia typu chkconfig czy service optymalnie się sprawowały i nikt naprawdę się nie spodziewał tego, że SysVinit zostanie kompletnie wycofany z obiegu. Teoretycznie nie było takiej konieczności, a przynajmniej prawie nikt o niej nie wiedział, poza wązkim gronem ściśle wyspecjalizowanych programistów. Sam twórca Linuksa, Linus Torvalds, nie jest zadowolony z nadejścia Systemd i definitywnego wycofania starego i poczciwego SystemVinit.

Co jest grane?


Zmiany są spore. Wiele fachowców wychowanych na SysVinit nie może się z nimi uporać. Można było oczywiście przewidzieć, że wiele osób ze zmianami szybko się nie oswoi i głównie z tej przyczyny nowy Systemd został dodatkowo wzbogacony o narzędzia zapewniające pewien stopien kompatybilności ze starym podejściem. Na dzień dzisiejszy narzędzia chkconfig oraz service, choć oficjalnie należą już do przeszłości, działają nadal pod systemd, choć nie zapewniają one pełnej kompatybilności usług z nowym systemem i nie wiadomo dokładnie jak długo jeszcze będą one dostępne w dystrybucjach Linux. Z tych i innych przyczyn nadszedł czas aby się pogodzić ze zmianami i zapoznać się z systemd. Oferuje on bowiem, wiele cikawych rozwiązań.

Kiedyś katalogi ze skryptami odpowiedzialnymi za usługi uruchamiane podczas startu systemu oraz skryptami sterującymi usługami wyglądały mniej więcej tak:

[root@filemon ~]# ls -al /etc/rc.d
total 68
drwxr-xr-x 10 root root  4096 Feb  2  2011 .
drwxr-xr-x 73 root root  4096 Nov  9 18:34 ..
drwxr-xr-x  2 root root  4096 Oct 23 08:08 init.d
-rwxr-xr-x  1 root root  2617 Nov 24  2010 rc
drwxr-xr-x  2 root root  4096 Nov 30 20:44 rc0.d
drwxr-xr-x  2 root root  4096 Nov 30 20:44 rc1.d
drwxr-xr-x  2 root root  4096 Nov 30 20:44 rc2.d
drwxr-xr-x  2 root root  4096 Nov 30 20:44 rc3.d
drwxr-xr-x  2 root root  4096 Nov 30 20:44 rc4.d
drwxr-xr-x  2 root root  4096 Nov 30 20:44 rc5.d
drwxr-xr-x  2 root root  4096 Nov 30 20:44 rc6.d
-rwxr-xr-x  1 root root   220 Nov 24  2010 rc.local
-rwxr-xr-x  1 root root 19088 Nov 24  2010 rc.sysinit

Katalogi od rc-0.d do rc6.d przchowywały symboliczne powiązania do skryptów usług, znajdujących si w /etc/rc.d/init.d

Choć syboliczne powiązania do skryptów usług pozostają, to Systemd zorganizowany jest w zupełnie odmienny sposób.

W odpowiednich podkatalogach ścieżki /etc/systemd/system znajdują się symboliczne powiązania do plików umieszczonych w katalogu /usr/lib/systemd/system. Katalog /usr/lib/systemd/system jest miejscem, w którym znajdują się skrypty usług. Jeżeli okreśłona usługa, której skrypt znajduje się w /usr/lib/systemd/system ma być uruchamiona w trakcje startu systemu, wówczas należy utworzyć do jej skryptu odpowiednie powiązanie symboliczne, umieszczacjąc je w podkatalogach ścieżki /etc/systemd/system. Z pomocą przychodzi tutaj narzędzie systemctl, więc nie trzeba tego robić ręcznie.

Powiedzmy, że chcemy, aby usługa httpd była uruchamiana w trakcie startu systemu. Kiedyś robiło się to za pomocą narzędzia chkconfig, określając poziomy pracy (runlevels) w których usługa ma być automatycznie uruchamiana. Przykładowo:

chkconfig --level 35 httpd on


W platformach bazujących na systemd, aby uzyskać podobny efekt można posłużyć się narzędziem systemctl:

[root@filemon1 ~]# systemctl enable httpd.service
ln -s '/usr/lib/systemd/system/httpd.service' '/etc/systemd/system/multi-user.target.wants/httpd.service'

Systemctl a usługi

Jednym z głównych narzędzi pracy w systemd jest komenda systemctl.

Narzędzie systemctl może być stosowane nie tylko do nadzoru i zmian statusów usług, automatycznego włączania usług podczas startu systemu, lecz także do zadań takich jak zamykanie systemu, ponowne uruchamianie systemu, uzyskiwanie informacji o aktywnych gniazdach (sockets), uzyskiwanie informacji o zależnościach związanych z usługami, zdalne administrowanie usługami i o wiele, wiele więcej.

Odnosząc się w komendzie systemctl do usług, należy dodawać rozszerzenie .service, choć, jak narazie, nie jest to wymuszane przez system. W przypadku pominięcia rozszerzenia, domniemane jest, iż chodzi właśnie  o .service.

Poziomów pracy, w których usługa ma być uruchamiana, nie trzeba już wskazywać ręcznie jak kiedyś, za czasów chkconfig. Jak pisałem wyżej, narzędzie systemctl, podczas aktywowania usług (opcja enable) tworzy symboliczne powiązania do skryptów usług. W zależności od tego, w którym podkatalogu ścieżki /etc/systemd/system umieści powiązanie, to usługa będzie automatycznie uruchamiana w określonym 'poziomie pracy' systemu. Nie ma już jednak mowy tutaj o klasycznych poziomach pracy typu init runlevel z czasów SysVinit. Systemd funkcjonuje nieco inaczej, ale to zagadnieje opiszę trochę dalej. Teraz postaram się odpowiedzieć na pytanie skąd systemctl wie w którym podkatalogu /etc/systemd/system ma wstawić symboliczne powiązanie do skryptu usługi. Skąd narzędzie systemctl, wywołane z parametrem enable, wie w których 'poziomach pracy' systemu dana usługa ma być uruchamiana? Odpowiedź na to pytanie staje się jasna po przeanalizowaniu zawartości przykładowego skryptu usługi. Przeanalizujmy przykładowo skrypt usługi httpd, znajdujący się w katalogu /usr/lib/systemd/system. Oto zawartość skryptu, który w porównaniu ze swoim odpowiednikiem ze środowiska SysVinit, jest bardzo krótki:

[Unit]
Description=The Apache HTTP Server
After=network.target
After=remote-fs.target
After=nss-lookup.target
After=named-setup-rndc.service
Wants=nss-lookup.target
Wants=named-setup-rndc.service

[Service]
Type=notify
EnvironmentFile=/etc/sysconfig/httpd
ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND
ExecReload=/usr/sbin/httpd $OPTIONS -k graceful
ExecStop=/bin/kill -WINCH ${MAINPID}
# We want systemd to give httpd some time to finish gracefully, but still want
# it to kill httpd after TimeoutStopSec if something went wrong during the
# graceful stop. Normally, Systemd sends SIGTERM signal right after the
# ExecStop, which would kill httpd. We are sending useless SIGCONT here to give
# httpd time to finish.
KillSignal=SIGCONT
PrivateTmp=true

[Install]
WantedBy=multi-user.target

Sekcja [Install] określna, w którym podkatalogu ścieżki /etc/systemd/system narzędzie systemctl ma umieścić symboliczne powiązanie do skryptu, w więc w którym 'poziomie pracy' systemu usługa ma być automatycznie uruchamiana. Ponieważ informacja ta zawarta jest w samym skrypcie, nie podaje się jej ręcznie w chwili włączania usługi przy pomocy narzędzia systemctl.

Sekcja [Unit] pozwala określić dokładny moment startu systemu, w którym usługa ma być uruchomiona. Słowo kluczowe After powoduje uruchomienie usługi po okreśłonym poziomie startu target lub po uruchomieniu okreśłonej usługi service, natomiast słowo before określa iż usługa ma być uruchomiona przed okreśłonym 'poziomem startu' target lub usługą service.

W przeciwieństwie do stosowanego w przeszłości narzędzia service, umożliwiającego uruchomienie, zatrzymanie bądź sprawdzenie stanu danej usługi, dziś można się w takich celach posługiwać narzędziem systemctl. Przykładowo:

[root@filemon1 ~]# systemctl status httpd.service
httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled)
   Active: active (running) since Mon 2014-12-01 21:54:54 CET; 1s ago
  Process: 14881 ExecStop=/bin/kill -WINCH ${MAINPID} (code=exited, status=0/SUCCESS)
 Main PID: 14889 (httpd)
   Status: "Processing requests..."
   CGroup: /system.slice/httpd.service
           ├─14889 /usr/sbin/httpd -DFOREGROUND
           ├─14890 /usr/sbin/httpd -DFOREGROUND
           ├─14892 /usr/sbin/httpd -DFOREGROUND
           ├─14893 /usr/sbin/httpd -DFOREGROUND
           ├─14894 /usr/sbin/httpd -DFOREGROUND
           ├─14895 /usr/sbin/httpd -DFOREGROUND
           └─14896 /usr/sbin/httpd -DFOREGROUND

Dec 01 21:54:54 filemon1 systemd[1]: Starting The Apache HTTP Server...
Dec 01 21:54:54 filemon1 systemd[1]: Started The Apache HTTP Server.

Jak widać, proste zapytanie o stan usługi, wyświetla całą gamę przydatnych informacji, począwszy od samego stanu usługi, informacji o tym, czy usługa jest automatycznie uruchamiana podczas startu systemu (enabled), poprzez informacje o procesach związanych z usługą, aż po komunikaty (messages) wygenerowane przez usługę.

Systemd opiera się na jednostkach (units), który można wymienić aż 12 różnych typów. Oprócz jednostki typu .service, systemd posługuje się następującymi typami jednostek:
  • Target: grupa jednostek
  • Automount: miejsce automatycznego zamontowania systemu plików
  • Device: nazwy urządzeń jądra, jakie widnieją w sysfs i udev
  • Mount: miejsce zamontowania systemu plików
  • Path: plik lub katalog
  • Scope: zewnętrzne procesy, nie uruchamiane przez systemd
  • Slice: jednostka zarządzania procesami
  • Snapshot: zachowany stan systemd
  • Socket: IPC (inter-process communication) socket
  • Swap: plik swap
  • Timer: timer systemd
Jak widać, jest tego wszystkiego sporo, ale ma to swoje zalety, więc naprawdę warto przekonać się do nowego podejścia. Jednak nawet średnio-zaawansowany użytkownik Linuxa, żadko kiedy będzie miał potrzebę posługiwania się wszystkimi wyżej wymienionymi jednostkami systemd. Najczęściej wydawane polecenia za pomocą narzędzia systemctl, będą ograniczały się do jednostki .service, przykładowo:

# systemctl enable [usługa.service]
# systemctl disable [usługa.service] 
# systemctl start [usługa.service]
# systemctl stop [usługa.service]
# systemctl restart [usługa.service]
# systemctl reload [usługa.service]
$ systemctl status [usługa.service]
# systemctl is-active [usługa.service] 
# systemctl is-enabled [usługa.service]  
$ systemctl list-units --type service --all

Aby uzyskać listę wszystkich jednostek systemd, które są usługami, można wydać polecenie

 systemctl list-units type=service

Systemctl ma wiele możliwości
systemctl list-units type=service

Systemd a poziomy pracy (runlevels)


Jak poziomy pracy systemu SysVinit mają się do nowych  'targets' systemd? Otóż można śmiało sporządzić pewną korelację:

runlevel0.target -> poweroff.target -> zamknięcie systemu
runlevel1.target -> rescue.target -> wiersz poleceń trybu rescue
runlevel2.target -> multi-user.target -> poziom multi-user bez grafiki
runlevel3.target -> multi-user.target -> poziom multi-user bez grafiki
runlevel4.target -> multi-user.target -> poziom multi-user bez grafiki
runlevel5.target -> graphical.target -> poziom multi-user w trybie graficznym
runlevel6.target -> reboot.target -> zamknięcie i restart systemu

Teoretycznie wycofane z obiegu, lecz wciąż działające w systemd polecenie runlevel, może być pewnym odpowiednikiem polecenia systemctl list-units --type=target jeżeli chodzi o uzyskanie informacji o bieżącym poziomie startu systemu. W systemd, jak pisałem wyżej, pojęcie poziomu pracy zostało zastąpione pojęciem grup jednostek (target):


[root@filemon1 ~]# runlevel
N 3
[root@filemon1 ~]# systemctl list-units --type=target
UNIT                LOAD   ACTIVE SUB    DESCRIPTION
basic.target        loaded active active Basic System
cryptsetup.target   loaded active active Encrypted Volumes
getty.target        loaded active active Login Prompts
local-fs-pre.target loaded active active Local File Systems (Pre)
local-fs.target     loaded active active Local File Systems
multi-user.target   loaded active active Multi-User System
network.target      loaded active active Network
nss-lookup.target   loaded active active Host and Network Name Lookups
paths.target        loaded active active Paths
remote-fs.target    loaded active active Remote File Systems
slices.target       loaded active active Slices
sockets.target      loaded active active Sockets
swap.target         loaded active active Swap
sysinit.target      loaded active active System Initialization
timers.target       loaded active active Timers

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.

15 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.

W celu zusykania informacji o usługach i innych jednostkach systemd, które są uruchamiane w określonej grupie jednostek (target) można wydać polecenie systemctl z odpowiednimi opcjami:

[root@filemon1 ~]#  systemctl show -p "Wants" multi-user.target
Wants=systemd-readahead-replay.service systemd-readahead-collect.service remote-fs.target crond.service kdump.service avahi-daemon.service libstoragemgmt.service

Zdalne administrowanie


Bardzo fajną sprawą jest to, że systemd pozwala na zdalną administrację innymi systemami w sieci, pod warunkiem, że są one wyposażone w systemd. Jeżeli mamy dostęp do konta root na zdalnej maszynie, możemy wykonywać sporą ilość zadań posługując się bezpośrednio komendą systemctl:

[root@filemon1 ~]# systemctl -H root@filemon2.mydomain.com status httpd.service
root@server-01.example.com's password:
httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled)
   Active: active (running) since Fri 2013-11-01 13:58:56 CET; 2h 48min ago
 Main PID: 649
   Status: "Total requests: 0; Current requests/sec: 0; Current traffic:   0 B/sec"

Warunkiem, jest jednak to, aby zdalny system był 'uzbrojony' w systemd, w przeciwnym razie próba połączenia zakończy się mniej więcej tak:

[root@filemon1 ~]# systemctl -H root@filemon3.mydomain.com status httpd.service
root@192.168.0.7's password:
bash: systemd-stdio-bridge: command not found
Failed to get D-Bus connection: Connection terminated during authentication.

Ogromne możliwości systemd

 

Systemd jest naprawdę innowacyjnym i dobrze opracowanym rozwiązaniem, które oferuje wiele ciekawych narzędzi. Wbrew pozorom, uproszczono i dopracowano wiele kwestii. Dokładne przeczytanie manuali oraz przetestowanie opcji i przykładów pozwoli rozjaśnić wszelkie wątpliwości średnio zaawansowanemu użytkownikowi w przeciągu jednej, maksymalnie dwóch godzin.
Pełna dokumentacja systemu, z którą każdy zaawansowany użytkownik Linuksa powinien się obowiązkowo zapoznać, znajduje się w witrynie ArchWiki.




Brak komentarzy:

Prześlij komentarz