Ми часто бачимо, як навіть досвідчені розробники залишають кастомні сервіси на 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-файл для сервісу?
-
Визначити залежності. Вкажіть
AfterтаRequiresдля мережевих, БД та інших сервісів. -
Вибрати Type. Для демонів з форком —
forking, для скриптів та застосунків —simple. - Вказати ExecStart. Використовуйте абсолютний шлях до бінарю або скрипта. Shell-змінні не розкриваються.
- Налаштувати Restart. Для критичних сервісів —
alwaysабоon-failure. - Додати безпеку.
NoNewPrivileges=yes,PrivateTmp=yes, обмеження прав. - Перевірити та увімкнути.
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 обхідних шляхів та підвищити надійність.







