В течении многих лет в подавляющем большинстве Linux систем использовался менеджер инициализации sysvinit
(System V initialization). Затем, в 2006 (10 лет тому, OMG!) в Ubuntu, а затем и в CentOS пришла система Upstart (Ubuntu 6.10), а в 2010 – появилась система Systemd.
Содержание
SysV && Upstart
Назначение sysvinit
– запуск пространства пользователя: во время загрузки ядро запускает процесс с PID == 1 с именем init
, который запускает все остальные процессы и является их “родителем”:
$ pstree init─┬─ModemManager───2*[{ModemManager}] ├─NetworkManager─┬─2*[dhclient] │ ├─dnsmasq │ └─3*[{NetworkManager}] ├─accounts-daemon───2*[{accounts-daemon}] ├─acpid ├─bluetoothd ...
sysvinit
и upstart
запускают процессы по очереди, в зависимости от его runlevel:
# ls -l /etc/ | grep "rc[0-9].d" drwxr-xr-x 2 root root 4096 кві 29 11:59 rc0.d drwxr-xr-x 2 root root 4096 кві 29 11:59 rc1.d drwxr-xr-x 2 root root 4096 кві 29 11:59 rc2.d drwxr-xr-x 2 root root 4096 кві 29 11:59 rc3.d drwxr-xr-x 2 root root 4096 кві 29 11:59 rc4.d drwxr-xr-x 2 root root 4096 кві 29 11:59 rc5.d drwxr-xr-x 2 root root 4096 кві 29 11:59 rc6.d
В зависимости от операционной системы – назначение уровней может варьироваться, но в любой системе есть три общих уровня:
- level 0: выключение системы
- level 1: Single-user (resque) mode
- level 6: перезагрузка
Уровни 2-5:
- level 2: RHEL/CentOS – многопользовательский режим без поддержки сети, Debian/Ubuntu – ссылка на level 5 и загрузка полноценной системы
- level 3: RHEL/CentOS – многопользовательский режим с поддержкой сети
- level 4: не используется
- level 5: RHEL/CentOS – многопользовательский режим с поддержкой сети и X-Windows системой
Затем менеджер проверяет зависимости запущенного процесса, ожидает его полного запуска – и только после этого переходят к запуску следующего процесса из списка init-файлов в /etc/rcN.d
, в зависимости от номера в имени скрипта:
# ls -l /etc/rc2.d/ total 4 -rw-r--r-- 1 root root 677 лют 17 06:59 README lrwxrwxrwx 1 root root 20 бер 9 10:23 S20kerneloops -> ../init.d/kerneloops lrwxrwxrwx 1 root root 15 бер 9 10:23 S20rsync -> ../init.d/rsync lrwxrwxrwx 1 root root 24 кві 1 11:28 S20screen-cleanup -> ../init.d/screen-cleanup ... lrwxrwxrwx 1 root root 18 бер 9 10:23 S99ondemand -> ../init.d/ondemand lrwxrwxrwx 1 root root 18 бер 9 10:23 S99rc.local -> ../init.d/rc.local
S99rc.local
будет выполняться последним, т.к. имеет самый большой номер – 99.
Из-за вынужденного ожидания запуска каждого демона во время загрузки – системы с SysV и Upstart загружались сравнительно долго.
Systemd
Для улучшения ситуации и улучшения управления зависимостями во время запуска служб – появилась система systemd
.
На самом деле, запускаемому демону не важно – запущен ли демон, о которого он зависит, или нет. Новому процессу достаточно получить доступ к Unix Domain Socket, что бы включиться в работу системы.
Сокеты являются частью IPC (Inter-process Communication), позволяющие процессам внутри системы “общаться” друг с другом.
Увидеть их можно с помощью netstat
, lsof
и т.п.:
# netstat -a --protocol=unix | head -n 5 Active UNIX domain sockets (servers and established) Proto RefCnt Flags Type State I-Node Path unix 2 [ ACC ] STREAM LISTENING 16763 @/tmp/.ICE-unix/2633 unix 2 [ ACC ] STREAM LISTENING 15724 /tmp/.X11-unix/X0 unix 2 [ ACC ] STREAM LISTENING 17454 /run/user/1000/keyring-bRTxOS/control ...
Таким образом – можно одним шагом создать все сокеты, а вторым – запустить демоны, которые эти сокеты используют. Все запросы к демону, который ещё не запущен – будут записаны в буфер сокета:
# sysctl net.core.rmem_max net.core.rmem_max = 212992 # sysctl net.core.wmem_max net.core.wmem_max = 212992
и переданы демону после его запуска.
Ещё один недостаток sysvinit
– это необходимость всякий раз помнить о правильном порядке очеди запуска служб, например – выполнять запуск ntpd
после запуска самой сети. Кроме того – вам необходимо запускать все службы во время загрузки системы, так как после её старта – sysvinit
уходит в “спячку” и запускать службы вам придётся уже вручную.
Systemd
Общую схему работы systemd
можно представить так:
systemd
использует “агрессивную параллелизацию”, используя сокеты и D-Bus для запуска сервисов, имеет возможность запуска служб по требованию, контролирует процессы с помощью cgroups
, поддерживает создание снимков системы, работает с монтированием дисков и так далее.
В отличии от SysV – в Systemd нет понятия “runlevel“, а вместо этого используются концепция “целей” (targets).
Такие target-ы всегда имеют расширение .target
, и единственное их предназначениие – группровка различных юнитов, через цепочку зависимостей.
Например – юнит graphical.target
, который используется для запуска графической сессии, запускает такие сервисы как GNOME DM (gdm.server
) или службу учётных записей (accounts-daemon.service
) и активирует юнит multi-user.target
. Аналогично – multi-user.target
юнит запускает другие необходимые службы, такие как NetworkManager (NetworkManager.service
) или D-Bus (dbus.service
) и активирует юнит basic.target
.
Для сравнения SystmV/Upstart и Systemd – можно использовать такую таблицу:
Runlevel | Target Units | Description |
---|---|---|
0 |
runlevel0.target , poweroff.target |
Shut down and power off the system. |
1 |
runlevel1.target , rescue.target |
Set up a rescue shell. |
2 |
runlevel2.target , multi-user.target |
Set up a non-graphical multi-user system. |
3 |
runlevel3.target , multi-user.target |
Set up a non-graphical multi-user system. |
4 |
runlevel4.target , multi-user.target |
Set up a non-graphical multi-user system. |
5 |
runlevel5.target , graphical.target |
Set up a graphical multi-user system. |
6 |
runlevel6.target , reboot.target |
Shut down and reboot the system. |
Пример graphical.target
из Ubuntu 16:
$ cat /lib/systemd/system/graphical.target # This file is part of systemd. # # systemd is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. [Unit] Description=Graphical Interface Documentation=man:systemd.special(7) Requires=multi-user.target Wants=display-manager.service Conflicts=rescue.service rescue.target After=multi-user.target rescue.service rescue.target display-manager.service AllowIsolate=yes
Systemd использует несколько каталогов для файлов конфигурации и юнит-файлов.
Для Ubuntu 16 это:
/etc/systemd/system
и/etc/systemd/user
– локальные файлы конфигурации/lib/systemd/system
и/usr/lib/systemd/user
– файлы юнитов установленных приложений
Про создание файлов юнитов и добавление служб к автозапуску – в другом посте.
Что бы просмотреть все зависимости отдельного юнита – используйте list-dependencies
[service name], например:
# systemctl list-dependencies multi-user.target multi-user.target ● ├─console-setup.service ● ├─cron.service ● ├─dbus.service ● ├─grub-common.service ● ├─irqbalance.service ● ├─networking.service ● ├─nginx.service ...
cgroups
cgroups
(Control groups) появился в 2009 году, однако широкое распространение получил только с появлением systemd
.
Из документации:
“Control groups предоставляют механизм для объединения/разделения наборов задач (процессов) и их потомков в иерархические группы с определённым поведением”.
Другими словами – cgroups
имеет возможность управлять, ограничивать и выделять ресурсы различными способами. cgroups
активно используется systemd
для работы с таргетами.
Для просмотра таких групп – используйте systemd-cgls
:
# systemd-cgls Control group /: -.slice ├─init.scope │ └─1 /sbin/init ├─system.slice │ ├─dbus.service │ │ └─520 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation │ ├─cron.service │ │ └─499 /usr/sbin/cron -f │ ├─lvm2-lvmetad.service │ │ └─280 /sbin/lvmetad -f │ ├─[email protected] │ │ └─712 /sbin/dhclient -1 -v -pf /run/dhclient.enp0s3.pid -lf /var/lib/dhcp/dhclient.enp0s3.leases -I -df /var/lib/dhcp/dhclient6.enp0s3.leases enp0s3 │ ├─nginx.service │ │ ├─19893 nginx: master process /usr/sbin/nginx -g daemon on; master_process on │ │ └─19894 nginx: worker process │ ├─accounts-daemon.service │ │ └─506 /usr/lib/accountsservice/accounts-daemon │ ├─systemd-journald.service ...
Либо – ps
:
# ps xawf -eo pid,user,cgroup,args PID USER CGROUP COMMAND 2 root - [kthreadd] 3 root - \_ [ksoftirqd/0] ... 520 message+ 8:pids:/system.slice/dbus.s /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation 712 root 8:pids:/system.slice/ifup@e /sbin/dhclient -1 -v -pf /run/dhclient.enp0s3.pid -lf /var/lib/dhcp/dhclient.enp0s3.leases -I -df /var/lib/dhcp/dhclient6.enp0s3.leases enp0s3 740 root 8:pids:/system.slice/ssh.se /usr/sbin/sshd -D 19210 root 8:pids:/user.slice/user-900 \_ sshd: vagrant [priv] 19236 vagrant 8:pids:/user.slice/user-900 | \_ sshd: vagrant@pts/0 19237 vagrant 8:pids:/user.slice/user-900 | \_ -bash 19333 root 8:pids:/user.slice/user-900 | \_ sudo -s 19334 root 8:pids:/user.slice/user-900 | \_ /bin/bash 20088 root 8:pids:/user.slice/user-900 | \_ ps xawf -eo pid,user,cgroup,args 19393 root 8:pids:/user.slice/user-900 \_ sshd: vagrant [priv] 19414 vagrant 8:pids:/user.slice/user-900 \_ sshd: vagrant@pts/1 19415 vagrant 8:pids:/user.slice/user-900 \_ -bash 755 root 8:pids:/system.slice/system /sbin/agetty --noclear tty1 linux 762 ntp 8:pids:/system.slice/ntp.se /usr/sbin/ntpd -p /var/run/ntpd.pid -g -u 108:114 787 root 8:pids:/system.slice/vboxad /usr/sbin/VBoxService --pidfile /var/run/vboxadd-service.pid 19212 vagrant 8:pids:/user.slice/user-900 /lib/systemd/systemd --user 19217 vagrant 8:pids:/user.slice/user-900 \_ (sd-pam) 19893 root 8:pids:/system.slice/nginx. nginx: master process /usr/sbin/nginx -g daemon on; master_process on; 19894 www-data 8:pids:/system.slice/nginx. \_ nginx: worker process
Что бы определить таргет, который запускается по умолчанию – используйте get-default
:
$ systemctl get-default graphical.target
Это команада использует файл /lib/systemd/system/default.target
(/etc/systemd/system/default.target
в RHEL/CentOS), который является симлинком на юнит-файл таргета, который будет запущен:
# ls -l /lib/systemd/system/default.target lrwxrwxrwx 1 root root 16 Apr 25 11:56 /lib/systemd/system/default.target -> graphical.target
Отобразить все загруженные в данный момент таргеты:
# 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 ... sysinit.target loaded active active System Initialization time-sync.target loaded active active System Time Synchronized 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. 19 loaded units listed. Pass --all to see loaded but inactive units, too. To show all installed unit files use 'systemctl list-unit-files'.
По умолчанию – тут отображатся только активные таргеты. Что бы вывести все – добавьте --all
:
# systemctl list-units --type target --all
Для перевода системы в однопользовательский режим (Resque mode) – выполните:
# systemctl rescue
Она аналогична команде:
# systemctl isolate rescue.target
однако дополнительно отрпавляет сообщение всем активным пользователям системы.
Для перевода системы в Emergency mode – выполните:
# systemctl emergency
В Emergency mode – система монтирует /
в режим только чтение и оставляет минимально необходимый набор служб.
Ссылки по теме
How do I change the target (runlevel)?
systemd/ FrequentlyAskedQuestions
Understanding Systemd Units and Unit Files
How To Use Systemctl to Manage Systemd Services and Units
systemd for Administrators // must read!
Documentation/cgroups/cpusets.txt
Intro to Systemd Runlevels and Service Management Commands
Here We Go Again, Another Linux Init: Intro to systemd
Understanding and Using Systemd
Learn Linux, 101: Runlevels, shutdown, and reboot
Linux: определить init систему – Systemd vs Upstart