Мы часто видим, как даже опытные разработчики оставляют кастомные сервисы на 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 костылей и повысить надёжность.







