При загрузке компьютера множество сообщений, пробегающих на консоли, отображает выполнение многочисленных автоматических начальных инициализаций и настроек. Иногда может возникнуть желание несколько изменить работу этого этапа, а значит, необходимо хорошо её понимать. Помочь в этом — назначение данного раздела.
Сначала BIOS получает контроль над компьютером, определяет диски, считывает главную загрузочную запись и запускает загрузчик. Загрузчик принимает управление, находит ядро на диске, считывает и запускает его. Затем ядро инициализируется и начинает поиск и монтирование корневой файловой системы и, наконец, запускает первую программу — init
. Зачастую эти «корневой раздел» и init
на самом деле находятся на виртуальной файловой системе, существующей только в ОЗУ (отсюда её название — initramfs, ранее — initrd, от "initialization RAM disk"). Эта файловая система загружается в память загрузчиком, часто из файла на жёстком диске или по сети. Он содержит самый минимум, необходимый для того, чтобы ядро загрузило «настоящую» корневую файловую систему: сюда могут входить модуля ядра для жёсткого диска или других устройств, без которых система не способна загрузиться, или, чаще, сценарии инициализации и модули для сборки массивов RAID, открытия зашифрованных разделов, активации томов LVM и т. п. Когда корневой раздел примонтирован, initramfs передаёт управление настоящему процессу "init", и система возвращается к стандартному процессу загрузки.
9.1.1. Система инициализации systemd
«Настоящий init» сейчас предоставляется systemd, и в данном разделе описывается эта система инициализации.
Systemd запускает несколько процессов для настройки клавиатуры, драйверов, файловых систем, сети, служб. Также соблюдаются требования для всех компонентов системы, каждый из которых описан в «файле элемента» — unit (иногда требуется более одного файла). Синтаксис заимствован из «*.ini файлов» с парами «ключ = значение» — key = value
, разделёнными заголовками [section]
. Unit-файлы хранятся в каталогах /lib/systemd/system/
и /etc/systemd/system/
. Далее будут описаны типы unit «сервис» — service и «цель» — target.
Файл service описывает процесс systemd. Он содержит ту же информацию, что и прежние init-сценарии, но она описана в декларативном (и сжатом) стиле. Systemd обслуживает повторяющиеся задачи (старт и остановка процесса, проверка его статуса, журнал, привилегии и т . п.) и файл service должен быть наполнен конкретикой, относящейся к процессу. Например для SSH, он выглядит так:
[Unit]
Description=OpenBSD Secure Shell server
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run
[Service]
EnvironmentFile=-/etc/default/ssh
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
[Install]
WantedBy=multi-user.target
Alias=sshd.service
Как видно из примера, кода очень мало, только объявления. Также systemd описывает ход процесса, отслеживает их выполнение и даже перезапускает, если необходимо.
Файл «цели» в systemd описывает состояние системы, когда функционирует некоторый набор сервисов. Его можно рассматривать как эквивалент уровня запуска. Одна из целей — local-fs.target
; при её достижении остальная система может рассчитывать, что все локальные файловые системы смонтированы и доступны. В число других целей входят network-online.target
и sound.target
. Зависимости цели могут быть указаны как внутри файла target (в строке Requires=
), так и с использованием символьной ссылки на файл service в каталоге /lib/systemd/system/targetname.target.wants/
. Например /etc/systemd/system/printer.target.wants/
cодержит ссылку на /lib/systemd/system/cups.service
, поэтому systemd запустит CUPS для достижения цели printer.target
.
Так как файлы unit декларативны, в отличие от сценарием и программ, они не могут запускаться отдельно и интерпретируются только systemd, хотя несмотря на это, несколько вспомогательных программ позволяют администратору взаимодействовать с systemd, контролировать состояние системы и отдельных компонентов.
Первая из них — systemctl
. При запуске без параметров, выводится список всех unit-файлов, известных системе (за исключением отключенных) и их статус. systemctl status
дает лучший обзор сервисов и связанных процессов. Выводится имя файла service (как в systemctl status ntp.service
), также дополнительная информация и последние несколько строчек из журнала, касающиеся этого процесса (позднее про это будет сказано более подробно).
Для запуска сервиса вручную, нужно просто набрать systemctl start servicename.service
. Как можно догадаться, для остановки: systemctl stop servicename.service
. Есть другие подкоманды: reload
и restart
.
Для контроля за активность сервиса (запускается при загрузки системы или нет), нужно использовать systemctl enable servicename.service
(или disable
). Для проверки запущен ли сервис — is-enabled
.
Интересная особенность systemd состоит в журнале journald
. Он идет как дополнение к традиционному syslogd
, но содержит особенности, как например формальная ссылка между сервисом и сообщением, им создаваемом при процедуре инициализации. Сообщения можно посмотреть с помощью journalctl
. Без аргументов, выводится журнал сообщений, создаваемый при загрузке системы, однако в большинстве случаев команда используется с идентификатором сервиса:
#
journalctl -u ssh.service
-- Logs begin at Tue 2015-03-31 10:08:49 CEST, end at Tue 2015-03-31 17:06:02 CEST. --
Mar 31 10:08:55 mirtuel sshd[430]: Server listening on 0.0.0.0 port 22.
Mar 31 10:08:55 mirtuel sshd[430]: Server listening on :: port 22.
Mar 31 10:09:00 mirtuel sshd[430]: Received SIGHUP; restarting.
Mar 31 10:09:00 mirtuel sshd[430]: Server listening on 0.0.0.0 port 22.
Mar 31 10:09:00 mirtuel sshd[430]: Server listening on :: port 22.
Mar 31 10:09:32 mirtuel sshd[1151]: Accepted password for roland from 192.168.1.129 port 53394 ssh2
Mar 31 10:09:32 mirtuel sshd[1151]: pam_unix(sshd:session): session opened for user roland by (uid=0)
Другой полезный флаг -f
используется с journalctl
для просмотра появления новых сообщений (похоже на tail -f file
).
Если сервис не работает как ожидалось, то первым делом нужно проверить его статус с systemctl status
, если проблема не решена, то проверьте его журнал. Допустим сервер SSH не работает:
#
systemctl status ssh.service
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled)
Active: failed (Result: start-limit) since Tue 2015-03-31 17:30:36 CEST; 1s ago
Process: 1023 ExecReload=/bin/kill -HUP $MAINPID (code=exited, status=0/SUCCESS)
Process: 1188 ExecStart=/usr/sbin/sshd -D $SSHD_OPTS (code=exited, status=255)
Main PID: 1188 (code=exited, status=255)
Mar 31 17:30:36 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:36 mirtuel systemd[1]: ssh.service start request repeated too quickly, refusing to start.
Mar 31 17:30:36 mirtuel systemd[1]: Failed to start OpenBSD Secure Shell server.
Mar 31 17:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
#
journalctl -u ssh.service
-- Logs begin at Tue 2015-03-31 17:29:27 CEST, end at Tue 2015-03-31 17:30:36 CEST. --
Mar 31 17:29:27 mirtuel sshd[424]: Server listening on 0.0.0.0 port 22.
Mar 31 17:29:27 mirtuel sshd[424]: Server listening on :: port 22.
Mar 31 17:29:29 mirtuel sshd[424]: Received SIGHUP; restarting.
Mar 31 17:29:29 mirtuel sshd[424]: Server listening on 0.0.0.0 port 22.
Mar 31 17:29:29 mirtuel sshd[424]: Server listening on :: port 22.
Mar 31 17:30:10 mirtuel sshd[1147]: Accepted password for roland from 192.168.1.129 port 38742 ssh2
Mar 31 17:30:10 mirtuel sshd[1147]: pam_unix(sshd:session): session opened for user roland by (uid=0)
Mar 31 17:30:35 mirtuel sshd[1180]: /etc/ssh/sshd_config line 28: unsupported option "yess".
Mar 31 17:30:35 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:35 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:35 mirtuel sshd[1182]: /etc/ssh/sshd_config line 28: unsupported option "yess".
Mar 31 17:30:35 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:35 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:35 mirtuel sshd[1184]: /etc/ssh/sshd_config line 28: unsupported option "yess".
Mar 31 17:30:35 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:35 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:36 mirtuel sshd[1186]: /etc/ssh/sshd_config line 28: unsupported option "yess".
Mar 31 17:30:36 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:36 mirtuel sshd[1188]: /etc/ssh/sshd_config line 28: unsupported option "yess".
Mar 31 17:30:36 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:36 mirtuel systemd[1]: ssh.service start request repeated too quickly, refusing to start.
Mar 31 17:30:36 mirtuel systemd[1]: Failed to start OpenBSD Secure Shell server.
Mar 31 17:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
#
vi /etc/ssh/sshd_config
#
systemctl start ssh.service
#
systemctl status ssh.service
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled)
Active: active (running) since Tue 2015-03-31 17:31:09 CEST; 2s ago
Process: 1023 ExecReload=/bin/kill -HUP $MAINPID (code=exited, status=0/SUCCESS)
Main PID: 1222 (sshd)
CGroup: /system.slice/ssh.service
└─1222 /usr/sbin/sshd -D
#
После проверки статуса (ошибка), был проверен журнал, была обнаружена ошибка в конфигурационном файле. После его редактирования и исправления ошибки, сервис запускается заново, далее проверяется его статус.
9.1.2. Система инициализации System V
Система инициализации System V (которую называют init для краткости), используя инструкции из файла
/etc/inittab
, запускает несколько процессов. Первая команда (относящаяся к шагу
sysvinit) — это сценарий
/etc/init.d/rcS
, который запускает все программы в каталоге
/etc/rcS.d/
.
Среди них можно найти последовательность программ, отвечающих за:
настройку клавиатуры в консоли;
загрузку драйверов: большая часть модулей ядра загружается самим ядром при обнаружении оборудования; дополнительные драйверы затем загружаются автоматически, если соответствующие модули указаны в /etc/modules
;
проверку целостности файловых систем;
монтирование локальных разделов;
настройку сети;
монтирование сетевых файловых систем (NFS).
Следом, init
запускает программы уровня запуска по умолчанию (обычно runlevel 2). Запускается сценарий /etc/init.d/rc 2
, который, в свою очередь, запускает сервисы, перечисленные в /etc/rc2.d/
. Названия файлов в каталоге начинаются с буквы «S», за которой идут две цифры, что определяет очерёдность запуска. В настоящее время, загрузочная система по умолчанию использует программу insserv
, которая автоматически всё организовывает, основываясь на зависимостях сценариев. Каждый сценарий объявляет условия, необходимые для его запуска и остановки (например, очерёдность по отношению к другим сценариям), init
запускает сценарии в соответствующей последовательности для удовлетворения зависимостей. Поэтому наименование сценариев больше не учитывается (хотя они всё еще должны начинаться с «S» и далее продолжаться двумя цифрами и названием сервиса, которое и используется для организации зависимостей). В общем, основные сервисы (как журналирование с rsyslog
или назначение портов с portmap
) запускаются в первую очередь, затем следуют стандартные сервисы и графический интерфейс (gdm3
).
Такая основанная на зависимостях система загрузки делает возможной автоматизацию смены нумерации, которая была бы весьма утомительной, если бы её приходилось выполнять вручную, и снижает риск человеческой ошибки, поскольку планирование выполняется в соответствии с формальными параметрами. Другим преимуществом является возможность параллельного запуска сервисов, независимых друг от друга, что может ускорить процесс загрузки.
init
различает несколько уровней запуска, так что она может переключаться с одного на другой при посредстве команды telinit новый-уровень
. init
сразу же запускает /etc/init.d/rc
заново с новым уровнем запуска. Этот сценарий после этого запускает недостающие сервисы и останавливает те, которые более не нужны. Для этого он руководствуется содержимым /etc/rcX.d
(где X означает новый уровень запуска). Сценарии, начинающиеся с «S» (как в слове «Start») — это сервисы, которые должны быть запущены; те, что начинаются с «K» (как в слове «Kill») — сервисы, которые должны быть остановлены. Сценарий не запускает никаких сервисов, которые уже были активированы на прежнем уровне запуска.
По умолчанию, System V init Debian использует четыре разных уровня запуска:
Уровень 0 используется только временно, при выключении питания компьютера. Поэтому он содержит только «K»-сценарии.
Уровень 1, также известный как однопользовательский режим, соответствует системе с урезанной функциональностью; он включает только основные сервисы и предназначается для операций по обслуживанию, когда взаимодействие с обычными пользователями нежелательно.
Уровень 2 — уровень для нормальной работы, включающий сетевые сервисы, графический интерфейс, вход пользователей и т. п.
Уровень 6 похож на уровень 0 с той разницей, что он используется во время остановки системы перед перезагрузкой.
Есть и другие уровни, в частности с 3 по 5. По умолчанию они настроены, чтобы работать точно так же, как уровень 2, но администратор может изменить их (путём добавления или удаления сценариев в соответствующие каталоги /etc/rcX.d
), чтобы приспособить их под свои специфические нужды.
Все сценарии, содержащиеся в различных каталогах /etc/rcX.d
на самом деле являются лишь символьными ссылками — созданными при установке пакета программой update-rc.d
— указывающими на сами сценарии, хранящиеся в /etc/init.d/
. Администратор может настроить доступность сервисов на каждом уровне запуска путём повторного запуска update-rc.d
с изменёнными параметрами. На странице руководства update-rc.d(8) подробно описан синтаксис. Обратите внимание, что удаление всех символьных ссылок (с помощью параметра remove
) — не лучший метод отключения сервиса. Вместо этого следует просто настроить, чтобы он не запускался на нужном уровне запуска (сохранив соответствующие вызовы для остановки его в случае, если сервис работал на предыдущем уровне запуска). Поскольку интерфейс update-rc.d
несколько запутанный, может оказаться более удобным использовать rcconf
(из пакета rcconf), интерфейс которой более дружествен к пользователю.
Наконец, init
запускает программу управления виртуальными консолями (getty
). Она выводит приглашение, ожидает ввода имени пользователя, а затем выполняет login пользователь
, чтобы начать сессию.