Skip to content

Запуск Axum как системный сервис с systemd

Systemd — это система инициализации и управления службами в Linux, которая позволяет запускать, останавливать и мониторить приложения Axum в качестве системных служб.

Содержание

Создание systemd-сервиса

Основной конфигурационный файл

Для запуска Axum-приложения как системной службы, создайте файл .service в директории /etc/systemd/system/:

bash
sudo nano /etc/systemd/system/axum-app.service

Базовая конфигурация:

ini
[Unit]
Description=Axum Web Service
After=network.target
Wants=network-online.target

[Service]
Type=simple
User=axumuser
Group=axumuser
WorkingDirectory=/opt/axum-app
ExecStart=/opt/axum-app/axum-server
Restart=on-failure
RestartSec=5s
Environment="RUST_LOG=info"

[Install]
WantedBy=multi-user.target

Подготовка окружения

  1. Создайте пользователя (для безопасности избегайте запуска от root):
bash
sudo useradd -r -s /bin/false axumuser
  1. Подготовьте директорию для приложения:
bash
sudo mkdir -p /opt/axum-app
sudo cp /path/to/your/axum-server /opt/axum-app/
sudo chown -R axumuser:axumuser /opt/axum-app
sudo chmod 755 /opt/axum-app/axum-server

Управление сервисом

Перезагрузка конфигурации systemd

После создания или изменения конфигурационного файла, выполните:

bash
sudo systemctl daemon-reload

Управление жизненным циклом

Чтобы запустить сервис:

bash
sudo systemctl start axum-app

Остановка сервиса:

bash
sudo systemctl stop axum-app

Перезапуск:

bash
sudo systemctl restart axum-app

Проверка статуса:

bash
sudo systemctl status axum-app

Автозапуск после перезагрузки

Чтобы сервис автоматически запускался после перезагрузки сервера:

bash
sudo systemctl enable axum-app

Отключение автозапуска:

bash
sudo systemctl disable axum-app

Настройка автоматического перезапуска

Systemd поддерживает различные стратегии перезапуска:

ini
[Service]
# Перезапуск при аварийном завершении
Restart=on-failure
# Пауза перед перезапуском (в секундах)
RestartSec=5

# Другие возможные значения Restart:
# always - всегда перезапускать независимо от причины завершения
# on-abnormal - перезапуск при аварийных сигналах или таймауте
# on-watchdog - перезапуск только при срабатывании сторожевого таймера
# on-abort - перезапуск только при получении сигнала аварийного завершения
# no - не перезапускать (по умолчанию)

Ограничение числа перезапусков

Предотвращение бесконечных перезапусков при стабильных сбоях:

ini
[Service]
Restart=on-failure
RestartSec=5s
# Максимум 3 перезапуска каждые 30 секунд
StartLimitIntervalSec=30
StartLimitBurst=3

# Что делать, если достигнут лимит перезапусков
StartLimitAction=none  # или reboot, poweroff

Управление зависимостями

Управление порядком запуска сервисов:

ini
[Unit]
# Запуск после сетевого подключения
After=network.target
# И после того, как база данных запущена
After=postgresql.service

# Если наш сервис зависит от базы данных
Requires=postgresql.service

# Опционально: если база данных не обязательна, но желательна
Wants=postgresql.service

Логирование

Systemd автоматически перехватывает вывод приложения и направляет его в журнал:

bash
# Просмотр логов сервиса
sudo journalctl -u axum-app

# Просмотр только последних 100 строк
sudo journalctl -u axum-app -n 100

# Отслеживание новых сообщений в реальном времени
sudo journalctl -u axum-app -f

Настройка логов в конфигурации

ini
[Service]
# Журналирование стандартного вывода и ошибок
StandardOutput=journal
StandardError=journal

# Дополнительные метаданные для журнала
SyslogIdentifier=axum-app

Мониторинг состояния

Базовый статус

bash
sudo systemctl status axum-app

Расширенная проверка здоровья

Systemd может контролировать здоровье сервиса через HTTP:

ini
[Service]
Type=simple
ExecStart=/opt/axum-app/axum-server

# Проверка здоровья каждые 30 секунд
ExecStartPost=/bin/sh -c 'sleep 5 && systemd-notify --ready'
WatchdogSec=30
# Скрипт, который проверяет работоспособность сервиса
ExecStartPre=/opt/axum-app/healthcheck.sh

Скрипт проверки здоровья healthcheck.sh:

bash
#!/bin/bash
# Простая проверка, что сервис отвечает на HTTP-запросы
response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/health)
if [ "$response" = "200" ]; then
    systemd-notify WATCHDOG=1
    exit 0
else
    exit 1
fi

Работа с переменными окружения

Указание переменных в конфигурации

ini
[Service]
Environment="DATABASE_URL=postgres://user:pass@localhost/mydb"
Environment="RUST_LOG=info"
Environment="PORT=3000"

Использование файла с переменными окружения

ini
[Service]
EnvironmentFile=/etc/axum-app/app.env

Файл /etc/axum-app/app.env:

DATABASE_URL=postgres://user:pass@localhost/mydb
RUST_LOG=info
PORT=3000
JWT_SECRET=your_secret_key

Лучшие практики

1. Ограничение ресурсов

ini
[Service]
# Ограничение CPU
CPUQuota=50%
# Ограничение памяти
MemoryLimit=512M
# Ограничение на количество файловых дескрипторов
LimitNOFILE=65535

2. Безопасность

ini
[Service]
# Запуск от непривилегированного пользователя
User=axumuser
Group=axumuser

# Дополнительные ограничения безопасности
ProtectSystem=full
ProtectHome=true
PrivateTmp=true
NoNewPrivileges=true
PrivateDevices=true

3. Уведомления при сбоях

Можно настроить отправку уведомлений при сбоях:

ini
[Service]
ExecStopPost=/opt/axum-app/notify_failure.sh

Скрипт notify_failure.sh:

bash
#!/bin/bash
if [ "$SERVICE_RESULT" = "failure" ]; then
    # Отправка уведомления в Slack, Telegram, по email и т.д.
    curl -X POST -H 'Content-type: application/json' \
    --data '{"text":"Axum service failed!"}' \
    https://hooks.slack.com/services/YOUR_WEBHOOK_URL
fi

4. Корректная обработка сигналов

В вашем Axum-приложении реализуйте обработку сигналов завершения для graceful shutdown:

rust
use tokio::signal;

#[tokio::main]
async fn main() {
    // Настройка приложения
    let app = Router::new()
        // ... маршруты и слои
        ;
    
    // Получение адреса из конфигурации
    let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
    
    // Запуск сервера с graceful shutdown
    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .with_graceful_shutdown(shutdown_signal())
        .await
        .unwrap();
}

async fn shutdown_signal() {
    let ctrl_c = async {
        signal::ctrl_c()
            .await
            .expect("Failed to install Ctrl+C handler");
    };

    #[cfg(unix)]
    let terminate = async {
        signal::unix::signal(signal::unix::SignalKind::terminate())
            .expect("Failed to install signal handler")
            .recv()
            .await;
    };

    #[cfg(not(unix))]
    let terminate = std::future::pending::<()>();

    tokio::select! {
        _ = ctrl_c => {},
        _ = terminate => {},
    }

    println!("Shutdown signal received, starting graceful shutdown");
}

5. Динамическая конфигурация

Для проектов, требующих разные конфигурации для разных окружений:

bash
# Создание файлов конфигурации для разных окружений
sudo mkdir -p /etc/axum-app/environments
sudo cp app.env.production /etc/axum-app/environments/production
sudo cp app.env.staging /etc/axum-app/environments/staging

И в сервис добавляем:

ini
[Service]
EnvironmentFile=/etc/axum-app/environments/%i

Затем можно запускать разные экземпляры:

bash
# Запуск продакшен-версии
sudo systemctl start axum-app@production

# Запуск staging-версии
sudo systemctl start axum-app@staging

6. Полный пример конфигурации

ini
[Unit]
Description=Axum Web Application
Documentation=https://github.com/yourusername/axum-app
After=network.target postgresql.service
Wants=network-online.target postgresql.service

[Service]
User=axumuser
Group=axumuser
WorkingDirectory=/opt/axum-app
ExecStart=/opt/axum-app/axum-server
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5s
StartLimitIntervalSec=60
StartLimitBurst=3

# Переменные окружения
EnvironmentFile=/etc/axum-app/app.env

# Ограничения ресурсов
CPUWeight=100
MemoryHigh=512M
MemoryMax=1G
LimitNOFILE=65535

# Безопасность
ProtectSystem=full
ProtectHome=true
PrivateTmp=true
NoNewPrivileges=true
CapabilityBoundingSet=
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectControlGroups=true

# Логирование
StandardOutput=journal
StandardError=journal
SyslogIdentifier=axum-app

[Install]
WantedBy=multi-user.target

7. Проверка и отладка

Проверка конфигурации:

bash
sudo systemd-analyze verify /etc/systemd/system/axum-app.service

Запуск с отладочной информацией:

bash
sudo SYSTEMD_LOG_LEVEL=debug systemctl start axum-app

Использование systemd для запуска Axum-приложений в качестве системных служб обеспечивает надежность, автоматическое восстановление при сбоях и интеграцию с экосистемой Linux. Это делает его идеальным выбором для развертывания веб-приложений в production-окружении.