sadrix logoSadriX
Минцифры готовит обязательную регистрацию IMEI смартфонов, купленных за границей
Гайды

Как создать systemd unit для своего скрипта: пошаговое руководство

От простого скрипта до полноценной службы: разбираем структуру unit-файла, типы сервисов и типичные ошибки

+19 526 просмотров4 мин
+1
Поделиться:TelegramVK

Введение

В Linux-системах управление службами уже давно перешло к systemd. Если у вас есть скрипт на Python, Bash или бинарное приложение, которое должно работать в фоне, автоматически запускаться при загрузке и перезапускаться при сбоях, лучший способ — оформить его как systemd-юнит. В этом руководстве мы разберём, как создать unit-файл с нуля, настроить его и управлять службой.

Что такое systemd unit и зачем он нужен

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

Преимущества использования systemd перед простым запуском через nohup или screen:

  • Автоматический старт при загрузке системы.

  • Перезапуск при аварийном завершении.

  • Централизованное логирование через journald.

  • Управление зависимостями (запуск после сети, базы данных и т.д.).

  • Ограничение ресурсов и прав доступа.

Требования

  • Linux-система с systemd (Ubuntu, Debian, CentOS, Fedora, Arch и др.).

  • Права root или sudo для размещения файлов в системных каталогах.

  • Скрипт или приложение, готовое к запуску.

  • Базовые навыки работы с командной строкой.

Шаг 1: Подготовка скрипта

Убедитесь, что ваш скрипт работает корректно при запуске из командной строки. Например, создадим простой скрипт /opt/myapp/hello.sh:

#!/bin/bash
echo "Служба запущена в $(date)"
while true; do
  echo "Работаю... $(date)"
  sleep 10
done

Сделайте его исполняемым:

chmod +x /opt/myapp/hello.sh

Проверьте запуск вручную. Если скрипт использует относительные пути, лучше заменить их на абсолютные, так как systemd запускает процессы с другим рабочим каталогом.

Шаг 2: Выбор места для unit-файла

Unit-файлы могут располагаться в нескольких каталогах:

  • /etc/systemd/system/ — для пользовательских служб (рекомендуется).

  • /usr/lib/systemd/system/ — для пакетов из репозиториев.

  • ~/.config/systemd/user/ — для пользовательских служб без root.

Мы будем использовать /etc/systemd/system/, так как это стандартное место для администраторских служб.

Шаг 3: Создание unit-файла

Создайте файл, например /etc/systemd/system/hello.service:

[Unit]
Description=My Hello Service
After=network.target

[Service]
Type=simple
ExecStart=/opt/myapp/hello.sh
Restart=on-failure
User=myuser

[Install]
WantedBy=multi-user.target

Разберём секции подробнее.

Шаг 4: Секция [Unit]

Здесь описываются метаданные и зависимости:

  • Description — человекочитаемое описание службы.

  • After — указывает, после каких юнитов запускать данный. Например, network.target гарантирует, что сеть уже поднята.

  • Requires — жёсткая зависимость: если указанный юнит не запустится, наш тоже не будет запущен.

  • Wants — мягкая зависимость.

Для большинства служб достаточно After=network.target.

Шаг 5: Секция [Service]

Самая важная часть. Ключевые параметры:

  • Type — тип службы. simple — если процесс не форкается (обычный скрипт). forking — если процесс уходит в фон. oneshot — для задач, выполняемых один раз. notify — если приложение поддерживает sd_notify.

  • ExecStart — команда запуска. Указывайте полный путь.

  • ExecStop — команда для остановки (опционально).

  • Restart — политика перезапуска: no, on-failure, always, on-abnormal.

  • User и Group — от какого пользователя запускать. Никогда не запускайте от root, если не требуется.

  • WorkingDirectory — рабочий каталог.

  • Environment — переменные окружения.

  • StandardOutput и StandardError — куда направлять вывод (по умолчанию в journal).

Пример с переменными окружения:

[Service]
Environment="PORT=8080"
Environment="DEBUG=false"
ExecStart=/usr/bin/python3 /opt/myapp/app.py

Шаг 6: Секция [Install]

Определяет, как служба включается в автозагрузку. WantedBy=multi-user.target означает, что служба будет запущена при переходе в многопользовательский режим (обычный запуск системы).

Шаг 7: Перезагрузка конфигурации systemd

После создания или изменения unit-файла выполните:

sudo systemctl daemon-reload

Это заставит systemd перечитать все unit-файлы.

Шаг 8: Запуск и проверка службы

Запустите службу:

sudo systemctl start hello.service

Проверьте статус:

sudo systemctl status hello.service

Вы увидите, активна ли служба, её PID и последние строки лога.

Шаг 9: Включение автозапуска

Чтобы служба запускалась при загрузке:

sudo systemctl enable hello.service

Отключить автозапуск можно командой disable.

Шаг 10: Просмотр логов

Логи службы доступны через journalctl:

journalctl -u hello.service

Для просмотра в реальном времени добавьте -f. Чтобы увидеть логи только за сегодня: journalctl -u hello.service --since today.

Шаг 11: Остановка и перезапуск

  • sudo systemctl stop hello.service — остановить.

  • sudo systemctl restart hello.service — перезапустить.

  • sudo systemctl reload hello.service — перечитать конфигурацию (если поддерживается).

Шаг 12: Настройка прав и безопасности

Systemd позволяет ограничить возможности службы. Полезные директивы в секции [Service]:

  • PrivateTmp=yes — изолирует /tmp.

  • NoNewPrivileges=yes — запрещает повышение привилегий.

  • ProtectSystem=full — монтирует /usr и /boot только для чтения.

  • ProtectHome=yes — скрывает домашние каталоги.

  • ReadWritePaths=/var/lib/myapp — разрешает запись только в указанные каталоги.

Пример:

[Service]
User=myuser
Group=myuser
PrivateTmp=yes
NoNewPrivileges=yes
ProtectSystem=full
ProtectHome=yes
ReadWritePaths=/var/lib/myapp

Шаг 13: Использование таймеров вместо cron

Systemd умеет запускать задачи по расписанию через таймеры. Создайте hello.timer:

[Unit]
Description=Run hello every hour

[Timer]
OnCalendar=hourly
Persistent=true

[Install]
WantedBy=timers.target

И службу hello.service с Type=oneshot. Затем включите таймер: sudo systemctl enable --now hello.timer.

Типичные ошибки

1. Забыли `daemon-reload` — изменения не применяются. 2. Относительные пути — systemd не находит скрипт. Используйте абсолютные пути. 3. Неверный `Type` — для скриптов, которые не завершаются, нужен simple, а не oneshot. 4. Запуск от root без необходимости — создаёт угрозу безопасности. 5. Отсутствие прав на файл — скрипт должен быть исполняемым. 6. Конфликт портов — если служба уже запущена вручную. 7. Неправильный `Restart` — always может привести к бесконечному циклу при ошибке конфигурации.

FAQ

Вопрос: Можно ли запускать службу от имени текущего пользователя без root? Ответ: Да, используйте systemctl --user и размещайте unit в ~/.config/systemd/user/. Не забудьте включить loginctl enable-linger, чтобы служба работала после выхода из системы.

Вопрос: Как передать переменные окружения из файла? Ответ: Используйте EnvironmentFile=/path/to/env в секции [Service].

Вопрос: Что делать, если служба сразу падает? Ответ: Проверьте логи через journalctl -u имя.service -e. Часто причина в неверном пути или отсутствии прав.

Вопрос: Как ограничить потребление памяти? Ответ: Добавьте MemoryMax=512M в секцию [Service].

Вопрос: Можно ли использовать systemd в Docker-контейнере? Ответ: Да, но требуются специальные настройки и привилегии. Обычно не рекомендуется.

Итог

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

Читайте также

Комментарии

Комментарии доступны только зарегистрированным пользователям. Войти

  • Пока нет комментариев. Будьте первым.