🔧 Полный гайд по systemctl и unit-файлам (systemd)

Platform Category Tools


📑 Содержание


Что такое systemd / systemctl

systemd — это init-система и менеджер служб, которая управляет запуском системы, служб, сокетов, таймеров и т.д. systemctl — основной инструмент для взаимодействия с systemd (запуск/остановка/включение/отладка юнитов).

systemd использует unit-файлы (юниты) разного типа: .service, .socket, .timer, .target, .mount, .path и другие.


Основные команды systemctl

Краткий справочник — самое часто используемое:


Где хранятся unit-файлы и приоритет (важно)

Типичные пути (приоритет сверху вниз — чем выше, тем важнее):

  1. /etc/systemd/system/ — администратора: локальные изменения и overrides. (высокий приоритет)
  2. /run/systemd/system/ — runtime-юниты, генерируются в процессе работы.
  3. /lib/systemd/system/ или /usr/lib/systemd/system/ — поставщик пакета (поставляются дистрибутивом). (низкий приоритет)

Также пользовательские юниты:

Важно: правка файлов в /lib/systemd/system/ не рекомендуется — при обновлении пакета изменения могут быть перезаписаны. Правильный способ — поместить override в /etc/systemd/system/<unit>.d/ или использовать systemctl edit.


Структура unit-файла (на примере .service)

Unit-файл — обычный INI-файл с секциями:

[Unit]
Description=My background service
Documentation=man:myservice(8)
After=network.target
Requires=network.target
Wants=postgresql.service

[Service]
Type=simple
User=svcuser
Group=svcgroup
WorkingDirectory=/opt/myapp
Environment=ENV=prod
EnvironmentFile=/etc/default/myapp
ExecStart=/usr/bin/myapp --config /etc/myapp/config.yml
ExecStartPre=/usr/bin/myapp-prep
ExecStop=/bin/kill -TERM $MAINPID
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
PrivateTmp=true
ProtectSystem=full

[Install]
WantedBy=multi-user.target

Ключевые секции и опции:


Создание собственного .service — шаги и рекомендации

  1. Создаём unit в /etc/systemd/system/:

    sudo tee /etc/systemd/system/myapp.service > /dev/null <<'EOF'
    [Unit]
    Description=MyApp background service
    After=network.target
    
    [Service]
    Type=simple
    User=myapp
    Group=myapp
    WorkingDirectory=/opt/myapp
    ExecStart=/usr/bin/myapp --config /etc/myapp/config.yml
    Restart=on-failure
    RestartSec=5
    LimitNOFILE=65536
    PrivateTmp=true
    
    [Install]
    WantedBy=multi-user.target
    EOF
    
  2. Перечитать конфигурацию systemd:

    sudo systemctl daemon-reload
    
  3. Включить автозапуск и запустить:

    sudo systemctl enable --now myapp.service
    
  4. Проверить статус и логи:

    sudo systemctl status myapp.service
    sudo journalctl -u myapp.service -b --no-pager
    

Советы:


Шаблонные unit-файлы (instance units) — @-юниты

Шаблонный unit позволяет запускать несколько экземпляров одной службы с разными параметрами: myservice@instance.service.

Пример /etc/systemd/system/web@.service:

[Unit]
Description=Web instance %i
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/web --name %i --config /etc/web/%i.conf

[Install]
WantedBy=multi-user.target

Запуск экземпляра:

sudo systemctl start web@front.service
sudo systemctl enable --now web@front.service

В шаблоне %i — «instance name» (часть после @), %f — с escape, %n — полное имя юнита.


Drop-in и systemctl edit — безопасная кастомизация

Вместо изменения оригинальных файлов пакета используйте drop-in или systemctl edit:

[Service]
Environment=NEW_VAR=1
Restart=always

Mask / Unmask — зачем маскировать службы

mask создаёт символическую ссылку … -> /dev/null, после чего systemctl start и другие команды не смогут запустить юнит (даже если попытаться зависимостью). Это надёжный способ запретить запуск сервиса (вручную или автоматически).

sudo systemctl mask foo.service
# Проверка:
systemctl is-enabled foo.service   # вернёт "masked"
# Снятие маски:
sudo systemctl unmask foo.service

Когда использовать:

Не путать с disable: disable лишь убирает автозапуск, mask — запрещает вообще.


Таймеры и socket-активация

.timer — планировщик systemd (замена cron для юнитов)

Создаёт юнит, который вызывает .service по расписанию или через OnBootSec/OnActiveSec.

Пример: /etc/systemd/system/backup.timer и backup.service

backup.timer:

[Unit]
Description=Daily backup timer

[Timer]
OnCalendar=daily
Persistent=true

[Install]
WantedBy=timers.target

backup.service — обычный сервис, исполняющий бэкап.

Запуск:

sudo systemctl enable --now backup.timer
systemctl list-timers

.socket — socket-activated services

systemd слушает сокет и запускает службу по подключению. Это экономит ресурсы и полезно для on-demand сервисов.

myapp.socket:

[Socket]
ListenStream=12345

[Install]
WantedBy=sockets.target

myapp@.service — можно настроить StandardInput=socket или использовать шаблон.


Жизненный цикл службы: нюансы

Про daemon-reload: После любого изменения unit-файла или добавления — выполнить systemctl daemon-reload. Это не перезапускает службы — только перечитывает конфигурацию systemd.


Параметры перезапуска и поведение при падении

Restart= — ключевой для надежности:

Полезные опции:

Если служба «падает» часто, systemd пометит её failed; systemctl reset-failed сбросит флаг.


Безопасность: ограничиваем привилегии unit-ов

Systemd предоставляет много опций безопасности — используй их по мере возможности:

Рекомендация: по умолчанию запускай сервисы от неправавного пользователя и используй ProtectSystem, PrivateTmp и NoNewPrivileges когда возможно.


Отладка и логирование

Проверка переменных окружения:


Полезные приёмы и чеклист для продакшн-служб

  1. Drop-in вместо редактирования пакета — используем systemctl edit.
  2. Unit должен корректно реагировать на SIGTERM/SIGINT — systemd шлёт SIGTERM при stop.
  3. Укажите Restart=on-failure и корректные RestartSec=.
  4. Ограничте ресурсы: LimitNOFILE=, LimitNPROC=, CPUQuota= при необходимости.
  5. Логи: пишите в stdout/stderr — systemd capture через journal.
  6. Healthcheck: используйте WatchdogSec= + Type=notify для автоматического обнаружения зависания.
  7. Тестирование: проверяйте systemctl daemon-reloadsystemctl startjournalctl -u.
  8. Документируйте Description= и Documentation= в unit-файле.
  9. Тестовый режим: systemctl start --no-block при асинхронных стартах, но чаще — избегать.
  10. CI/CD: при доставке юнитов через пакетный менеджер используйте systemctl preset или systemctl enable в postinst.

Примеры unit-файлов

1) Простая web-служба (/etc/systemd/system/myweb.service)

[Unit]
Description=Simple HTTP server
After=network.target

[Service]
Type=simple
User=www-data
WorkingDirectory=/srv/myweb
ExecStart=/usr/bin/python3 -m http.server 8080
Restart=on-failure
PrivateTmp=true
ProtectSystem=full

[Install]
WantedBy=multi-user.target

2) Форкающийся демон (Type=forking)

[Unit]
Description=Legacy daemon

[Service]
Type=forking
ExecStart=/usr/sbin/legacy-daemon -D
PIDFile=/var/run/legacy.pid
Restart=on-failure

3) Таймер + service (backup.timer + backup.service)

backup.timer:

[Unit]
Description=Daily backup timer

[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true

[Install]
WantedBy=timers.target

backup.service — запускает скрипт бэкапа.


Короткие ресурсы для дальнейшего чтения


Заключение

Этот гайд даёт фундамент для: