Налаштування Systemd Unit файлів для керування сервісами
Додаток задеплоїли, але запускати його вручну через nohup ./app & — це не продакшен. Ми це проходили: без systemd сервіс живе до першого ребуту або падіння. Systemd — стандартний спосіб керувати сервісами на сучасних Linux-системах, і unit-файл визначає все: як запустити, як перезапустити при падінні, які ресурси виділити, в якому середовищі працювати. Наші інженери з 5-річним досвідом допоможуть налаштувати unit-файли під ключ — systemd реально спрощує життя. Замовте аудит ваших unit-файлів — це займе 2 дні.
Чому «просто запустити» не працює надійно
Типова ситуація: сервіс написаний як Node.js-додаток, запускається скриптом start.sh, працює під root, змінні середовища прописані прямо в скрипті. При ребуті сервера — тиша. Розробник заходить по SSH і запускає вручну. Через місяць про це всі забувають. За нашою статистикою, понад 80% таких сервісів мають проблеми з автозапуском або витоком ресурсів. В результаті простій сервісу обходиться бізнесу в десятки годин втраченого часу щомісяця.
Друга проблема — залежності. Якщо додаток стартує раніше PostgreSQL або Redis, він падає з ECONNREFUSED і більше не піднімається. Systemd вміє відстежувати залежності через After= і Requires=, але без правильного налаштування Type= і ExecStartPost= це працює ненадійно — сервіс стартував, але база ще не готова приймати з'єднання. Впровадження правильних unit-файлів скорочує кількість таких інцидентів на 70%.
Анатомія production-grade unit-файла
# /etc/systemd/system/myapp.service
[Unit]
Description=My Application Service
After=network-online.target postgresql.service
Wants=network-online.target
Requires=postgresql.service
[Service]
Type=notify
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
EnvironmentFile=/etc/myapp/env
ExecStart=/opt/myapp/bin/myapp --config /etc/myapp/config.yaml
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5s
TimeoutStartSec=30s
TimeoutStopSec=30s
# Обмеження ресурсів
LimitNOFILE=65536
MemoryMax=2G
CPUQuota=80%
# Ізоляція
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/lib/myapp /var/log/myapp
PrivateTmp=yes
[Install]
WantedBy=multi-user.target
Кілька деталей, які часто пропускають. Type=notify означає, що процес сам повідомляє systemd про готовність через sd_notify(3). Якщо додаток цього не робить — ставте Type=simple або Type=forking. Неправильний Type призводить до того, що залежні сервіси стартують раніше, ніж цей встигає ініціалізуватися.
EnvironmentFile=/etc/myapp/env — правильний спосіб передавати змінні середовища. Файл повинен містити рядки виду KEY=value, не потрібен export. Секрети в нього не кладуть відкритим текстом на проді — використовують або Vault з agent, або systemd credentials (LoadCredential=).
ProtectSystem=strict + ReadWritePaths= — мінімальний набір для ізоляції. Сервіс не може писати нікуди, крім явно дозволених шляхів. Ламає погано написані додатки, які пишуть логи в /tmp або ./logs — але це і є привід виправити.
Як працює socket activation в systemd?
Для сервісів з високим навантаженням при старті — socket activation дозволяє systemd тримати сокет відкритим, поки додаток ініціалізується:
# /etc/systemd/system/myapp.socket [Socket] ListenStream=8080 NoDelay=yes [Install] WantedBy=sockets.target Запити не губляться, навіть якщо сервіс перезапускається — systemd буферизує вхідні з'єднання. Це дає приріст надійності до 3x порівняно зі звичайним налаштуванням. На практиці такий підхід знижує час недоступності при рестартах на 95%.
Які ресурси можна контролювати в unit-файлі?
Systemd дозволяє гнучко обмежувати ресурси сервісу через директиви секції [Service]:
| Ресурс | Директива | Приклад |
|---|---|---|
| Пам'ять | MemoryMax= |
MemoryMax=2G |
| CPU | CPUQuota= |
CPUQuota=80% |
| Файлові дескриптори | LimitNOFILE= |
LimitNOFILE=65536 |
| Кількість процесів | TasksMax= |
TasksMax=100 |
| Швидкість дискового введення-виведення | IOReadBandwidthMax=, IOWriteBandwidthMax= |
IOReadBandwidthMax=/var/log 1M |
Ці обмеження запобігають ефекту «шумного сусіда» і захищають систему від перевантаження. У наших проектах ми часто комбінуємо MemoryMax і CPUQuota для стабільної роботи в умовах обмежених ресурсів.
Типові помилки при написанні unit-файлів
After=postgresql.service не гарантує, що база готова приймати з'єднання — тільки що unit запустився. Для реальної перевірки готовності використовуйте ExecStartPre= зі скриптом очікування:
ExecStartPre=/usr/bin/pg_isready -h localhost -p 5432 -U myapp -t 30 Restart=always при помилці конфігурації запустить нескінченний цикл. Systemd обмежує це через StartLimitIntervalSec= і StartLimitBurst=, але краще використовувати Restart=on-failure і моніторити через systemctl is-failed. Нижче порівняння популярних політик рестарту:
| Політика | Поведінка | Рекомендація |
|---|---|---|
no |
Не перезапускати | Для разових завдань |
on-failure |
Тільки при ненульовому коді виходу | Основний вибір для продакшену |
always |
При будь-якому завершенні | Тільки для критичних сервісів з захистом від циклу |
on-abnormal |
При сигналах і збоях | Для сервісів, які можуть коректно завершуватися |
Після зміни unit-файлу обов'язково: systemctl daemon-reload перед systemctl restart. Без цього systemd продовжує використовувати стару версію файлу з пам'яті.
Додаткові поради
- Використовуйте
systemd-analyze security myapp.serviceдля оцінки безпеки unit-файлу. - Для налагодження дивіться журнал:
journalctl -u myapp -f. - Налаштуйте сповіщення при збої:
OnFailure=myapp-failure-notify@%n.service.
Процес роботи
Аудит поточного стану: як запущені сервіси, чи є вже unit-файли, які залежності між компонентами. Проектування структури: користувачі, директорії, змінні середовища, політики рестарту. Написання unit-файлів з ізоляцією та обмеженнями ресурсів. Тестування на staging — systemd-analyze security myapp.service покаже оцінку безпеки, journalctl -u myapp -f — логи в реальному часі.
| Масштаб | Термін |
|---|---|
| 1–3 сервіси, прості залежності | 4–8 годин |
| 5–10 сервісів з socket activation | 1–2 дні |
| Повний аудит + переробка + документація | 2–3 дні |
Вартість розраховується індивідуально після аудиту поточної конфігурації сервісів. Зв'яжіться — ми оцінимо ваш проект.
Що входить в роботу
- Аудит існуючих unit-файлів та скриптів запуску
- Проектування структури сервісів (користувачі, шляхи, оточення)
- Написання unit-файлів з ізоляцією та обмеженнями
- Налаштування socket activation для високонавантажених компонентів
- Тестування на staging та налаштування моніторингу через
journalctlіsystemctl - Документація з обслуговування та інструкція з деплою
- Підтримка протягом 30 днів після здачі
Замовте налаштування systemd unit-файлів — ваші сервіси будуть працювати стабільно та без ручного втручання.







