Пишем systemd Unit файл
Первое что стоит сделать — так это проверить инициализацию:
# ps -s1| awk '{print $4}'| grep -Ev "CMD"
PS: Вот небольшая статья:
Файлы шаблонов блоков могут быть определены, потому что они содержат символ @ после имени базового блока и перед суффиксом блокового типа. Имя файла блока с шаблоном может выглядеть следующим образом:
my_test@.service
Из созданного блока ( что выше) можно создать экземпляр др блока, который выглядит следующим образом:
my_test@instance1.service
Мощность файлов шаблонных модулей в основном проявляется благодаря возможности динамически подставлять соответствующую информацию в определение устройства в соответствии со средой (ENV). Это делается путем установки директив в файл шаблона как обычно, но заменяя определенные значения или части значений спецификаторами переменных.
Ниже приведены некоторые из наиболее распространенных спецификаторов, которые будут заменены, когда юнит-экземпляра интерпретируется с соответствующей информацией:
- %n: В любом месте, где это используется, будет добавлено полное имя элемента.
- %N: Это то же самое, что и выше, но любое экранирование, такое как те, что присутствуют в шаблонах пути файла, будет отменено.
- %p: Это указывает префикс имени юнита. Это часть названия юнита, которая предшествует символу @.
- %P: Это то же самое что и выше, но с любым отступлением.
- %i: Это ссылается на имя экземпляра, которое является идентификатором, следующим за @ в экземпляре. Это один из наиболее часто используемых спецификаторов, поскольку он динамичный. Использование этого идентификатора поощряет использование значимых идентификаторов конфигурации. Например, порт, в котором будет выполняться служба, может использоваться как идентификатор экземпляра, и шаблон может использовать этот спецификатор для настройки спецификации порта.
- %I: Этот спецификатор такой же, как и выше, но с любым отступлением.
- %f: Это будет заменено на имя неэкранированного юнита или имя префикса, добавленное к «/».
- %c: Это будет указывать на управляющую группу устройства со стандартной родительской иерархией /sys/fs/cgroup/ssytemd.
- %u: Имя пользователя, настроенного для запуска юнита.
- %U: То же, что и выше, UID вместо имени.
- %H: Имя хоста системы, на котором выполняется юнит.
- %%: Это используется для вставки буквенного знака процента.
Используя приведенные выше идентификаторы в шаблоне файла, Systemd заполнит правильные значения при интерпретации шаблона для создания юнит-экземпляра.
Targets
This article or section needs language, wiki syntax or style improvements. See Help:Style for reference.
Reason: Unclear description, copy-pasted content (explicitly mentions «Fedora»). (Discuss in )
systemd uses targets to group units together via dependencies and as standardized synchronization points. They serve a similar purpose as runlevels but act a little differently. Each target is named instead of numbered and is intended to serve a specific purpose with the possibility of having multiple ones active at the same time. Some targets are implemented by inheriting all of the services of another target and adding additional services to it. There are systemd targets that mimic the common SystemVinit runlevels so you can still switch targets using the familiar command.
The following should be used under systemd instead of running :
$ systemctl list-units --type=target
Create custom target
The runlevels that held a defined meaning under sysvinit (i.e., 0, 1, 3, 5, and 6); have a 1:1 mapping with a specific systemd target. Unfortunately, there is no good way to do the same for the user-defined runlevels like 2 and 4. If you make use of those it is suggested that you make a new named systemd target as that takes one of the existing runlevels as a base (you can look at as an example), make a directory , and then symlink the additional services from that you wish to enable.
Mapping between SysV runlevels and systemd targets
SysV Runlevel | systemd Target | Notes |
---|---|---|
runlevel0.target, poweroff.target | Halt the system. | |
1, s, single | runlevel1.target, rescue.target | Single user mode. |
2, 4 | runlevel2.target, runlevel4.target, multi-user.target | User-defined/Site-specific runlevels. By default, identical to 3. |
3 | runlevel3.target, multi-user.target | Multi-user, non-graphical. Users can usually login via multiple consoles or via the network. |
5 | runlevel5.target, graphical.target | Multi-user, graphical. Usually has all the services of runlevel 3 plus a graphical login. |
6 | runlevel6.target, reboot.target | Reboot |
emergency | emergency.target | Emergency shell |
Change current target
In systemd, targets are exposed via target units. You can change them like this:
# systemctl isolate graphical.target
This will only change the current target, and has no effect on the next boot. This is equivalent to commands such as or in Sysvinit.
Change default target to boot into
The standard target is , which is a symlink to . This roughly corresponds to the old runlevel 5.
To verify the current target with systemctl:
$ systemctl get-default
To change the default target to boot into, change the symlink. With systemctl:
# systemctl set-default multi-user.target
Removed /etc/systemd/system/default.target. Created symlink /etc/systemd/system/default.target -> /usr/lib/systemd/system/multi-user.target.
Alternatively, append one of the following kernel parameters to your bootloader:
- (which roughly corresponds to the old runlevel 3),
- (which roughly corresponds to the old runlevel 1).
Изменение файлов юнитов
Если требуется изменить файл юнита, это можно сделать непосредственно командой systemctl, чтобы не искать его на диске.
Для создания сниппета файла юнита (блок, который может использоваться для дополнения или замены параметров файла юнита по умолчанию) нужно воспользоваться опцией edit:
sudo systemctl edit nginx.service
Если нужно изменить все содержимое файла, а не создавать сниппет, воспользуйтесь флагом —full:
sudo systemctl edit --full nginx.service
После изменения файла юнита нужно перезагрузить сам процесс systemd для принятия изменений:
sudo systemctl daemon-reload
Интерфейс для systemd (опционально)
Chkservice — удобная утилита для управления юнитами systemd. В Debian 10 она доступна прямо из репозитория:
root@dedicated:~ apt install chkservice
Если в репозиториях вашего дистрибутива она отсутствует, установку можно выполнить с доступного PPA разработчиков:
root@dedicated:~ add-apt-repository ppa:linuxenko/chkservice root@dedicated:~ apt-get update root@dedicated:~ apt-get install chkservice
Запустить интерфейс:
root@dedicated:~ chkservice
Управление выполняется следующим образом, стрелками «вверх» и «вниз». Запустить юнит — клавиша «r», остановить — клавиша «s». Будьте осторожны, после нажатия клавиши, сигнал немедленно отправляет команду на выполнения без предупреждений.
Завершение процессов пользователя при выходе из системы
Arch Linux создает пакет с помощью , устанавливая равным по умолчанию. Этот параметр предотвращает уничтожение пользовательских процессов, когда пользователь полностью выходит из системы. Чтобы изменить это поведение и убить все пользовательские процессы при выходе из системы, установите в .
Обратите внимание, что изменение этого параметра нарушает работу мультиплексоров терминала, таких как tmux и GNU Screen (Русский). Если вы измените этот параметр, вы все равно сможете использовать терминальный мультиплексор, используя следующим образом:
$ systemd-run --scope --user command args
Например, чтобы запустить , вы должны сделать:
$ systemd-run --scope --user screen -S foo
Запущенные с помощью процессы продолжат работу даже после выхода пользователя, если он залогинен в системе где-то ещё и служба всё ещё работает.
Основные настройки
Все пользовательские службы размещаются в . Если вы хотите запускать службы при первом входе в систему, выполните для любой службы, которую вы хотите сделать автозагрузочной.
Совет: Если вы хотите включить службу для всех пользователей, а не для пользователя, выполняющего команду systemctl , запустите от имени суперпользователя.
Переменные окружения
Пользовательский процесс systemd не наследует какую-либо из переменных окружения, установленных в или других. Существует несколько способов установить переменные окружения для systemd:
- Для переменной пользовательского каталога, создайте файл .conf в каталоге со строками вида {{ic | 1 = NAME = VAL}. Применяется только к части пользовательских служб.
Смотрите для получения дополнительной информации.
- Используйте опцию в . Применяется ко всем пользовательским службам.
- Добавление конфигурационного файла в . Применяется ко всем пользовательским процессам; см
- Для временного изменения используйте или . Применяется ко всем пользовательским службам, созданным после установки переменных окружения, но не к службам, которые уже были запущены.
- Используйте команда обеспечивается dbus. Имеет тот же эффект, что и , но так же влияет на сессию D-Bus. Вы можете добавить это в конец вашего файла инициализации оболочки.
- Для «глобальных» переменных пользовательского окружения вы можете использовать каталоги , которые анализируются генераторами systemd. Подробнее см. и .
- Вы также можете написать скрипт генератора среды, который может создавать переменные среды, которые варьируются от пользователя к пользователю. Это, вероятно, лучший способ, если вам нужны индивидуальные среды (это относится к , и т.д.). Смотрите .
Одну переменную Вы можете установить в .
После настройки можно использовать команду для проверки правильности значений.
Пример службы
Создайте каталог и внутри создайте файл с расширением (например, ):
/etc/systemd/system/user@.service.d/local.conf
Environment="PATH=/usr/lib/ccache/bin:/usr/local/bin:/usr/bin:/bin" Environment="EDITOR=nano -c" Environment="BROWSER=firefox" Environment="NO_AT_BRIDGE=1"
PATH
Если изменить и запланированный запуск приложений, которые используют службу systemd, Вы должны убедиться, что модифицированный установлен и в среде systemd. Если предположить, что Вы установили переменную в , то лучшим способом сделать systemd осведомленным о модификации будет добавление в после заданной переменной:
~/.bash_profile
systemctl --user import-environment PATH
Обратите внимание, что это не повлияет на службы systemd, запущенные до импортирования PATH.
pam_environment
Переменные среды можно сделать доступными с помощью модуля . Смотрите для деталей конфигурации.
Автоматический запуск systemd от имени пользователя
Пользовательский процесс systemd запускается сразу после первого входа пользователя в систему, и будет убит после завершения последнего сеанса пользователя. Иногда может быть полезно запустить службу сразу после загрузки, и поддерживать процесс systemd запущенным даже после завершения последнего сеанса пользователя, например, чтобы некоторый пользовательский процесс работал без какой-либо открытой сессии. Для этой цели используются долговременные службы. Используйте следующую команду, чтобы включить долговременную службу для конкретного пользователя:
# loginctl enable-linger username
Важно: Служба systemd находится вне сессии, она запускается за пределами logind. Не используйте долговременные службы для включения автоматического входа в систему, иначе будет .
Диагностика
Также можно посмотреть список сервисов, которые необходимо перезапустить:
Но встречалась вполне достоверная информация с отсылкой к , что needs-restarting применительно к systemd не показывает верную информацию.
Поэтому предлагается вариант с использованием известного инструмента lsof, который может предоставить информацию о загруженных файлах в память, которые не соответствуют их копии на диске, т.е. для которых было выполнено обновление. Это хороший показатель того, что необходимо перезапустить службы или сервер:
- -n – запрещает преобразование адресов в доменные имена для сетевых файлов. Это позволяет работать lsof быстрее
- -P – запрещает преобразование номеров портов в имена портов для сетевых файлов, что также позволяет работать lsof быстрее.
- +L1 – указывает, что выборке подлежат только unlinked-файлы.
Для конкретного процесса, если известен PID, подойдет следующая команда:
Таким образом, lsof показывает, какие файлы и для каких сервисов были изменены, а дальше уже нужно принять решение о необходимости перезапуска того или иного сервиса (системы). В данном случае, при обновлении systemd команда lsof для p1 вернула пустой результат, что косвенно может говорить о том, что выполнять перезапуск systemd после upgrade не требуется.
Но есть один момент. Если обратиться к документации systemd, то можно узнать о существовании такой команды
Которая по всей видимости и решает вопрос “мягкого” перезапуска systemd после его обновления:
В случае возникновения ошибки вида “Failed to read server status: Access denied”, её можно исправить следующим образом. По сути daemon-reexec посылает TERM сигнал, т.е. можно выполнить:
Управление службами Linux
Теперь, когда вы уже знаете все основы, команды и параметры можно переходить к делу. Со всеми остальными тонкостями разберемся по пути. Сначала давайте посмотрим запущенные службы linux. Нас будут интересовать только программы, а не все эти дополнительные компоненты, поэтому воспользуемся опцией type:
Команда отобразила все службы, которые известны systemd, они сейчас запущены или были запущены. Программа не пересматривает все файлы, поэтому будут показаны только те службы, к которым уже обращались. Состояние loaded — означает, что конфигурационный файл был успешно загружен, следующая колонка active — служба была запущена, а running или exited значит выполняется ли сейчас служба или она успешно завершила свою работу. Листать список можно кнопками вверх/вниз.
Следующая команда позволяет получить список служб linux, в который входят все службы, даже не запущенные, те, которые не запускались, но известны systemd, но это еще не все службы в системе:
Дальше больше. Вы можете отсортировать список служб systemctl по состоянию. Например, только выполняющиеся:
Или те, которые завершились с ошибкой:
Для фильтрации можно брать любой показатель состояния из любой колонки. Другой командой мы можем посмотреть все файлы конфигурации служб на диске. Тут не будем фильтровать по типу, пусть программа покажет все:
Теперь отфильтруем только службы linux:
Здесь вы тоже можете использовать фильтры по состоянию. Теперь вы знаете как посмотреть запущенные службы linux, идем дальше.
Чтобы запустить службу используется команда start, например:
Причем расширение service можно опустить, оно и так подставляется по умолчанию. Если запуск прошел хорошо, программа ничего не выведет.
Остановить службу linux можно командой:
Посмотреть состояние службы позволяет команда status:
Здесь вы можете видеть, состояние running, exited, dead, failed и т д. А также несколько последних строчек вывода программы, которые очень помогут решить проблему с запуском если она возникнет.
Типы systemd Unit файлов
Самый простой способ определить тип устройства — это посмотреть на его суффикс, который добавляется к концу имени ресурса (юнита). В следующем списке описаны типы unit-ов, доступных для systemd:
- .service: Данный юнит описывает, как управлять службой или приложением на сервере. Он в себе будет включать запуск или остановку службу, при каких обстоятельствах она должна автоматически запускаться, а также информацию о зависимости для соответствующего программного обеспечения.
- .socket: Файл сокет-устройства описывает сетевой, IPC-сокет или FIFO буфер, который systemd использует для активации сокета. Они всегда имеют связанный .service файл, который будет запущен при сокет активности, которая определяет этот блок.
- .device: Юнит, который описывает устройство, которое было указано как необходимое для управления systemd с помощью udev или файловой системы sysfs. Не все устройства имеют файлы .device. Некоторые скрипты, которым может потребоваться устройства .device, предназначены для монтирования и доступа к устройствам.
- .mount: Этот блок определяет точку монтирования в системе, которой управляет systemd. Они называются по пути монтирования, при этом «/» изменены на тире. Записи внутри /etc/fstab могут иметь блоки, созданные автоматически.
- .automount: Модуль .automount настраивает точку монтирования, которая будет автоматически установлена и должен быть определен после точки монтирования, на которую они ссылаются, и должны иметь соответствующий модуль .mount для определения особенностей монтирования.
- .swap: Данный юнит, описывает SWAP (пространство подкачки) в системе. Название этих блоков должно отражать путь к устройству или файлу.
- .target: Данный юнит используется для обеспечения точек синхронизации для других устройств при загрузке или изменения состояний. Они также могут использоваться для перевода системы в новое состояние.
- .path: Данный юнит, определяет путь, который может использоваться для активации на основе пути. По умолчанию, юнит будет запущен с тем же базовым именем. Это использует inotify для отслеживания изменения путей.
- .timer: Этот юнит, определяет таймер, который будет управляться systemd (аналог cron джоб) для задержки или запланированной активации. При достижении таймера будет запускаться соответствующий блок.
- .snapshot: Это юнит, создается автоматически командой snapshot systemctl. Он позволяет вам восстановить текущее состояние системы после внесения изменений. Снимки не сохраняются во время сеансов и используются для отката временных состояний.
- .slice: Он связан с узлами группы управления Linux, что позволяет ограничить ресурсы или назначить их для любых процессов, связанных с slice. Имя отражает его иерархическую позицию внутри дерева групп. Юниты размещаются в определенных slice по умолчанию в зависимости от их типа.
- .scope: Они создаются автоматически systemd из информации которую получили от его интерфейса шины. Они используются для управления наборами системных процессов, созданных извне.
Как вы можете видеть, существует множество различных юнитов с которыми взаимодействует система. Многие из них работают вместе, чтобы добавить функциональности. В основном, используется .service из-за их полезности.
Порядок запуска юнитов
Все описанное выше абсолютно не значит, что вы не сможете установить порядок запуска юнитов самостоятельно. При отсутствии каких-либо дополнительных инструкций, systemd действительно будет запускать группы юнитов одновременно. Скорее всего, именно по этой причине некоторые люди уверены в том, что systemd запускает все системные службы одновременно (или в «параллельном режиме»). Но, разумеется, иногда необходимо запускать процессы в определенном порядке.
К счастью, systemd также поддерживает директивы, предназначенные для решения подобных задач, а именно, и . Эти директивы работают так, как вы можете предположить:
- Если юнит-файл юнита unit1 содержит директиву , то при запуске обоих юнитов юнит unit1 будет запущен до момента запуска юнита unit2.
- Если юнит-файл юнита unit1 содержит директиву , то при запуске обоих юнитов процесс запуска юнита unit2 будет полностью завершен перед запуском юнита unit1.
И снова обратите внимание на то, что порядок запуска юнитов никак не влияет на зависимости юнитов. Ведь с помощью описанных в данном разделе директив ни в каком из случаев не будет осуществляться запуск юнита unit2
Давайте снова рассмотрим юнит-файл :
Wants=sshd-keygen.service After=network.target sshd-keygen.service
Директива , регламентирующая порядок запуска юнитов, позволяет гарантированно запустить сервер SSH только после того, как окончит свою работу юнит генерации ключей для узла и будет установлено сетевое соединение. (Юнит позволяет осуществить гарантированный запуск юнитов, необходимых для организации сетевого соединения.) Директивы зависимостей и обычно используются вместе с директивой для корректного описания как зависимостей юнитов, так и порядка их запуска.
Немного теории
Чтобы всем этим управлять нужна основная служба — система инициализации, которая будет запускать службы linux в нужный момент, следить чтобы они нормально работали, записывать сообщения логов, и самое главное позволять останавливать службы. Раньше, для управления службами использовались скрипты. Я уже говорил, что можно запустить службу из терминала, так вот, каждая служба запускалась в фоновом режиме одна за другой, без возможности параллельного запуска и возвращала свой PID процесса скрипту инициализации, он сохранялся и потом с помощью этого PID можно было проверить работает ли служба и остановить службу linux если это нужно. Все это можно сделать и вручную.
Но потом на смену этому методу пришла новая модель и система инициализации systemd. Система инициализации запускается сразу после загрузки ядра и начинает инициализировать службы, теперь появилась возможность параллельной инициализации, а также зависимостей между службами. Таким образом, теперь можно определить сложное дерево порядка запуска служб. Но мы не будем вникать в подробности создания служб, нас интересует только сам процесс запуска. После запуска systemd собирает весь вывод службы в лог, и следит за ее работой, если служба аварийно завершилась, то автоматически ее перезапускает.
Служба в Systemd описывается файлом юнита, в нем описано что с ней нужно делать и как себя вести. Существуют такие типы служб:
- service — обычная служба, программа
- target — группа служб
- automount — точка автоматического монтирования
- device — файл устройства, генерируется на этапе загрузки
- mount — точка монтирования
- path — файл или папка
- scope — процесс
- slice — группа системных служб systemd
- snapshot — сохраненное состояние запущенных служб
- socket — сокет для взаимодействия между процессами.
Нас будут интересовать только service, и совсем немного target, но мы рассмотрели все остальные, чтобы вы смогли взглянуть на картину немного шире. Основы рассмотрели, теперь будет настройка служб LInux.
Заключение
В статье был рассмотрен вопрос необходимости перезагрузки системы после обновления пакета systemd. Резюмируя, можно сказать, что такой необходимости нет. При возникновении ситуации, когда нужно обновить и не перезагружать сервер, есть инструменты вида daemon-reexec.
Но всё это применимо, как мне видится, на каких-то системах, где нет ничего критичного. Лучше всегда запланировать даунтайм и выполнить плановую перезагрузку (совместив, например, с какими-то другими работами). Ведь даже Red Hat не зря рекомендует выполнять перезагрузку. А на каких-то крупных хайлоад-проектах есть балансировщики и кластеры с нескольким количеством нод, которые в любом случае можно и нужно обслуживать, а значит выводить из работы с их последующим даунтаймом.
P.S. В моём случае были обновлены следующие пакеты на продуктивных серверах без каких-либо проблем на стороне приложения и запланирован даунтайм для ребута:
- systemd-libs
- systemd
- systemd-sysv
- libgudev1