====== Глава 6: Запуск пользовательского пространства ====== Пользовательское пространство запускается в следующем порядке: - Процесс init. - Основные службы низшего уровня, такие как udevd и syslogd. - Конфигурация сети. - Службы среднего и высокого уровня (cron, print и т.д.). - Приглашения для входа в систему, графические интерфейсы и приложения высокого уровня, такие как веб-серверы. ===== 6.1 Основные сведения об init ===== **init** (инициализация) - программа пользовательского пространства, расположенная в /sbin. Её основная цель - запускать и останавливать основные служебные процессы системы. Во всех актуальных версиях основных дистрибутивов Linux стандартной реализацией init является **systemd**. ==== Альтернативные системы init ==== В старых системах встречаются другие реализации: ^ Система ^ Описание ^ Использование ^ | **System V init** | Традиционная последовательная инициализация (Sys V из Unix System V) | RHEL до 7.0, Debian 8 | | **Upstart** | Реализация для дистрибутивов Ubuntu | Ubuntu до 15.04 | | **runit** | Облегченная система инициализации | Встроенные платформы и облегченные системы | | **Android init** | Собственная система инициализации | Android | | **BSD init** | Версия для BSD | Редко встречается в современных Linux системах | ==== Проблемы System V init ==== Система инициализации System V работает как **последовательная серия сценариев**, где каждый сценарий запускает одну службу или настраивает отдельную часть системы. Обычно зависимости разбираются просто, и система достаточно гибка для необычных задач. Однако существуют существенные ограничения: **Производительность:** * Две части последовательной загрузки не могут выполняться одновременно **Управление системой:** * Сложность поиска PID демона службы (требуется ps или механизм, специфичный для службы) * Полустандартная система записи PID (/var/run/myservice.pid) * Много стандартного шаблонного кода в сценариях **Конфигурация:** * Мало информации о службах и конфигурации по требованию * Большинство служб запускается только при загрузке * Конфигурация устанавливается в основном при загрузке * Традиционный демон inetd (для сетевых служб по требованию) уже не используется Современные системы инициализации (такие как systemd) решают эти проблемы путём изменения способа запуска служб, порядка их контроля и настройки зависимостей. ===== 6.2 Определение системы инициализации ===== Определить версию инициализации можно, проверив наличие определённых файлов и каталогов: **systemd:** * Наличие каталогов /usr/lib/systemd и /etc/systemd **Upstart:** * Наличие каталога /etc/init с несколько файлами .conf * (Исключение: Debian 7 и старше используют System V init, несмотря на /etc/init) **System V init:** * Отсутствие вышеуказанных каталогов * Наличие файла /etc/inittab Информацию также можно получить из страницы руководства init(1). ===== 6.3 systemd ===== systemd - современная реализация init в Linux, интегрирующая функциональность Unix-служб (cron, inetd). Вдохновлена launchd от Apple. Основные отличия от традиционной init: * Расширенное управление службами * Отслеживание демонов после запуска * Группировка процессов службы * Ориентирована на выполнение задач и целей Система использует юниты (units) для задач, содержит инструкции запуска и зависимости. Активирует юниты по мере готовности, не придерживаясь жесткой последовательности. Реагирует на системные события (uevents). ==== 6.3.1 Юниты и типы юнитов ==== systemd управляет не только процессами/службами, но и монтированием ФС, запросами подключения сети, таймерами. ^ Тип юнита ^ Описание ^ | Service units | Управление служебными демонами Unix | | Target units | Управление другими юнитами, группировка | | Socket units | Местоположение запросов входящих сетевых подключений | | Mount units | Контроль присоединения файловых систем | **Примечание:** полный список типов см. systemd(1) ==== 6.3.2 Графики загрузки и зависимостей юнитов ==== При загрузке активируется целевой юнит **default.target**, объединяющий юниты служб и монтирования как зависимости. Зависимости образуют граф (не дерево). Юниты могут зависеть от нескольких предыдущих. Визуализировать граф: `systemd-analyze dot` (требует фильтрации для сложных систем). **Примечание:** В большинстве систем default.target → целевой юнит высокого уровня (графический интерфейс и т.д.) ==== 6.3.3 Конфигурация systemd ==== **Основные каталоги:** ^ Каталог ^ Назначение ^ | /lib/systemd/system или /usr/lib/systemd/system | Системные юниты (глобальная конфигурация) | | /etc/systemd/system | Локальная конфигурация | **Правило:** не изменяйте системные юниты (сохраняет дистрибутив), вносите изменения в /etc/systemd/system. **Проверка пути поиска:** systemctl -p UnitPath show pkg-config systemd --variable=systemdsystemunitdir pkg-config systemd --variable=systemdsystemconfdir === Юнит-файлы === Формат из спецификации XDG Desktop Entries (.ini подобный) с секциями в квадратных скобках и переменными. Пример dbus-daemon.service: [Unit] Description=D-Bus System Message Bus Documentation=man:dbus-daemon(1) Requires=dbus.socket RefuseManualStart=yes [Service] ExecStart=/usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only ExecReload=/usr/bin/dbus-send --print-reply --system --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig **[Unit]** - описание, информация о зависимостях **[Service]** - подготовка, запуск, перезагрузка службы === Переменные === Синтаксис: `$ПЕРЕМЕННАЯ` Пример (sshd.service): [Service] EnvironmentFile=/etc/sysconfig/sshd ExecStartPre=/usr/sbin/sshd-keygen ExecStart=/usr/sbin/sshd -D $OPTIONS $CRYPTO_POLICY ExecReload=/bin/kill -HUP $MAINPID * **$OPTIONS, $CRYPTO_POLICY** - из EnvironmentFile * **$MAINPID** - PID отслеживаемого процесса === Спецификаторы === Синтаксис: `%спецификатор` * **%n** - имя текущего юнита * **%H** - имя хоста * **%I, %i** - имя экземпляра (для юнитов с @) Пример: getty@.service → getty@tty1, getty@tty2 (динамическое создание). Полный список см. systemd.unit(5) ===== 6.3.4 Процесс работы systemd ===== systemctl - основная команда для управления systemd юнитами. ==== Основные команды ==== ^ Операция ^ Команда ^ Описание ^ | Список активных юнитов | systemctl list-units | Вывод сокращен; используйте --full для полных имен | | Все юниты | systemctl list-units --all | Включает неактивные юниты | | Статус юнита | systemctl status | Показывает статус, PID, cgroup, журнал | | Запуск | systemctl start | Активация юнита | | Остановка | systemctl stop | Деактивация юнита | | Перезапуск | systemctl restart | Перезапуск юнита | | Перезагрузка конфига | systemctl reload | Перезагрузка только для данного юнита | | Перезагрузка всех | systemctl daemon-reload | Перезагрузка всех конфигураций | | Текущие задания | systemctl list-jobs | Список активных заданий (изменений состояния) | | Журнал юнита | journalctl --unit= | Все сообщения журнала | ==== Пример просмотра статуса ==== $ systemctl status sshd.service Вывод содержит: статус загрузки, состояние (active/inactive), основной процесс (Main PID), контрольную группу (cgroup) и сообщения журнала. ==== Добавление юнита ==== Размещайте юнит-файлы в **/etc/systemd/system** (не перезаписываются при обновлении дистрибутива). # Создать файл /etc/systemd/system/test1.target [Unit] Description=test 1 # Создать файл /etc/systemd/system/test2.target с зависимостью [Unit] Description=test 2 Wants=test1.target # Активировать systemctl start test2.target # Если есть секция [Install], включить перед активацией systemctl enable test2.target ==== Удаление юнита ==== # 1. Деактивировать systemctl stop # 2. Отключить (если есть [Install]) systemctl disable # 3. Удалить юнит-файл **Примечание:** Задания (jobs) - это изменения состояния юнитов, не путать с заданиями оболочки. Требуются права суперпользователя для некоторых операций. ==== 6.3.5 Отслеживание и синхронизация процессов systemd ==== systemd использует **cgroups** (группы управления ядра Linux) для отслеживания иерархии процессов. Параметр **Type** в юнит-файле указывает поведение службы при запуске. ^ Type ^ Описание ^ | **simple** | Процесс не разветвляется, остается основным процессом | | **forking** | Процесс разветвляется; systemd ждет завершения исходного процесса | | **notify** | Служба отправляет уведомление systemd, когда готова | | **dbus** | Служба регистрируется на D-Bus, когда готова | | **oneshot** | Процесс полностью завершается после запуска; RemainAfterExit=yes по умолчанию | | **idle** | Как simple, но запуск отложен до завершения всех активных заданий | **Примечание:** Type=simple не известен время запуска; используйте Type=notify, Type=dbus или отложенный запуск (раздел 6.3.7) для синхронизации зависимых юнитов. ==== 6.3.6 Зависимости systemd ==== Гибкая система зависимостей требует баланса между строгостью и отказоустойчивостью. Слишком строгие правила могут заблокировать доступ при сбое некритичного сервиса. systemd предлагает несколько типов зависимостей для гибкого управления: ^ Тип ^ Описание ^ | **Requires** | Строгие зависимости. При сбое зависимости юнит также отключается. | | **Wants** | Зависимости только для активации. Сбой зависимости не влияет на юнит. Рекомендуется использовать по возможности. | | **Requisite** | Юниты, которые уже должны быть активны. Если не активны, юнит не запустится. | | **Conflicts** | Отрицательные зависимости. При активации юнита противоположная зависимость деактивируется. | Просмотр зависимостей: systemctl show -p type unit === Порядок выполнения юнитов === По умолчанию юниты с Requires и Wants запускаются одновременно. Для упорядочивания используйте: * **Before** - текущий юнит активируется раньше перечисленных * **After** - текущий юнит активируется после перечисленных systemd ждет активного статуса юнита перед активацией зависимостей. === Зависимости по умолчанию === systemd автоматически добавляет зависимость After к Wants-зависимостям. Эти неявные зависимости вычисляются во время загрузки и не сохраняются в файлах конфигурации. Отключить зависимости по умолчанию: DefaultDependencies=no === Условные зависимости === Для проверки состояния системы: * **ConditionPathExists=p** - путь существует * **ConditionPathIsDirectory=p** - путь является каталогом * **ConditionFileNotEmpty=p** - файл существует и не пуст При ложном условии юнит не активируется, но другие зависимости активируются независимо от условия. === Секция [Install] и включение юнитов === Раздел [Install] позволяет указывать зависимости в обратном порядке без изменения дополнительных файлов. Используйте **WantedBy** или **RequiredBy**. Пример: **test1.target:** [Unit] Description=test 1 [Install] WantedBy=test2.target **test2.target:** [Unit] Description=test 2 Включение юнита: systemctl enable test1.target # Создаст: /etc/systemd/system/test2.target.wants/test1.target Отключение юнита: systemctl disable test1.target **Важно:** включение юнита не активирует его. Юнит с разделом [Install] считается отключенным по умолчанию и включается после перезагрузки. Каталоги .wants и .require в /etc/systemd/system обычно управляются разделом [Install], но можно добавлять символические ссылки вручную для временных зависимостей без редактирования системных файлов юнитов. ==== 6.3.7 Запуск по запросу и параллелизация ресурсов в systemd ==== systemd позволяет откладывать запуск юнита до момента, когда на него поступит запрос. Процесс: 1. Создается юнит systemd для сервиса (Unit A) 2. Определяется ресурс (сокет, файл, устройство) 3. Создается юнит ресурса (Unit R): .socket, .path или .device 4. systemd мониторит ресурс и активирует Unit A при обращении При обращении к ресурсу: 1. systemd блокирует ресурс и буферизует входные данные 2. Активирует Unit A 3. Unit A берет управление ресурсом и обрабатывает буферизованные данные **Важные замечания:** * Юнит ресурсов должен охватывать все точки доступа сервиса * Связь между юнитами может быть неявной (по имени) или явной (параметр Socket=) * Не все серверы поддерживают взаимодействие с юнитами ресурсов === Пример: сокет-юнит и служебный юнит === Echo-сервис на TCP-порту 22222. **echo.socket:** [Unit] Description=echo socket [Socket] ListenStream=22222 Accept=true **echo@.service:** [Unit] Description=echo service [Service] ExecStart=/bin/cat StandardInput=socket Запуск: systemctl start echo.socket telnet localhost 22222 Остановка: systemctl stop echo.socket === Экземпляры и передача управления === Символ @ в имени echo@.service означает параллельные экземпляры. При **Accept=true** в сокет-юните systemd принимает входящие соединения и создает отдельный экземпляр для каждого. Каждый экземпляр считывает данные как стандартный ввод. Если сервис может самостоятельно принимать соединения, исключите @ из имени и не устанавливайте Accept=true. Сервис получит полный контроль над сокетом. Документация: systemd.socket(5), systemd.path(5), systemd.device(5), systemd.exec(5) === Оптимизация загрузки с помощью юнитов ресурсов === Юниты ресурсов ускоряют загрузку путем параллельной активации: ^ Последовательный запуск ^ Параллельный запуск с юнитом ресурса ^ | Служба E (ресурс R) запускается | Юнит R активируется немедленно | | Службы A, B, C ждут E | Службы A, B, C, E стартуют параллельно | | Долгое время загрузки | Быстрая загрузка, E берет управление когда готова | systemd предоставляет интерфейс юнита ресурса (R) еще до полной активации служебного юнита (E). Это позволяет зависимым юнитам (A, B, C) стартовать параллельно, а не ждать E. **Побочный эффект:** Одновременный запуск многих юнитов может временно замедлить систему. **Пример:** journald и D-Bus обычно загружаются параллельно этим способом. ==== 6.3.8 Вспомогательные компоненты systemd ==== systemd включает поддержку задач управления системой, помимо запуска и управления сервисами. Исполняемые файлы расположены в /lib/systemd и имеют префикс **systemd-**. ^ Служба ^ Назначение ^ | **udevd** | Управление устройствами (см. Глава 3) | | **journald** | Служба логирования; обрабатывает различные механизмы, включая syslog (см. Глава 7) | | **resolved** | Демон кэширования DNS (см. Глава 9) | **Примеры программ:** * systemd-udevd (интегрированный в systemd demон udevd) * systemd-fsck (простая обертка для стандартных системных утилит) Некоторые программы в /lib/systemd - обычные обертки, запускающие стандартные утилиты и уведомляющие systemd о результатах. **Справка:** Неизвестную программу в /lib/systemd можно найти в man-страницах, где описаны и утилита, и соответствующий ей тип юнита. ===== 6.4. Уровни выполнения в System V ===== System V init использует **уровни выполнения** (runlevel) для определения состояния машины - число от 0 до 6. Проверить текущий уровень: who -r Выход: ''run-level 5 2019-01-27 16:43'' Уровни выполнения различают состояния: запуск, выключение, однопользовательский режим, консоль. Например, 2–4 - текстовая консоль, 5 - графический интерфейс. **Примечание:** systemd поддерживает уровни выполнения как устаревшие, предпочитая им целевые юниты. ===== 6.5. System V init ===== System V init - одна из старейших систем инициализации Linux. Устанавливается редко (встречается в RHEL < 7.0, встроенных системах), но пакеты могут содержать её сценарии, совместимые с systemd. Состоит из: * Конфигурационный файл: ''**/etc/inittab**'' * Сценарии загрузки и символические ссылки ^ Файл ^ Содержимое ^ | /etc/inittab | Четыре поля: идентификатор : уровни выполнения : действие : команда | | /etc/rc.d/rc | Запускает программы из rc*.d в числовом порядке | | /etc/rc*.d | Каталоги со сценариями (rc1.d, rc2.d и т.д.) | **Пример строки inittab:** id:5:initdefault: l5:5:wait:/etc/rc.d/rc 5 ^ Действие ^ Назначение ^ | **initdefault** | Уровень выполнения по умолчанию | | **wait** | Выполнить команду один раз при входе на уровень, ждать завершения | | **respawn** | Перезапустить команду при выходе (например, getty для виртуальных консолей) | | **ctrlaltdel** | Действие при нажатии Ctrl+Alt+Del (обычно shutdown) | | **sysinit** | Первое действие при запуске, до всех уровней выполнения | ==== 6.5.1. System V init: последовательность команд при запуске ==== Команда ''rc 5'' запускает сценарии из ''/etc/rc5.d'': * **S** (Start) - выполнить с аргументом ''start'' * **K** (Kill) - выполнить с аргументом ''stop'' * **Числа 00–99** - порядок выполнения **Пример каталога rc5.d:** S10sysklogd S20ppp S99gpm S12kerneld S25netstd_nfs S99httpd S15netstd_init S30netstd_misc S99rmnologin Команда rc выполняет их последовательно: S10sysklogd start S12kerneld start S15netstd_init start ... S99sshd start Сценарии оболочки запускают программы из ''/sbin'' или ''/usr/sbin''. Для редактирования используйте ''less'' или аналогичные программы. ==== 6.5.2. Ферма ссылок System V init ==== Содержимое rc*.d - **символические ссылки** на файлы в ''/etc/init.d'': lrwxrwxrwx . . . S10sysklogd -> ../init.d/sysklogd lrwxrwxrwx . . . S12kerneld -> ../init.d/kerneld lrwxrwxrwx . . . S99httpd -> ../init.d/httpd Дистрибутивы используют эту **ферму ссылок (link farm)** для переиспользования одних сценариев на всех уровнях выполнения. === Запуск и остановка служб === /etc/init.d/httpd start # Запустить /etc/init.d/httpd stop # Остановить === Изменение последовательности загрузки === **Отключить службу без удаления:** mv S99httpd _S99httpd Префикс ''_'' заставит rc игнорировать ссылку. **Добавить службу:** скопируйте сценарий в init.d, создайте символическую ссылку в rc*.d. Несущественные службы - номера 90+, после основных систем. ==== 6.5.3. Команда run-parts ==== Утилита **run-parts** запускает все исполняемые программы в каталоге в определённом порядке. ^ Дистрибутив ^ Функции ^ | Fedora | Простая версия - запускает всё подряд | | Debian/Ubuntu | Сложная - фильтр по регулярным выражениям, передача аргументов | Используется в сценариях для массового запуска программ. Большинству пользователей детали неважны. ==== 6.5.4. Управление System V init ==== **telinit** - команда управления уровнями выполнения: ^ Команда ^ Действие ^ | ''telinit 3'' | Переключиться на уровень выполнения 3 | | ''telinit q'' | Перечитать ''/etc/inittab'' | | ''telinit s'' | Однопользовательский режим | **Предупреждение:** init завершит процессы, отсутствующие в inittab для нового уровня. ==== 6.5.5. Совместимость systemd и System V ==== systemd отслеживает System V сценарии: 1. Активирует ''.target'' (N - уровень выполнения) 2. Идентифицирует скрипты в ''/etc/rc.d'' 3. Связывает скрипт со служебным юнитом (''foo.service'') 4. Активирует юнит, запускает с аргументом start/stop 5. Связывает процессы со служебным юнитом **Результат:** можно использовать ''systemctl'' для управления, но режим совместимости всё равно запускает сценарии **последовательно**. ===== 6.6 Завершение работы системы ===== Используйте **shutdown** для корректного завершения: shutdown -h now # Остановить сейчас shutdown -r +10 # Перезагрузить через 10 минут ^ Параметр ^ Действие ^ | **-h** | Halt - остановка и отключение питания | | **-r** | Reboot - перезагрузка | | **now** | Немедленно | | **+n** | Через n минут | **Перед завершением:** shutdown создаёт ''/etc/nologin'' (запрет входа), уведомляет пользователей. === Процедура завершения === 1. init просит каждый процесс завершиться 2. Через время применяет сигнал TERM 3. Если не помогает - KILL для оставшихся процессов 4. Блокирует системные файлы 5. Демонтирует все FS кроме корневой 6. Ремонтирует корневую FS в режиме read-only 7. Синхронизирует буфер (sync) 8. Указывает ядру перезагрузиться/остановиться (reboot(2)) **halt/reboot:** вызывают shutdown, или если система уже на уровне выключения - сигналят ядру напрямую. Флаг **-f** (force) - быстрое выключение без проверок. ===== 6.7 Начальная файловая система оперативной памяти ===== **initramfs** - временное пользовательское пространство перед основной загрузкой. Решает проблему: **ядру нужны драйверы в виде модулей, но модули - это файлы, а FS не смонтирована.** === Как это работает === 1. Загрузчик загружает архив с модулями ядра в оперативную память 2. Ядро распаковывает архив во временную RAM-FS 3. Утилиты в initramfs загружают необходимые драйверы 4. Монтируют реальную корневую FS 5. Запускают полноценный init ^ Дистрибутив ^ Реализация ^ | Простые системы | Shell-скрипт, udev, монтирование корня | | systemd системы | Полная systemd без модулей, minimal udev config | === Отключение initramfs === Если все драйверы встроены в ядро - можно пропустить initramfs. Удалите строку ''initrd'' в GRUB (лучше через редактор меню, чем файл конфига). **Примечание:** современные ядра требуют initramfs для UUID-монтирования и других функций. === Содержимое initramfs === Распакуйте архив: unmkinitramfs /boot/initramfs-*.img . Старые системы использовали **cpio** архивы (см. cpio(1)). === Создание initramfs === Обычно создаётся автоматически дистрибутивом. Основные утилиты: * **mkinitramfs** - простая, распространённая * **dracut** - более мощная **Примечание:** термин initrd (initial RAM disk) - устаревший, использовал образ диска. Сейчас initramfs (cpio-архив) стандарт. Файлы конфига ещё содержат имя initrd. ===== 6.8 Аварийная загрузка системы и однопользовательский режим ===== При проблемах с системой используйте **live-образ** дистрибутива или SystemRescueCD на съёмном носителе. Live-образ - полная Linux, загружающаяся без установки. === Задачи после сбоя === * Проверка файловых систем * Сброс забытого пароля * Исправление критичных файлов (''/etc/fstab'', ''/etc/passwd'') * Восстановление резервных копий === Однопользовательский режим === **Быстрая загрузка в root-оболочку без служб.** ^ Init система ^ Режим ^ | System V | Уровень выполнения 1 | | systemd | rescue.target | | Параметр загрузчика | **-s** | **Недостатки:** сеть часто недоступна, нет GUI, терминал может работать некорректно. **Live-образ более предпочтителен.** **Требует:** пароль суперпользователя для входа.