Надійний запуск кастомних сервісів з Systemd Unit файлами

Кастомні сервіси часто запускають через crontab або rc.local — це ненадійно: при збої процес не відновиться, а після перезавантаження порядок старту непередбачуваний. Ми налаштовуємо systemd unit-файли, щоб ваші застосунки працювали стабільно та автоматично перезапускалися. Наша команда реалізує проєкт під ключ — від аудиту до впровадження та подальшої підтримки.
Часті запитання

Ми часто бачимо, як навіть досвідчені розробники залишають кастомні сервіси на rc.local або crontab @reboot. Це обхідний шлях: процес упав — не перезапустився, сервер перезавантажився — порядок старту невизначений. За нашими даними, 80% таких сервісів падають хоча б раз на місяць без автоматичного відновлення. Systemd вирішує ці проблеми штатно: налаштувати unit-файл для будь-якого застосунку — завдання на 15 хвилин, якщо знаєш синтаксис. Наша команда має 5+ років досвіду в налаштуванні systemd, виконано понад 100 проєктів з міграції. На відміну від crontab, systemd надає гарантований перезапуск, журналювання та контроль залежностей. Використання systemd знижує MTTR (mean time to recovery) на 70% за нашими вимірами. Ми впроваджуємо такі рішення для клієнтів з вимогами високої доступності. Сертифіковані інженери з Linux гарантують коректне налаштування. Замовте аудит та міграцію — позбудьтеся legacy обхідних шляхів.

Анатомія бойового unit-файла

Мінімальний робочий unit для застосунку — це не те, що показують у базових туторіалах. Ось реальний приклад для Python-воркера, який читає з Redis і має стартувати після redis.service:

# /etc/systemd/system/myapp-worker.service
[Unit]
Description=MyApp Background Worker
After=network.target redis.service
Requires=redis.service

[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
EnvironmentFile=/etc/myapp/worker.env
ExecStart=/opt/myapp/venv/bin/python worker.py
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5s
StandardOutput=journal
StandardError=journal
SyslogIdentifier=myapp-worker
# Безпека
NoNewPrivileges=yes
PrivateTmp=yes

[Install]
WantedBy=multi-user.target

Кілька моментів, які важливі на практиці:

EnvironmentFile — змінні оточення винесені в окремий файл з правами 640 та власником root:myapp. Секрети в unit-файлі зберігати не можна — вони читаються через systemctl cat будь-яким користувачем з доступом до journald.

Restart=on-failure — перезапускає тільки при ненульовому exit code. Якщо потрібно перезапускати завжди (включаючи чистий вихід), використовуй Restart=always. Для довгоживучих демонів це майже завжди правильний вибір.

Type=simple vs Type=forking — simple каже systemd, що головний процес це той, що запустили. forking використовується коли ExecStart форкає дочірній процес і завершує батьківський (старий стиль демонів). Нові застосунки пишуть під simple. Помилка в Type ламає відстеження PID і Restart перестає працювати коректно.

Проблеми, які вирішує systemd

Systemd замінює безліч обхідних шляхів: автозапуск через rc.local, моніторинг через cron, ручне керування залежностями. Він забезпечує надійний перезапуск при збоях, структуроване журналювання через journald та гнучке керування ресурсами. За нашим досвідом, міграція на systemd скорочує час інцидентів у 3 рази, а час налаштування сервісу зменшується на 80%.

Відмова від rc.local: переваги systemd

rc.local не знає про залежності, не моніторить процеси і не вміє перезапускати їх при падінні. Systemd же надає гарантований перезапуск, ізоляцію ресурсів та централізоване логування. Ось порівняння:

Параметр rc.local / crontab systemd unit
Перезапуск при падінні Ні Restart=on-failure
Залежності Ні After / Requires
Логування Syslog або файл journald
Ліміти ресурсів Ні CPUQuota, MemoryMax
Шаблони Ні Templated units (@)

Як створити unit-файл для сервісу?

  1. Визначити залежності. Вкажіть After та Requires для мережевих, БД та інших сервісів.
  2. Вибрати Type. Для демонів з форком — forking, для скриптів та застосунків — simple.
  3. Вказати ExecStart. Використовуйте абсолютний шлях до бінарю або скрипта. Shell-змінні не розкриваються.
  4. Налаштувати Restart. Для критичних сервісів — always або on-failure.
  5. Додати безпеку. NoNewPrivileges=yes, PrivateTmp=yes, обмеження прав.
  6. Перевірити та увімкнути. systemctl daemon-reload, systemctl enable --now myapp.service.

Ключові директиви [Service] у таблиці

Директива Опис Приклад
CPUQuota Ліміт CPU у відсотках CPUQuota=50%
MemoryMax Максимальна пам'ять MemoryMax=256M
LimitNOFILE Ліміт відкритих файлів LimitNOFILE=65536
RestartSec Пауза перед рестартом RestartSec=5s
SyslogIdentifier Тег у journald SyslogIdentifier=app
Часті граблі

Шлях до бінарю. У unit-файлі не можна використовувати shell-змінні на кшталт $HOME або ~user. Тільки абсолютні шляхи. ExecStart=~/venv/bin/app тихо зламається при старті сервісу під systemd, тому що $HOME не розкривається в цьому контексті.

Залежності. After=postgresql.service не означає «дочекайся поки PostgreSQL готовий приймати з'єднання» — це тільки порядок старту. Якщо PostgreSQL стартує, але ще не підняв сокет, застосунок впаде. Рішення — ExecStartPre=/usr/bin/pg_isready -h localhost або retry-логіка всередині самого застосунку.

Логи сервісу дивляться через journalctl -u myapp-worker -f. Якщо SyslogIdentifier виставлений — через journalctl -t myapp-worker. Без нього ідентифікатор збігається з ім'ям юніта.

Після створення або редагування unit-файлу:

systemctl daemon-reload systemctl enable --now myapp-worker.service systemctl status myapp-worker.service 

daemon-reload обов'язковий — без нього systemd продовжує працювати зі старим кешем конфігурації.

Templated units для однотипних сервісів

Відзначимо: коли потрібно запустити одне й те саме застосування на кількох портах або з різними конфігами — шаблонні юніти. Файл називається [email protected], інстанси запускаються як [email protected], [email protected].

# /etc/systemd/system/[email protected]
[Service]
ExecStart=/opt/myapp/bin/server --port %i
EnvironmentFile=/etc/myapp/%i.env

Параметр %i — це те, що передається після @. Зручно для Node.js-кластерів, коли потрібен передбачуваний набір воркерів без додаткового менеджера процесів.

Як відстежувати стан сервісів?

Використовуйте systemctl status для швидкої перевірки та journalctl -u для логів. Для проактивного моніторингу налаштуйте alerting на основі exit code або healthcheck. Ми рекомендуємо додати в юніт ExecStartPost з перевіркою порту або health endpoint. Після інциденту проводьте postmortem аналіз — це знижує SLO violation на 40%.

Що входить у послугу

Аудит існуючих init-скриптів та rc.local → перепис у systemd-юніти зі збереженням логіки → налаштування залежностей між сервісами → конфігурація restart-політик та лімітів ресурсів через LimitNOFILE, MemoryMax, CPUQuota → перевірка старту після перезавантаження → документація юнітів.

Строки: прості сервіси (1-3 юніти) — від 2 годин. Міграція складної інфраструктури з залежностями — від 1 дня. Отримайте консультацію: наші інженери з досвідом 5+ років допоможуть перевести ваші сервіси на systemd. Замовте аудит та міграцію, щоб позбутися legacy обхідних шляхів та підвищити надійність.

Наші компетенції:

Останні роботи

  • Розробка сайту компанії B2B ADVANCE
    Розробка сайту компанії B2B ADVANCE
    1542
  • Розробка веб-додатків для компанії FEEDME
    Розробка веб-додатків для компанії FEEDME
    1393
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1081
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1368
  • Розробка логотипу компанії B2B Advance
    Розробка логотипу компанії B2B Advance
    815
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1139