.service-файл размещают в предназначенном для администратора каталоге, выполняют systemctl daemon-reload, а затем отдельно запускают службу и при необходимости включают автозагрузку. Пользователя, окружение, зависимости и перезапуск задают директивами unit-файла, а первичную проверку выполняют через systemctl и journalctl.Где хранить собственный service unit
Service unit — это вид Systemd unit, описывающий управляемую системную службу. Для постоянной локальной конфигурации обычно используют /etc/systemd/system/имя.service. Каталог /run/systemd/system/ предназначен для unit-файлов, созданных на время тек ущей загрузки: после перезагрузки его содержимое исчезает.
Файлы, поставленные пакетами, обычно находятся в каталогах вроде /usr/lib/systemd/system/, /lib/systemd/system/ или другом пути из unit load path конкретного дистрибутива. Состав путей зависит от дистрибутива и версии systemd. Определение с тем же именем в /etc/systemd/system/ имеет более высокий приоритет, чем пакетное, поэтому локальный файл может полностью заменить unit пакета.
Не редактируйте unit-файлы пакетов напрямую
/etc/systemd/system/имя.service.d/. Drop-in-конфигурации объединяются с основным unit-файлом; одноимённый drop-in из /etc имеет приоритет над вариантом из /run и каталогов поставщика. Порядок нескольких файлов определяется их именами. Точные правила загрузки и перечень каталогов смотрите в man pages systemd.unit и systemd.directives вашей системы.Unit для постоянно работающего приложения
Ниже — заменяемый шаблон для приложения, которое должно работать постоянно. Пути /opt/example/bin/app, /etc/example-app/example-app.env, каталог /opt/example/app и имя appuser — примеры, а не обязательные значения.
[Unit]
Description=Example application
StartLimitIntervalSec=60
StartLimitBurst=5
[Service]
Type=exec
User=appuser
Group=appuser
WorkingDirectory=/opt/example/app
EnvironmentFile=/etc/example-app/example-app.env
ExecStart=/opt/example/bin/app --config /etc/example-app/config.yaml
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.targetТакой unit не зависит от того, является /opt/example/bin/app бинарным файлом или скриптом. Существенно поведение: главный процесс должен продолжать работать, пока служба активна. Если программа сама отделяется от родительского процесса, создаёт PID-файл или работает по иной модели, нужны настройки по документации приложения; переносить этот шаблон без проверки нельзя.
Директивы шаблона
| Директива | Назначение |
|---|---|
Type=exec | systemd считает запуск успешным после успешного execve() программы. Этот тип удобен, когда важно получить ошибку отсутствующего или неисполняемого файла уже при старте unit. |
User= и Group= | Запускают процесс от заранее созданной учётной записи пользователя и основной либо явно указанной группы пользователей, а не от root. |
WorkingDirectory= | Устанавливает рабочий каталог процесса. Относительные пути, которые использует само приложение, будут отсчитываться от него. |
EnvironmentFile= | Загружает переменные окружения из отдельного файла в синтаксисе, который понимает systemd. Это не произвольный скрипт shell. |
ExecStart= | Задаёт запускаемую программу и её аргументы. |
StandardOutput= и StandardError= | Явно направляют стандартный вывод и поток ошибок в journal. |
Type=simple во многих конфигурациях является значением по умолчанию: systemd начинает последующие действия сразу после fork процесса, не дожидаясь результата execve(). Type=exec ждёт успешного выполнения execve() и потому иначе отражает ранние ошибки запуска. Доступность и детали Type=exec нужно сверить с systemd.service целевой версии: на старых выпусках этот тип может отсутствовать. Ни simple, ни exec не означают «для бинарного файла» или «для скрипта».
ExecStart= не является строкой командной оболочки. systemd не обрабатывает неявно пайпы, >, 2>&1, &&, подстановки и другие конструкции shell. Для последовательности команд или пайпа создайте отдельный исполняемый скрипт-обёртку либо явно вызовите нужную оболочку, например /bin/sh -c ...; второй вариант требует аккуратного экранирования и осознанной обработки входных данных.
Форма ExecStart
ExecStart=/opt/example/bin/app .... Согласно systemd.service, в версиях, поддерживающих это правило, первым аргументом также может быть простое имя исполняемого файла без разделителей каталогов: systemd ищет его в собственном фиксированном пути поиска. Путь с / должен быть абсолютным. Скрипт можно запускать напрямую, если файл доступен для выполнения, имеет корректный shebang и указанный в нём интерпретатор доступен; альтернативно явно указывают интерпретатор, например ExecStart=/usr/bin/python3 /opt/example/bin/app.py. Проверьте эти условия в до кументации используемой версии systemd и приложения.Пользователь, рабочий каталог и файл окружения
До запуска убедитесь, что appuser уже существует и может пройти по всем каталогам в пути к программе, прочитать конфигурацию и файл окружения, а также читать или записывать нужные приложению данные. Это определяется владельцем файла, группой и правами доступа к файлам. Если приложение открывает сокет, журнал или каталог для временных файлов, доступ нужен и к этим объектам.
sudo -u appuser test -x /opt/example/bin/app && sudo -u appuser test -r /etc/example-app/example-app.env && echo OKOKНе помещайте в EnvironmentFile= секреты, если права на файл и модель хранения секретов не оценены отдельно: переменные окружения не являются универсальным защищённым хранилищем. Создание пользователей, назначение групп и изменение прав разобраны в статье «Пользователи, группы, sudo и права файлов в Linux».
Перезапуск и лимит неудачных запусков
Restart=on-failure повторно запускает службу при неуспешном завершении: например, при ненулевом коде выхода, сигнале, тайм-ауте или срабатывании watchdog. Он не перезапускает процесс после штатного выхода с кодом 0 и ряда ожидаемых сигналов завершения, а также после явной остановки через systemctl stop. Для другого поведения есть Restart=always, on-success, on-abnormal, on-abort и on-watchdog; выбирайте режим по тому, какие исходы приложение считает нормальными.
RestartSec=5 задаёт паузу перед очередной попыткой. StartLimitIntervalSec=60 и StartLimitBurst=5 в секции [Unit] ограничивают число запусков за заданный интервал. После превышения лимита systemd отклоняет новые попытки; когда предыдущие попытки выйдут за пределы интервала, запуск снова станет возможен. Команда systemctl reset-failed имя.service сбрасывает состояние failed и счётчик ограничения запусков. Эти параметры не исправляют неверный путь в ExecStart=, отсутствующую конфигурацию, ошибку приложения или недостаточные права.
Ограничение Type=oneshot
Type=oneshot нельзя сочетать Restart=always или Restart=on-success. Другие варианты перезапуска и их смысл проверяйте по systemd.service вашей версии. Не превращайте однократную задачу в бесконечный цикл перезапусков: причина постоянной ошибки должна быть устранена.Unit для однократной задачи
Если команда должна выполниться и завершиться, используйте Type=oneshot. Это также не зависит от того, написана задача как скрипт или скомпилированная программа.
[Unit]
Description=Example one-time maintenance task
[Service]
Type=oneshot
User=appuser
WorkingDirectory=/opt/example/app
ExecStart=/opt/example/bin/maintenance --cleanupПосле успешного выполнения такой unit обычно становится inactive (dead): задача завершена, а процесса больше нет. RemainAfterExit=yes меняет это представление на active (exited), но не оставляет программу работающей. Если задача должна запускаться по времени, используйте systemd timer или cron — это отдельный сценарий из статьи «Cron и systemd timers: задачи по расписанию и диагностика сбоев».
Как задать зависимости и порядок запуска
After= и Before= задают только порядок, когда systemd запускает оба unit. Wants= и Requires= задают зависимости запуска. Wants= пытается активировать указанный unit вместе с текущим, но неудача или остановка желательного unit сама по себе обычно не делает текущий unit неуспешным. Requires= сильнее: systemd также активирует обязательный unit, а его явная остановка приводит к остановке зависимого. Чтобы не запускать текущий unit при неудачной активации обязательного, обычно сочетают Requires= с After=. Эти директивы сами по себе не подтверждают готовность службы и не гарантируют совместную активность после любого самопроизвольного сбоя.
[Unit]
Wants=example-cache.service
After=example-cache.serviceВ этом примере приложение хочет запустить example-cache.service и, если оба запускаются в одной транзакции, будет запущено после него. Одного After= недостаточно, чтобы подтянуть cache-службу в запуск; одного Wants= недостаточно, чтобы обеспечить порядок. Поэтому ordering dependency и requirement dependency решают разные задачи и часто применяются вместе. Если без внешней службы приложение неработоспособно, вместо Wants= может потребоваться Requires=, но это нужно подтвержд ать поведением приложения.
Порядок не равен готовности
After=network.target означает порядок относительно target, а не гарантирует доступность конкретного удалённого сервиса. Для сетевых, базовых и иных зависимостей используйте unit и условия готовности, которые документированы для конкретного приложения и дистрибутива.Перечитать unit, запустить службу и включить автозагрузку
Создать systemd service и применить конфигурацию
Команды ниже выполняются после сохранения /etc/systemd/system/example-app.service. Имя unit в командах соответствует имени файла.
- 1Проверьте синтаксис и ссылки unit-файлаВ системах, где утилита доступна, выполните
sudo systemd-analyze verify /etc/systemd/system/example-app.service. Она помогает обнаружить часть ошибок в unit-файле и ссылках на units, но не заменяет реальный запуск, проверку прав и работоспособности приложения. Доступность и диагностику этой команды сверяйте с man pagesystemd-analyzeвашей версии. - 2Перечитайте определения unitsВыполните
sudo systemctl daemon-reload. Менеджер systemd заново читает unit-файлы и drop-in-конфигурации. Команда не запускает службу, не перезапускает уже работающий процесс и не перечитывает конфигурационный файл самого приложения. - 3Запустите службу отдельноВыполните
sudo systemctl start example-app.service, затем проверьтеsudo systemctl status example-app.service. После изменения unit-файла работающей службы обычно требуется осознанно применить изменение черезrestartлибо иной подходящий для приложения способ;daemon-reloadсам процесс не меня ет. - 4Включите службу в автозагрузкуВыполните
sudo systemctl enable example-app.service. Для шаблона это создаёт связь сmulti-user.targetсогласно[Install].enableнастраивает запуск при будущей загрузке, но сам по себе не обязан запускать службу сейчас; для обоих действий можно использоватьsudo systemctl enable --now example-app.service.
Поддерживаемый приложением reload — отдельное действие: оно имеет смысл, только если приложение умеет безопасно перечитывать свою конфигурацию и unit описывает этот механизм. Не путайте его с systemctl daemon-reload: первая операция относится к конфигурации приложения, вторая — только к определениям units. Базовые различия команд управления описаны в статье «systemd и systemctl: управление службами и автозагрузкой Linux».
Проверка статуса и журналов службы
sudo systemctl status example-app.servicesudo journalctl -u example-app.service -bsudo journalctl -u example-app.service -fСтандартные потоки stdout и stderr обычно принимает systemd-journald, поэтому journalctl -u имя.service отбирает сообщения по имени unit. Это не произойдёт в ожидаемом виде, если unit направляет потоки в файл, null или другой механизм, либо приложение самостоятельно перенаправляет вывод. В шаблоне это явно задано через StandardOutput=journal и StandardError=journal.
Наличие старых записей после перезагрузки зависит от настройки хранения journald, в частности от Storage= и доступности постоянного каталога журнала; на части систем журнал может быть только в памяти. Поиск, хранение и р асширенная фильтрация разобраны в статье «Журналы Linux: journalctl, rsyslog и logrotate».
Проблема
Служба не запускается или сразу завершается
Возможные причины
- Указан несуществующий либо недоступный файл в `ExecStart=`, `WorkingDirectory=` или `EnvironmentFile=`
- `appuser` не имеет нужного доступа к программе, каталогам, конфигурации или данным
- Для постоянно работающего приложения выбран `Type=oneshot`, либо программа штатно завершается
- Перезапуски достигли лимита `StartLimitBurst`
Решение
Сначала сохраните вывод systemctl status и журнал, затем сверяйте пути, способ запуска и права с документацией приложения. После изменения unit-файла выполните daemon-reload; после исправления конфигурации приложения примените именно поддерживаемый приложением способ. Подробная ветвящаяся диагностика приведена в статье «Служба systemd не запускается: диагностика ошибок и восстановление».
Как избежать
Проверяйте unit через `systemd-analyze verify`, тестируйте запуск от целевой учётной записи и не маскируйте постоянную ошибку бесконечным `Restart=`.
Термины в статье
- Владелец файла
- Владелец файла — числовой UID, записанный в метаданных объекта и определяющий применение класса прав владельца.
- Группа пользователей
- Группа пользователей — объект разграничения доступа, объединяющий учётные записи под общим GID для назначения прав на файлы, службы и иные ресурсы нескольким пользователям.
- Демон
- Демон — обычно длительно работающий неинтерактивный процесс, который в фоне выполняет системную, сетевую или прикладную функцию.
- Командная оболочка
- Командная оболочка — программа-интерпретатор, принимающая команды и запускающая процессы; в отличие от терминала, она обрабатывает синтаксис и сценарии.
- Права доступа к файлам
- Права доступа к файлам — разрешения файловой системы на чтение, запись и выполнение объекта для его владельца, группы-владельца и остальных пользователей.
- Процесс
- Процесс — экземпляр выполняемой программы в Linux с PID, виртуальным адресным пространством, состоянием и связанными с ним ресурсами.
- Сист емная служба
- Системная служба — программный компонент, которым ОС управляет как логической единицей для фонового выполнения задач или предоставления функций программам и пользователям.
- Учётная запись пользователя
- Учётная запись пользователя — запись в системе идентификации ОС, связывающая имя и UID с параметрами входа, домашним каталогом и членством в группах.
- Bash
- Bash — командная оболочка Unix-подобных систем, реализующая язык POSIX shell и добавляющая расширения для интерактивной работы и сценариев.
- Cron
- Cron — служба-планировщик в Unix-подобных ОС, запускающая команды по расписаниям из таблиц crontab, обычно с минутной дискретностью.
- journalctl
- journalctl — консольная утилита чтения и фильтрации журнала systemd, выводящая сообщения по времени, юниту, загрузке системы, приоритету и другим полям.
- systemctl
- systemctl — командная утилита управления systemd, которая запускает и останавливает юниты, показывает их состояние и настраивает автоматическую активацию.
- systemd
- systemd — система инициализации и менеджер служб Linux, управляющий службами и другими ресурсами как объектами unit, обычно описанными unit-файлами.
- systemd timer
- systemd timer — юнит systemd, который по календарному или монотонному расписанию активирует другой юнит, по умолчанию одноимённый сервис.
- Systemd unit
- Systemd unit — именованный объект systemd, представляющий отслеживаемый или управляемый ресурс, службу, задачу либо состояние системы.
- systemd-journald
- systemd-journald — служба systemd для приёма, индексации и хранения структурированных журналов ядра, служб, процессов и системных сообщений.
