Когда вы загружаете компьютер, множество сообщений, прокручиваемых на консоли, отображают множество выполняемых автоматических процессов инициализации и конфигурирования. Иногда может возникнуть желание несколько изменить работу этого этапа, а значит, необходимо хорошо её понимать. Помочь в этом — назначение данного раздела.
В системах с BIOS сначала BIOS берет на себя управление компьютером, инициализирует контроллеры и аппаратное обеспечение, обнаруживает диски и соединяет всё воедино. Затем он просматривает Master Boot Record (MBR) первого диска в порядке загрузки и загружает сохранённый там код (первый этап). Затем этот код запускает второй этап и, наконец, исполняет загрузчик.
В отличие от BIOS, UEFI более сложный, он знает файловые системы и может читать таблицы разделов. Интерфейс выполняет поиск в системном хранилище раздела, помеченного определенным глобальным уникальным идентификатором (
GUID), который помечает его как
EFI System Partition (
ESP), где находятся загрузчики, менеджеры загрузки, оболочка UEFI и т.д. и запускает нужный загрузчик. Если включена безопасная загрузка, процесс загрузки проверит подлинность двоичных файлов EFI с помощью подписи (таким образом, в этом случае требуется
grub-efi-arch-signed). Спецификация UEFI также определяет поддержку загрузки в устаревшем режиме BIOS (legacy BIOS mode). Это называется
Compatibility Support Module (
CSM). Если CSM включен, он попытается загрузиться с MBR диска. Однако многие новые системы больше не поддерживают режим CSM.
В обоих случаях фактический загрузчик принимает управление на себя, находит либо связанный загрузчик, либо ядро на диске, загружает и выполняет его. Затем ядро инициализируется и начинает поиск и монтирование раздела, содержащего корневую файловую систему, и, наконец, запускает первую программу — init
. Зачастую эти «корневой раздел» и init
на самом деле находятся на виртуальной файловой системе, существующей только в ОЗУ (отсюда её название — initramfs, ранее — initrd, от "initialization RAM disk"). Эта файловая система загружается в память загрузчиком, часто из файла на жёстком диске или по сети. Он содержит самый минимум, необходимый для того, чтобы ядро загрузило «настоящую» корневую файловую систему: сюда могут входить модули драйверов для жёсткого диска или других устройств, без которых система не способна загрузиться, или, чаще, сценарии инициализации и модули для сборки массивов RAID, открытия зашифрованных разделов, активации томов LVM и т. п. Когда корневой раздел примонтирован, initramfs передаёт управление настоящему процессу "init", и система возвращается к стандартному процессу загрузки.
9.1.1. Система инициализации systemd
«Настоящий init» сейчас предоставляется системой systemd, и в данном разделе описывается эта система инициализации.
Systemd запускает несколько процессов для настройки клавиатуры, драйверов, файловых систем, сети, служб. При этом сохраняется глобальное представление о системе в целом и требованиях к её компонентам, каждый из которых описан в “unit file” (иногда в нескольких). Синтаксис заимствован из «*.ini файлов» с парами «ключ = значение» — key = value
, разделёнными заголовками [section]
. Unit-файлы хранятся в каталогах /lib/systemd/system/
и /etc/systemd/system/
. Далее будут описаны типы unit «сервис» — service и «цель» — target.
systemd файл “.service
file” описывает процесс, управляемый systemd. Он содержит примерно ту же информацию, что и init-скрипты старого стиля, но выраженную в декларативном (и гораздо более кратком) виде. Systemd берет на себя основную часть повторяющихся задач (запуск и остановка процесса, проверка его статуса, ведение журнала, удаление привилегий и т. д.), а служебный файл должен лишь заполнить специфику процесса. Например, вот служебный файл для SSH:
[Unit]
Description=OpenBSD Secure Shell server
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run
[Service]
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
Alias=sshd.service
Раздел [Unit]
содержит общую информацию о сервисе, такую как его описание и ресурсы страницы руководства, а также связи (зависимость и порядок) с другими сервисами. Часть [Service]
содержит объявления, относящиеся к выполнению службы (запуск, остановка, уничтожение, перезапуск), используемые каталоги и файлы конфигурации. Последний раздел [Install]
снова содержит общую информацию, в какую цель устанавливать службу, и, в данном случае, псевдоним, который можно использовать вместо имени службы. Как видите, кода там очень мало, только объявления. Systemd отображает отчеты о ходе работы, отслеживает процессы и даже перезапускает их при необходимости. Синтаксис этих файлов полностью описан на нескольких страницах руководства (например, systemd.service(5), systemd.unit(5), systemd.exec(5), и т.д.).
Файл «цели» “.target
file” в systemd описывает состояние системы, при котором известно, что набор служб работает. Его можно рассматривать как эквивалент уровня запуска старого стиля. Одной из заранее определенных целей является — local-fs.target
; при её достижении остальная система может рассчитывать, что все локальные файловые системы смонтированы и доступны. В число других целей входят network-online.target
и sound.target
(полный список специальных целей см. systemd.special(7)). Зависимости цели могут быть перечислены либо внутри целевого файла (в строке 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
. Первая программа, которая выполняется (что соответствует шагу sysinit) это /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 new-level
. 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 пользователь
, чтобы начать сессию.