Ubuntu. Создание юнита для Systemd
Основная цель Systemd — инициализировать компоненты, которые должны запускаться после загрузки ядра Linux. Кроме того, с помощью команды systemctl
позволяет управлять службами и демонами сервера.
Systemd запускает сервисы описанные в его конфигурации. Конфигурация состоит из множества файлов, которые часто называют юнитами. Все эти юниты разложены в трех директориях.
/lib/systemd/system
— юниты из установленных пакетов — nginx, apache, mysql/run/systemd/system
— нужен самому Systemd для динамически создаваемых юнитов/etc/systemd/system
— юниты, созданные администратором сервера
Юнит представляет из себя текстовый файл с форматом, похожим на файлы ini
. Для создания простейшего юнита надо описать три секции — [Unit]
, [Service]
, [Install]
.
В секции [Unit]
описываем, что это за юнит, директива Description
описывает назначение (краткое описание).
[Unit] Description=SSH tunnel to TimeWeb server at startup
Далее следуют директивы, которые влияют на порядок загрузки сервисов.
Запускать наш сервис можно после запуска network-online.target
After=network-online.target
Для запуска сервиса необходим запущенный сервис mysql.service
Requires=mysql.service
Для запуска сервиса желателен запущенный сервис redis.service
Wants=redis.service
Директива After
отвечает за порядок запуска юнитов. Если юнит foo.service
содержит директиву After=bar.service
и оба юнита запускаются, запуск foo.service
откладывается до тех пор, пока не завершится запуск bar.service
(не обязательно успешно).
Директива Requires
означает, что если текущий юнит запускается, то и все юниты из этой директивы также будут запущены. Если юнит из Requires
не запустится успешно, и этот юнит есть в After
, текущий юнит не будет запущен — нет смысла запускать, все равно не сможет нормально работать. Текущий юнит будет остановлен (или перезапущен), если один из юнитов в Requires
будет явно остановлен (или перезапущен).
Тип зависимости Requires
не означает, что все юниты в нем должны быть в активном состоянии, когда текущий юнит находится в активном состоянии. Остановка (или перезапуск) текущего юнита не означает остановку (или перезапуск) юнитов из Requires
— это он от них зависит, а не они от него.
Директива BindsTo
очень похожа на Requires
, но зависимость сильнее. Если юнит в BindsTo
остановлен (неважно по какой причине), то текущий юнит также будет остановлен. Это односторонняя зависимость — остановка или перезапуск текущего юнита никак не влияют на юнит в BindsTo
.
[Unit] Description=Service Two # Если юнит one.service перешел в неактивное состояние по любой причине, то текущий юнит # также будет остановлен. Это односторонняя зависимость two.service от one.service. BindsTo=one.service
Директива PartOf
похожа на BindsTo
, но срабатывает только при остановке и перезапуске. Когда Systemd останавливает или перезапускает юнит в BindsTo
, то и текущий юнит будет остановлен или перезапущен. Это односторонняя зависимость — остановка или перезапуск текущего юнита никак не влияют на юнит в PartOf
.
[Unit] Description=Service Two # Когда Systemd останавливает или перезапускает юнит one.service, этот юнит также будет # остановлен или перезапущен. Это односторонняя зависимость two.service от one.service. PartOf=one.service
Не следует путать зависимость и порядок запуска — это абсолютно независимые директивы. Директива Requires
требует только запуска перечисленных юнитов, без определения порядка запуска. Директива After
требует только дождаться окончания запуска перечисленных юнитов (не обязательно успешного). Совместное использование двух директив изменяет этот порядок вещей.
Если юнит есть в Requires
, но нет в After
, то текущий юнит будет запущен параллельно с требуемым юнитом, а не после завершения запуска требуемого юнита (не обязательно успешного). Если юнит есть в Requires
и After
, то текущий юнит будет запущен только после успешного завершения запуска требуемого юнита.
В секции [Service]
указываем какими командами и под каким пользователем надо запускать сервис.
[Service] Type=simple
Тип сервиса Type
может принимать значения
simple
(по умолчанию) — служба будет запущена незамедлительно. Процесс при этом не должен разветвляться. Не используйте этот тип, если другие службы зависят от очередности при запуске данной службы.forking
— служба запускается однократно и процесс разветвляется с завершением родительского процесса. Данный тип используется для запуска классических демонов.
Директивы User
и Group
— пользователь и группа, под которым нужно стартовать сервис.
[Service] Type=simple User=evgeniy Group=evgeniy
Директива PIDFile
— если тип службы отмечен как forking
, эта директива используется для установки пути файла, который должен содержать идентификационный номер процесса основного «ребенка», который должен контролироваться.
Директива WorkingDirectory
— рабочий каталог службы, он делается текущим перед запуском стартап команд.
Директива Environment
задает переменные окружения, которые должны быть доступны нашей службе.
Директивы ExecStart
, ExecStop
, ExecReload
задают команды на start
, stop
и reload
сервиса. Тут есть тонкость — Systemd настаивает, чтобы команда указывала на конкретный исполняемый файл — нужно указывать полный путь.
Директива Restart
предписывает перезапускать наш сервис, если он вдруг перестанет работать.
[Service] Type=simple User=evgeniy Group=evgeniy ExecStart=/usr/bin/ssh -N -F /home/evgeniy/.ssh/config remote-forward-timeweb-server Restart=always RestartSec=5
Директива RestartSec
— если автоматический перезапуск службы включен, это указывает время ожидания перед попыткой перезапуска службы.
Директива TimeoutSec
устанавливает время, в течение которого система будет ждать запуска или остановки службы, прежде чем пометить ее как неудачную или убитую принудительно.
В секции [Install]
описываем, на каком уровне запуска должен стартовать сервис.
[Install] WantedBy=multi-user.target
В итоге у нас получился вот такой юнит для Systemd.
[Unit] Description=SSH tunnel to TimeWeb server at startup After=network-online.target Requires=network-online.target [Service] Type=simple User=evgeniy Group=evgeniy ExecStart=/usr/bin/ssh -N -F /home/evgeniy/.ssh/config remote-forward-timeweb-server Restart=always RestartSec=5 [Install] WantedBy=multi-user.target
После создания нового юнита необходимо перезапустить Systemd.
$ sudo systemctl daemon-reload
Дополнительно
- Установка OpenVPN на Ubuntu 18.04 LTS. Часть 11 из 12
- Создание SSH-туннеля. Часть 4 из 4
- Ubuntu. Настройка сети
- Ubuntu. Автоматическое обновление
- Ubuntu. Запуск задач по расписанию
- Установка WireGuard на Ubuntu 20.04 LTS. Часть вторая из двух
- Установка WireGuard на Ubuntu 20.04 LTS. Часть первая из двух
Поиск: Linux • Systemd • Ubuntu • Конфигурация • Настройка • Теория • юнит