Введение
Systemd — стандартный менеджер служб в современных дистрибутивах Linux. Понимание systemd необходимо для развёртывания и управления приложениями в production — от запуска служб при загрузке до мониторинга их состояния, управления зависимостями и проверок работоспособности. В этом руководстве рассматриваются практические аспекты администрирования systemd для развёртывания приложений.
Основы управления службами
Часто используемые команды
# Запуск/остановка/перезапуск службы
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx
# Перезагрузка конфигурации без перезапуска
sudo systemctl reload nginx
# Включить/отключить службу при загрузке
sudo systemctl enable nginx
sudo systemctl disable nginx
# Включить и запустить одной командой
sudo systemctl enable --now nginx
# Проверить статус службы
sudo systemctl status nginx
# Показать список всех служб
sudo systemctl list-units --type=service
# Показать список включённых служб
sudo systemctl list-unit-files --type=service --state=enabled
Вывод статуса службы
● nginx.service - A high performance web server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2024-01-15 10:30:00 UTC; 5h ago
Docs: man:nginx(8)
Main PID: 1234 (nginx)
Tasks: 5 (limit: 4915)
Memory: 12.5M
CPU: 1.234s
CGroup: /system.slice/nginx.service
├─1234 nginx: master process /usr/sbin/nginx
└─1235 nginx: worker process
Ключевые индикаторы:
- Active: Текущее состояние (running, dead, failed)
- Main PID: Идентификатор процесса (PID) основного процесса
- Memory/CPU: Использование ресурсов
Создание пользовательских служб
Базовый unit-файл службы
# /etc/systemd/system/myapp.service
[Unit]
Description=My Application
Documentation=https://myapp.example.com/docs
After=network.target
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/myapp
ExecStart=/usr/bin/node /var/www/myapp/server.js
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
# Применить изменения
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
Типы служб
# Simple (по умолчанию): основной процесс и есть служба
Type=simple
ExecStart=/usr/bin/myapp
# Forking: процесс форкается, а родительский процесс завершается
Type=forking
PIDFile=/var/run/myapp.pid
ExecStart=/usr/bin/myapp --daemon
# Oneshot: процесс выполняется один раз и завершается
Type=oneshot
ExecStart=/usr/bin/setup-script.sh
RemainAfterExit=yes
# Notify: процесс сигнализирует о готовности
Type=notify
ExecStart=/usr/bin/myapp --notify
Конфигурация окружения
[Service]
# Переменные окружения inline
Environment=NODE_ENV=production
Environment=PORT=3000
# Файл окружения
EnvironmentFile=/etc/myapp/environment
# Несколько файлов окружения
EnvironmentFile=-/etc/myapp/environment # - означает опционально
EnvironmentFile=/etc/myapp/secrets
# /etc/myapp/environment
NODE_ENV=production
PORT=3000
DATABASE_URL=postgres://localhost/myapp
Ограничения ресурсов
Память и CPU
[Service]
# Ограничения памяти
MemoryMax=512M
MemoryHigh=400M
# Ограничения CPU
CPUQuota=50%
CPUWeight=100
# Файловые дескрипторы
LimitNOFILE=65535
# Ограничения по числу процессов
LimitNPROC=4096
# Core dumps
LimitCORE=infinity
Ограничения I/O
[Service]
IOWeight=500
IOReadBandwidthMax=/dev/sda 10M
IOWriteBandwidthMax=/dev/sda 5M
Усиление безопасности
Параметры изоляции
[Service]
# Запуск от имени не-root
User=myapp
Group=myapp
# Ограничения файловой системы
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/lib/myapp /var/log/myapp
ReadOnlyPaths=/etc/myapp
# Временный каталог
PrivateTmp=yes
# Сетевая изоляция
PrivateNetwork=yes # Без доступа к сети
# Доступ к устройствам
PrivateDevices=yes
# Запрет повышения привилегий
NoNewPrivileges=yes
# Фильтрация системных вызовов
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM
Ограничения capabilities
[Service]
# Сбросить все capabilities, кроме необходимых
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
# Удалить все capabilities
CapabilityBoundingSet=
Надзор за процессами
Политики перезапуска
[Service]
# Параметры перезапуска: no, on-success, on-failure, on-abnormal, on-watchdog, on-abort, always
Restart=on-failure
# Интервал между перезапусками
RestartSec=5s
# Максимальное число попыток перезапуска
StartLimitIntervalSec=300
StartLimitBurst=5
# Действия при достижении лимита
# FailureAction=reboot
# SuccessAction=poweroff
Watchdog
[Service]
Type=notify
WatchdogSec=30s
# Приложение должно периодически вызывать sd_notify(0, "WATCHDOG=1")
Команды до/после запуска
[Service]
ExecStartPre=/usr/bin/check-config.sh
ExecStart=/usr/bin/myapp
ExecStartPost=/usr/bin/notify-started.sh
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/usr/bin/graceful-stop.sh
ExecStopPost=/usr/bin/cleanup.sh
Логирование с помощью Journal
Просмотр логов
# Логи службы
sudo journalctl -u myapp
# Следовать за логами
sudo journalctl -u myapp -f
# Последние 100 строк
sudo journalctl -u myapp -n 100
# С момента загрузки
sudo journalctl -u myapp -b
# Диапазон времени
sudo journalctl -u myapp --since "2024-01-15 10:00:00" --until "2024-01-15 12:00:00"
# Фильтр по приоритету (err и выше)
sudo journalctl -u myapp -p err
# Вывод в JSON
sudo journalctl -u myapp -o json
# Использование диска
sudo journalctl --disk-usage
Конфигурация логов
[Service]
# Отправлять вывод в journal
StandardOutput=journal
StandardError=journal
# Или в файл
StandardOutput=append:/var/log/myapp/output.log
StandardError=append:/var/log/myapp/error.log
# Идентификатор syslog
SyslogIdentifier=myapp
Персистентность Journal
# Сделать логи персистентными
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
# Настроить хранение
sudo vi /etc/systemd/journald.conf
# SystemMaxUse=500M
# MaxRetentionSec=1month
sudo systemctl restart systemd-journald
Таймеры (замена cron)
Unit-файл таймера
# /etc/systemd/system/backup.timer
[Unit]
Description=Daily backup timer
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
# /etc/systemd/system/backup.service
[Unit]
Description=Backup service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
Расписания таймеров
# Выражения календаря
OnCalendar=hourly
OnCalendar=daily
OnCalendar=weekly
OnCalendar=monthly
OnCalendar=*-*-* 00:00:00 # Ежедневно в полночь
OnCalendar=Mon *-*-* 00:00:00 # Каждый понедельник
OnCalendar=*-*-* *:00:00 # Каждый час
OnCalendar=*-*-* *:*:00 # Каждую минуту
# Относительное время
OnBootSec=5min # Через 5 минут после загрузки
OnUnitActiveSec=1h # Через 1 час после последней активации
Управление таймерами
# Список таймеров
sudo systemctl list-timers
# Включить таймер
sudo systemctl enable --now backup.timer
# Немедленно запустить связанную службу
sudo systemctl start backup.service
Активация по сокету
# /etc/systemd/system/myapp.socket
[Unit]
Description=My App Socket
[Socket]
ListenStream=8080
Accept=no
[Install]
WantedBy=sockets.target
# /etc/systemd/system/myapp.service
[Unit]
Description=My App
Requires=myapp.socket
[Service]
ExecStart=/usr/bin/myapp
StandardInput=socket
Служба запускается только при получении подключения на сокет.
Мультиинстанс-службы
# /etc/systemd/system/[email protected]
[Unit]
Description=My App instance %i
[Service]
ExecStart=/usr/bin/myapp --instance %i --port %i
User=www-data
[Install]
WantedBy=multi-user.target
# Запустить несколько инстансов
sudo systemctl enable --now myapp@3000
sudo systemctl enable --now myapp@3001
sudo systemctl enable --now myapp@3002
# Управлять всеми инстансами
sudo systemctl restart 'myapp@*'
Отладка
# Проверить синтаксис unit-файла
sudo systemd-analyze verify /etc/systemd/system/myapp.service
# Показать конфигурацию unit
sudo systemctl show myapp
# Показать зависимости unit
sudo systemctl list-dependencies myapp
# Проверить производительность загрузки
systemd-analyze
systemd-analyze blame
systemd-analyze critical-chain myapp.service
Лучшие практики
- Используйте
Type=notify по возможности для точного статуса. - Задавайте подходящие политики перезапуска для устойчивости.
- Применяйте параметры усиления безопасности.
- Используйте environment files для конфигурации.
- Настраивайте ограничения ресурсов, чтобы предотвратить неконтролируемые процессы.
- Используйте таймеры вместо cron для задач по расписанию.
- Мониторьте через journalctl и настраивайте хранение логов.
Заключение
Systemd предоставляет мощные возможности управления службами. Создавайте корректные unit-файлы с усилением безопасности, настраивайте подходящие политики перезапуска и используйте таймеры для задач по расписанию. Шаблоны из этого руководства помогут вам развёртывать и сопровождать надёжные production-службы.