От включения питания до запуска сервисов

Как загружается ОС?

Table of Contents:

Есть два ряда событий, необходимых для приведения компьютера с Linux в рабочее состояние: загрузка ядра (boot) и запуск системы (startup).
Процесс загрузки ядра начинается при включении компьютера и заканчивается с инициализацией ядра и запуском подсистемы инициализации демонов. После этого начинается процесс запуска системы, и именно он доводит компьютер Linux до рабочего состояния.

Этапы загрузки ядра выглядят следующим образом (на каждом этапе используется одна из перечисленных технологий) :

  1. BIOS / EFI / UEFI
  2. MBR / GPT
  3. LILO / GRUB / GRUB2
  4. Kernel
  5. Init / systemd
  6. Runlevel / Target

Например для Centos 7 этапы загрузки представлены на рисунке.

Рассмотрим каждый из этапов подробно.

POST (Power on Self Test)

Post - это самотестирование после включения, запускаемое из прошивки, которая может быть как UEFI так и классическая BIOS.

Для примера рассмотрим BIOS.
BIOS (Базовая структура ввода-вывода) включает в себя микропрограмму загрузчика.
Микропрограмма загрузчика содержит низкоуровневые функции, такие как ввод с клавиатуры, доступ к видеодисплею, осуществление дисковых операций ввода-вывода и код для загрузки начальной стадии загрузчика. До того как BIOS может определить загрузочное устройство, он выполняет последовательность функций системной конфигурации, начиная со следующих:

  • Самотестирование при включении питания
  • Обнаружение и инициализация видеокарты.
  • Отображение стартового экрана BIOS.
  • Осуществление быстрой проверки памяти (RAM).
  • Конфигурация устройств plug and play.
  • Определение загрузочного устройства.

Как только BIOS определил загрузочное устройство, он считывает первый дисковый сектор этого устройства в память ОЗУ.

MBR

Первый сектор диска — это главная загрузочная запись (MBR) размером 512 байт. В этот размер поместились три объекта:

  • Первая стадия загрузчика (446 байт).
  • Таблица разделов диска (16 байт на раздел × 4 раздела) — MBR поддерживает только четыре раздела, подробнее об этом ниже.
  • Подпись (2 байта).

На этом этапе MBR сканирует таблицу разделов и загружает в оперативную память загрузчик ОС — GRand Unified Bootloader (GRUB2). И передаёт управление загрузчику.

GRUB2

GRUB2 — программа, которая делает компьютер достаточно “умным”, чтобы тот смог найти ядро операционной системы и загрузить его в память.

GRUB совместим со спецификацией мультизагрузки, что позволяет ему загружать разные версии Linux и других операционные системы, он также может запустить по цепочке загрузочную запись проприетарных операционных систем.  GRUB также позволяет пользователю выбрать загрузку ядра из нескольких возможных для любого предоставленного дистрибутива Linux. Это дает возможность загрузить предыдущую версию ядра, если обновленная не сможет загрузиться корректно или окажется несовместима с какой-то важной частью ПО.
Настройка GRUB2 происходит в /boot/grub2/grub.cfg Основная задача любого из GRUB — загрузить ядро Linux в память и запустить его, и происходит это в три этапа.

GRUB Stage 1

Как уже упоминалось в разделе BIOS POST, в конце POST BIOS ищет загрузочные записи на прикрепленных дисках, обычно расположенных в Главной Загрузочной Записи (Master Boot Record, MBR), после чего он загружает первую найденную запись в память и приступает к ее исполнению.
Bootstrap-код, то есть 1-ый этап GRUB2, занимает очень мало места, потому что должен влезать в первый 512-байтовый сектор на жестком диске вместе с таблицей разделов. Общее количество места, выделенного для самого bootstrap-кода в стандартной MBR — 446 байт.
446-байтовый файл для этапа 1 называется boot-img и не содержит таблицу разделов — она добавляется в загрузочную запись отдельно. Поскольку загрузочная запись должна быть настолько маленькой, она не очень “умная” и не понимает структуру файловой системы. Поэтому единственной целью этапа 1 является обнаружение и загрузка этапа 1.5.
Чтобы достичь этого, этап 1.5 GRUB должен располагаться в пространстве между самой загрузочной записью и первым разделом на диске. После загрузки этапа 1.5 GRUB в RAM, этап 1 передает контроль этапу 1.5.

GRUB Stage 1.5

Как было замечено выше, этап 1.5 GRUB должен находиться между загрузочной записью и первый разделом на диске. Исторически сложилось, что это пространство остается неиспользованным по техническим причинам.
Первый раздел на жестком диске начинается в 63 секторе, а с учетом MBR в секторе 0, остается 62 512-байтовых секторов — 31744 байта — в которых можно хранить файл core.img1.5 этап GRUB. Файл core.img весит 25389 байт, что достаточно места для его хранения между MBR и первым разделом диска.
Поскольку для этапа 1.5 можно использовать больше кода, его может быть достаточно для содержания нескольких распространенных драйверов файловых систем, например, стандартной EXT и прочих Linux файловых систем, FAT и NTFS. core.ing в GRUB2 более сложный и функциональный, чем в этапе 1.5 GRUB1.
Это значит, что этап 2 GRUB2 может находиться в стандартной EXT файловой системе, но не в логическом томе. Поэтому стандартное местоположение для файлов этапа 2 — файловая система /boot, а точнее /boot/grub2. Обратим внимание, что директория /boot должна располагаться в файловой системе, которая поддерживается GRUB. Не все файловые системы имеют эту поддержку.
Задача этапа 1.5 — начать с необходимыми драйверами файловой системы поиск файлов этапа 2 в файловой системе /boot и загрузить нужные драйверы.

GRUB Stage 2

Все файлы этапа 2 GRUB находятся в директории /boot/grub2 и нескольких поддиректориях. В GRUB2 нет файла образа как в этапах 1 и 2. Вместо этого он по большей части состоит из runtime модулей ядра, которые грузятся по необходимости из директории /boot/grub2/i386-p.
Задача этапа 2 GRUB2 — обнаружить и загрузить ядро Linux в RAM и передать контроль управления компьютером ядру. Ядро и связанные с ним файлы находятся в директории /boot. Файлы ядра легко узнать, поскольку их названия начинаются с vmlinuz. Вы можете составить список содержимого директории /boot, чтобы посмотреть текущие установленные ядра в вашей системе.
GRUB2, как и GRUB1, поддерживает загрузку одного из нескольких ядер Linux. Система управления пакетами Red Hat поддерживает сохранение нескольких версий ядра, чтобы можно было загрузить старую версию ядра в случае возникновения проблем с самой новой. По умолчанию, GRUB предоставляет предварительно загруженное меню установленные ядер, включая опцию rescue, а после настройки, и опцию recovery.
Этап 2 GRUB2 загружает выбранное ядро в память и передает контроль управления компьютером ядру.

Kernel

Все ядра находятся в самораспаковывающемся, сжатом формате для экономии места. Ядра расположены в директории /boot, вместе с исходным образом диска RAM и списком разделов на жестких дисках.  После того, как выбранное ядро загружено в память и начинает исполняться, в первую очередь, оно должно извлечь самого себя из сжатой версии файла, перед тем как начать выполнять полезную работу.
Как только извлечение произошло, оно загружает systemd, который является заменой старой программе [SysV init], и передает ему контроль.
Это конец процесса загрузки ядра. К этому моменту, ядро Linux и systemd запущены, но не могут выполнять какие-либо полезные задачи для конечного пользователя, так как выполнять еще нечего.

systemd

systemd — родитель всех процессов, ответственный за приведение хоста Linux в состояние эффективной работы. Некоторые его функции, более обширные, чем те, что были представлены в старой программе инициализации, и должны управлять множеством аспектов запущенного хоста Linux, включая монтирование файловой системы, запуск и управление системными сервисами, необходимыми для продуктивной работы хоста Linux.

Сначала, systemd монтирует файловые системы, как определено в /etc/fstab, включая любые swap-файлы и разделы. К этому моменту, он может получить доступ к файлам конфигурации, расположенным в /etc, включая его собственным. Он использует собственный конфигурационный файл /etc/systemd/system/default.target, чтобы определить таргет (target), по которому нужно загрузить хост. Файл default.target — просто симлинк на настоящий target файл. Для настольной рабочей станции обычно это graphical.target, эквивалентный runlevel 5 в старом инициализаторе SystemV. Для сервера, по умолчанию скорее всего будет multi-user.target, аналогичный runlevel 3 в SystemV. emergency.target похож на однопользовательский режим. 

Target’ы и сервисы являются юнитами systemd.

Ниже представлена таблица, в которой идет сравнение всех таргетов systemd со старыми уровнями выполнения (runlevel) в SystemV. Псевдонимы таргета systemd предоставляются для обратной совместимости. Псевдонимы таргета разрешают скриптам использовать такие SystemV команды как init3 для изменения уровней выполнения. Конечно, команды SystemV направлены systemd для интерпретации и исполнения.

Таблица 1: Сравнение уровней управления SystemV с target’ами systemd и некоторые псевдонимы таргетов.

У каждого таргета есть набор зависимостей, описанных в файле конфигурации. systemd запускает необходимые. Эти зависимости представляют собой сервисы, требуемые для запуска хоста Linux с определенным уровнем функционирования. Когда все зависимости, перечисленные в конфигурационных файлах таргета, загружены и запущены, система работает на этом уровне таргета.

systemd также просматривает устаревшие директории инициализации SystemV на предмет наличия стартап файлов. Если они есть, systemd использует их в качестве файлов конфигурации для запуска сервисов описанных в файлах. Устаревший сетевой сервис — хороший пример одного из тех, что до сих пор используют стартап файлы SystemV в Fedora.

Рисунок представленный ниже, напрямую скопирован с главной страницы bootup. На нем показана общая последовательность событий во время запуска systemd и базовые требования для обеспечения его успешности. 

Карта запуска systemd.

Таргеты sysinit.target and basic.target можно считать чекпоинтами в процессе запуска системы. Хоть одна из целей systemd — параллельно запускать системная сервисы, есть некоторые сервисы и функциональные таргеты, которые должны быть запущены раньше других. Эти контрольные точки не могут быть пройдены до тех пор, пока все сервисы и таргеты, необходимые для них, не будут выполнены. 

Таким образом, sysinit.target достигается, когда завершены все юниты, от которых он зависит. Должны быть завершены все следующие юниты: монтирование файловых систем, настройка swap-файлов, запуск udev, настройка начального состояния генератора случайных чисел, инициализация низкоуровневых сервисов, настройка криптографических сервисов, если хотя бы одна файловая система зашифрована. В sysinit.target они могут выполняться параллельно. sysinit.target запускает все низкоуровневые сервисы и юниты необходимые для минимальной функциональности системы, и те, что нужны для перехода к basic.target.

После выполнения sysinit.target, systemd запускает basic.target, начиная со всех юнитов, необходимых для его выполнения. Базовый таргет предоставляет дополнительный функционал, запуская юниты необходимые для следующего таргета, включая настройку путей до различных исполняемых директорий, коммуникационных сокетов и таймеров.

Наконец, можно начать инициализацию таргетов пользовательского уровня: multi-user.target или graphical.target. Стоит отметить, что multi-user.target должен быть достигнут до того, как будут выполнены зависимости графического таргета.

Подчеркнутые таргеты на рисунке — обычные стартап таргеты. Запуск системы завершается по достижении одного из них. Если multi-user.target является таргетом по умолчанию, то в консоли вы увидите логин в текстовом режиме. Если же по умолчанию задан graphical.target, то увидите графический логин; GUI экрана логина зависит от экранного менеджера, который вы используете.

Управление systemd

Главная команда для отслеживания и контроля состояния systemd - команда systemctl.
Некоторые из вариантов ее использования связаны с изучением состояния системы и управлением системой и службами.

Например, чтобы запустить сервер nginx при загрузке/инициализации системы, используется команда enable:

sudo systemctl enable nginx
comments powered by Disqus