Systemd за пять минут
Наша компания занимается администрированием веб-серверов на базе CentOS. Довольно часто наши клиенты используют веб-приложения на базе python, ruby или java. Для автозапуска подобных приложений есть готовые шаблоны для написания стартап-скриптов. Но прогресс не стоит на месте, вышел уже второй релиз CentOS 7 и, следуя старой традиции «не ставить dot-zero релизы на продакшен», мы начинаем предлагать клиентам сервера на базе CentOS 7.1 (1503).
В CentOS7, так же как и в его родителе RHEL7, используется systemd — менеджер системы и служб для Linux, совместимый со скриптами инициализации SysV и LSB. systemd обеспечивает возможности агрессивной параллелизации и много всего прочего.
Огромный монстр с множеством возможностей, гибкими настройками и мегабайтами документации…
Но что делать, если стоит задача быстро-быстро, вот прямо вчера, сделать автозапуск некоего сервиса?
Давайте выжмем из документации минимально необходимый набор информации для создания простых старт-стоп скриптов.
Systemd запускает сервисы описанные в его конфигурации.
Конфигурация состоит из множества файлов, которые по-модному называют юнитами.
Все эти юниты разложены в трех каталогах:
/usr/lib/systemd/system/ – юниты из установленных пакетов RPM — всякие nginx, apache, mysql и прочее
/run/systemd/system/ — юниты, созданные в рантайме — тоже, наверное, нужная штука
/etc/systemd/system/ — юниты, созданные системным администратором — а вот сюда мы и положим свой юнит.
Юнит представляет из себя текстовый файл с форматом, похожим на файлы .ini Microsoft Windows.
[Название секции в квадратных скобках]
имя_переменной = значение
Для создания простейшего юнита надо описать три секции: [Unit], [Service], [Install]
В секции Unit описываем, что это за юнит:
Названия переменных достаточно говорящие:
Далее следует блок переменных, которые влияют на порядок загрузки сервисов:
Запускать юнит после какого-либо сервиса или группы сервисов (например network.target):
After=syslog.target
After=network.target
After=nginx.service
After=mysql.service
В итоге переменная Wants получается чисто описательной.
Если сервис есть в Requires, но нет в After, то наш сервис будет запущен параллельно с требуемым сервисом, а не после успешной загрузки требуемого сервиса
В секции Service указываем какими командами и под каким пользователем надо запускать сервис:
(по умолчанию): systemd предполагает, что служба будет запущена незамедлительно. Процесс при этом не должен разветвляться. Не используйте этот тип, если другие службы зависят от очередности при запуске данной службы.
systemd предполагает, что служба запускается однократно и процесс разветвляется с завершением родительского процесса. Данный тип используется для запуска классических демонов.
Также следует определить PIDFile=, чтобы systemd могла отслеживать основной процесс:
Команды на старт/стоп и релоад сервиса
ExecStart=/usr/local/bin/bundle exec service -C /work/www/myunit/shared/config/service.rb —daemon
ExecStop=/usr/local/bin/bundle exec service -S /work/www/myunit/shared/tmp/pids/service.state stop
ExecReload=/usr/local/bin/bundle exec service -S /work/www/myunit/shared/tmp/pids/service.state restart
Тут есть тонкость — systemd настаивает, чтобы команда указывала на конкретный исполняемый файл. Надо указывать полный путь.
Таймаут в секундах, сколько ждать system отработки старт/стоп команд.
Попросим systemd автоматически рестартовать наш сервис, если он вдруг перестанет работать.
Контроль ведется по наличию процесса из PID файла
В секции [Install] опишем, в каком уровне запуска должен стартовать сервис
multi-user.target или runlevel3.target соответствует нашему привычному runlevel=3 «Многопользовательский режим без графики. Пользователи, как правило, входят в систему при помощи множества консолей или через сеть»
Вот и готов простейший стартап скрипт, он же unit для systemd:
myunit.service
Кладем этот файл в каталог /etc/systemd/system/
Смотрим его статус systemctl status myunit
Видим, что он disabled — разрешаем его
systemctl enable myunit
systemctl -l status myunit
Если нет никаких ошибок в юните — то вывод будет вот такой:
Запускаем сервис
systemctl start myunit
Смотрим красивый статус:
systemctl -l status myunit
Если есть ошибки — читаем вывод в статусе, исправляем, не забываем после исправлений в юните перегружать демон systemd
Источник
Linux systemd suse 11
The Linux boot process consists of several stages, each represented by a different component. The following list briefly summarizes the boot process and features all the major components involved.
BIOS.В After turning on the computer, the BIOS initializes the screen and keyboard and tests the main memory. Up to this stage, the machine does not access any mass storage media. Subsequently, the information about the current date, time, and the most important peripherals are loaded from the CMOS values. When the first hard disk and its geometry are recognized, the system control passes from the BIOS to the boot loader. If the BIOS supports network booting, it is also possible to configure a boot server that provides the boot loader. On x86 systems, PXE boot is needed. Other architectures commonly use the BOOTP protocol to get the boot loader.
Boot Loader.В The first physical 512-byte data sector of the first hard disk is loaded into the main memory and the boot loader that resides at the beginning of this sector takes over. The commands executed by the boot loader determine the remaining part of the boot process. Therefore, the first 512В bytes on the first hard disk are referred to as the Master Boot Record (MBR). The boot loader then passes control to the actual operating system, in this case, the Linux Kernel. More information about GRUB, the Linux boot loader, can be found in ChapterВ 11, The Boot Loader GRUB. For a network boot, the BIOS acts as the boot loader. It gets the image to start from the boot server and starts the system. This is completely independent of local hard disks.
Kernel and initramfs . To pass system control, the boot loader loads both the Kernel and an initial RAM–based file system ( initramfs ) into memory. The contents of the initramfs can be used by the Kernel directly. initramfs contains a small executable called init that handles the mounting of the real root file system. If special hardware drivers are needed before the mass storage can be accessed, they must be in initramfs . For more information about initramfs , refer to Section 10.1.1, “ initramfs ”. If the system does not have a local hard disk, the initramfs must provide the root file system to the Kernel. This can be done with the help of a network block device like iSCSI or SAN, but it is also possible to use NFS as the root device.
init on initramfs . This program performs all actions needed to mount the proper root file system, like providing Kernel functionality for the needed file system and device drivers for mass storage controllers with udev . After the root file system has been found, it is checked for errors and mounted. If this is successful, the initramfs is cleaned and the init program on the root file system is executed. For more information about init , refer to Section 10.1.2, “init on initramfs ”. Find more information about udev in Chapter 15, Dynamic Kernel Device Management with udev .
init . init handles the actual booting of the system through several different levels providing different functionality. init is described in Section 10.2, “The init Process”.
10.1.1 initramfs #
initramfs is a small cpio archive that the Kernel can load to a RAM disk. It provides a minimal Linux environment that enables the execution of programs before the actual root file system is mounted. This minimal Linux environment is loaded into memory by BIOS routines and does not have specific hardware requirements other than sufficient memory. initramfs must always provide an executable named init that should execute the actual init program on the root file system for the boot process to proceed.
Before the root file system can be mounted and the operating system can be started, the Kernel needs the corresponding drivers to access the device on which the root file system is located. These drivers may include special drivers for certain kinds of hard drives or even network drivers to access a network file system. The needed modules for the root file system may be loaded by init on initramfs . After the modules are loaded, udev provides the initramfs with the needed devices. Later in the boot process, after changing the root file system, it is necessary to regenerate the devices. This is done by boot.udev with the command udevtrigger .
If you need to change hardware (for example hard disks) in an installed system and this hardware requires different drivers to be present in the Kernel at boot time, you must update initramfs . This is done in the same way as with its predecessor, init —by calling mkinitrd . Calling mkinitrd without any argument creates an initramfs . Calling mkinitrd -R creates an init . In SUSE® Linux Enterprise Server , the modules to load are specified by the variable INITRD_MODULES in /etc/sysconfig/kernel . After installation, this variable is automatically set to the correct value. The modules are loaded in exactly the order in which they appear in INITRD_MODULES . This is only important if you rely on the correct setting of the device files /dev/sd? . However, in current systems you also may use the device files below /dev/disk/ that are sorted in several subdirectories, named by-id , by-path and by-uuid , and always represent the same disk. This is also possible at install time by specifying the respective mount option.
Important: Updating initramfs or init
The boot loader loads initramfs or init in the same way as the Kernel. It is not necessary to reinstall GRUB after updating initramfs or init , because GRUB searches the directory for the right file when booting.
10.1.2 init on initramfs #
The main purpose of init on initramfs is to prepare the mounting of and access to the real root file system. Depending on your system configuration, init is responsible for the following tasks.
Depending on your hardware configuration, special drivers may be needed to access the hardware components of your computer (the most important component being your hard drive). To access the final root file system, the Kernel needs to load the proper file system drivers.
Providing Block Special Files
For each loaded module, the Kernel generates device events. udev handles these events and generates the required special block files on a RAM file system in /dev . Without those special files, the file system and other devices would not be accessible.
Managing RAID and LVM Setups
If you configured your system to hold the root file system under RAID or LVM, init sets up LVM or RAID to enable access to the root file system later. Find information about RAID and LVM in ChapterВ 15, Advanced Disk Setup.
Managing Network Configuration
If you configured your system to use a network-mounted root file system (mounted via NFS), init must make sure that the proper network drivers are loaded and that they are set up to allow access to the root file system.
If the file system resides on a networked block device like iSCSI or SAN, the connection to the storage server is also set up by the initramfs .
When init is called during the initial boot as part of the installation process, its tasks differ from those mentioned above:
As you start the installation process, your machine loads an installation Kernel and a special init with the YaST installer on the installation medium. The YaST installer, which is run in a RAM file system, needs to have information about the location of the installation medium to access it and install the operating system.
Initiating Hardware Recognition and Loading Appropriate Kernel Modules
As mentioned in Section 10.1.1, “ initramfs ”, the boot process starts with a minimum set of drivers that can be used with most hardware configurations. init starts an initial hardware scanning process that determines the set of drivers suitable for your hardware configuration. The names of the modules needed for the boot process are written to INITRD_MODULES in /etc/sysconfig/kernel . These names are used to generate a custom initramfs that is needed to boot the system. If the modules are not needed for boot but for coldplug, the modules are written to /etc/sysconfig/hardware/hwconfig-* . All devices that are described with configuration files in this directory are initialized in the boot process.
Loading the Installation System or Rescue System
As soon as the hardware is properly recognized, the appropriate drivers are loaded, and udev creates the special device files, init starts the installation system with the actual YaST installer, or the rescue system.
Finally, init starts YaST, which starts package installation and system configuration.
10.2 The init Process #
The program init is the process with process ID 1. It is responsible for initializing the system in the required way. init is started directly by the Kernel and resists signalВ 9, which normally kills processes. All other programs are either started directly by init or by one of its child processes.
init is centrally configured in the /etc/inittab file where the runlevels are defined (see Section 10.2.1, “Runlevels”). The file also specifies which services and daemons are available in each of the runlevels. Depending on the entries in /etc/inittab , several scripts are run by init . By default, the first script that is started after booting is /etc/init.d/boot . Once the system initialization phase is finished, the system changes the runlevel to its default runlevel with the /etc/init.d/rc script. For reasons of clarity, these scripts, called init scripts , all reside in the directory /etc/init.d (see Section 10.2.2, “Init Scripts”).
The entire process of starting the system and shutting it down is maintained by init . From this point of view, the Kernel can be considered a background process to maintain all other processes and adjust CPU time and hardware access according to requests from other programs.
10.2.1 Runlevels #
In Linux, runlevels define how the system is started and what services are available in the running system. After booting, the system starts as defined in /etc/inittab in the line initdefault . Usually this is 3 or 5 . See Table 10.1, “Available Runlevels”. As an alternative, the runlevel can be specified at boot time (by adding the runlevel number at the boot prompt, for instance). Any parameters that are not directly evaluated by the Kernel itself are passed to init . To boot into runlevel 3, just add the single number 3 to the boot prompt.
Источник