Перейти к содержанию

Собственная служба systemd: разработка и безопасность

В НАЙС.ОС CLOUD роль менеджера служб выполняет systemd. Чтобы процесс надёжно запускался, останавливался и журналировался, его следует оформить как unit. Однако systemd не исправляет ошибки приложения и не гарантирует наличие сети/диска без явных зависимостей.

1. Типы unit

service запускает процесс; socket реализует сокетную активацию; timer запускает задачи по расписанию; mount управляет монтированием; target объединяет состояния загрузки. Устанавливать свои unit рекомендуется в /etc/systemd/system/, тогда как файлы в /usr/lib/systemd/system/ обычно принадлежат пакетам.

systemctl list-unit-files --type=service --no-pager | head -40
systemctl cat sshd.service
systemctl show sshd.service -p FragmentPath -p DropInPaths

Имя sshd.service подтверждено SPEC OpenSSH, но для диагностики на конкретном хосте сначала проверяйте systemctl list-unit-files '*ssh*'.

2. Пример отдельного приложения

Допустим, вы сами установили приложение /opt/example/bin/worker и создали системного пользователя example. Следующий unit показывает модель, но не может работать до создания приложения и учётной записи:

# /etc/systemd/system/example-worker.service
[Unit]
Description=Example background worker
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=example
Group=example
WorkingDirectory=/opt/example
ExecStart=/opt/example/bin/worker
Restart=on-failure
RestartSec=10s
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=full
ProtectHome=yes

[Install]
WantedBy=multi-user.target

ProtectSystem=full делает системные каталоги частично недоступными для записи процессу, но требования конкретного приложения нужно тестировать. Если worker должен писать в /var/lib/example, используйте выделенную директорию и политику прав; не запускайте его как root из удобства.

3. Проверка и запуск

systemd-analyze verify /etc/systemd/system/example-worker.service
systemctl daemon-reload
systemctl start example-worker.service
systemctl status example-worker.service --no-pager --full
journalctl -u example-worker.service -b --no-pager -n 100

Только если приложение запускается корректно и политика позволяет автозапуск:

systemctl enable example-worker.service
systemctl is-enabled example-worker.service

enable создаёт связи автозапуска, но не означает, что служба уже запущена. start запускает сейчас, но не добавляет в автозапуск. Отличайте эти операции.

4. Изменение пакетной службы

Не редактируйте unit-файл из /usr/lib/systemd/system/, потому что обновление RPM может его заменить. Используйте:

systemctl edit example-worker.service
systemctl cat example-worker.service
systemctl show example-worker.service -p DropInPaths

Параметры ExecStart при переопределении часто требуют очистить исходное значение пустой строкой. Проверяйте systemctl cat и документацию systemd.service перед использованием drop-in.

5. Диагностика

Проблема Проверка
status=203/EXEC Путь и права исполняемого файла, shebang, SELinux
status=217/USER Пользователь отсутствует/ошибка настройки UID
Start request repeated too quickly Реальная первопричина в journal; start limit
Работает руками, не работает в unit Окружение, права, рабочий каталог, сеть
Стартует до диска mount dependencies, RequiresMountsFor=

Никогда не заменяйте расследование циклическим Restart=always с интервалом в миллисекунды: это усилит нагрузку и скроет проблему.

Откат

В тестовой среде выполните systemctl stop, disable, удалите только созданный вами unit и systemctl daemon-reload. Чужие пакетные unit удалять нельзя. По результату диагностики сохраняйте unit и обезличенный journal.

Источники: Core/systemd/SPECS/systemd.spec; systemd.unit.