Настройка 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-файлов — ваши сервисы будут работать стабильно и без ручного вмешательства.







