Linux: SysV, Upstart и Systemd — runlevels и общие сведения

Автор: | 05/05/2016
 

linux_logoВ течении многих лет в подавляющем большинстве 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 3RHEL/CentOS — многопользовательский режим с поддержкой сети
  • level 4: не используется
  • level 5RHEL/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 можно представить так:

linux_systemd_1

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
│ ├─ifup@enp0s3.service
│ │ └─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

man/systemd

How To Use Systemctl to Manage Systemd Services and Units

Working with systemd targets

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

Debian RunLevel

Linux: определить init систему – Systemd vs Upstart