Переменная в unit-файле не разворачивается
systemd подставляет переменные только в командах Exec*= и только те, что заданы в Environment= или EnvironmentFile=. В остальных параметрах знак доллара — обычный символ, а переменные окружения вашей оболочки службе недоступны вовсе.
Вероятные причины
По порядку: сверху то, что встречается чаще.
-
Переменная используется не в команде запуска
В параметрах вроде
WorkingDirectory=илиReadWritePaths=подстановки нет: значение берётся буквально. -
Переменная не задана в unit-файле
Служба не читает профиль оболочки. Переменная, «которая есть в системе», для неё не существует.
-
Ожидается разбор как в оболочке
Конструкции вида
${VAR:-default},$(команда)и арифметика systemd не разбирает. Строка уйдёт программе как есть.
Диагностика
Команды идут в том порядке, в котором их стоит выполнять: каждая следующая проверяет то, что осталось после предыдущей.
Заданное окружение и разобранная команда: видно, что подставилось.
systemctl show myapp.service -p Environment -p ExecStartОбщее окружение менеджера, доступное службам.
systemctl show-environmentРешение
Решение своё для каждой причины. Сначала определите, какая из них ваша, — иначе правки наложатся друг на друга.
- Почему происходит
- В параметрах вроде
WorkingDirectory=илиReadWritePaths=подстановки нет: значение берётся буквально.
- Как проверить
-
Посмотрите, как systemd понял значение.
systemctl show myapp.service -p WorkingDirectory -p Environment
- Как исправить
-
Используйте подстановки systemd (
%h,%t,%S) вместо переменных окружения: они работают во всех параметрах.
- Почему происходит
- Служба не читает профиль оболочки. Переменная, «которая есть в системе», для неё не существует.
- Как проверить
-
Посмотрите окружение службы.
systemctl show myapp.service -p Environment -p EnvironmentFile
- Как исправить
-
Задайте переменную явно через
Environment=или файл окружения.
- Почему происходит
- Конструкции вида
${VAR:-default},$(команда)и арифметика systemd не разбирает. Строка уйдёт программе как есть.
- Как проверить
-
Поищите такие конструкции в файле.
systemctl cat myapp.service | grep -nE "\$\{|\$\("
- Как исправить
-
Вызовите оболочку явно (
/bin/sh -c) либо вычислите значение заранее и передайте готовым.
Пример вывода
Переменная не задана и попала в аргументы буквально. Пример показательный: он собран на тестовой машине специально для этой страницы, а не взят из чужого журнала.
$ systemctl cat myapp.service | grep ExecStart
ExecStart=/usr/local/bin/myapp --data $DATA_DIR
$ journalctl -u myapp.service -n 3 --no-pager
myapp[4200]: error: invalid path: "$DATA_DIR"
Связанные ошибки
- status=203/EXEC в systemd Код 203/EXEC означает, что systemd не смог выполнить программу из ExecStart=. Разбор причин: путь, права, интерпретатор, синтаксис оболочки.
- status=2/INVALIDARGUMENT в systemd Код 2/INVALIDARGUMENT: программа сочла аргументы или настройки недопустимыми. Частая причина — лишние кавычки в ExecStart=.
- status=127 в systemd: команда не найдена Код 127 без имени: оболочка не нашла команду. Появляется, когда ExecStart запускает скрипт или sh -c, а внутри команды нет.
- Apache: Invalid command — не включён модуль Apache не запускается: директива требует модуль, который не подключён. Как найти нужный модуль и включить.
- Docker: unable to configure the Docker daemon with file daemon.json Демон Docker не запускается из-за ошибки в /etc/docker/daemon.json: неверный JSON или неизвестный ключ.
- Service has more than one ExecStart= setting Несколько команд запуска допустимы только при Type=oneshot. Как правильно заменить команду в переопределении.
- Unit file is bad и ошибки разбора unit-файла systemd не может разобрать unit-файл: неизвестные параметры, ошибки в секциях, недопустимые значения. Как найти проблемную строку.
- Unit is masked: служба запрещена к запуску Сообщение Unit is masked: unit заблокирован ссылкой на /dev/null. Как найти и снять маскировку.
Источники
-
systemd.exec(5)
Подстановка переменных в командах Exec*= и её ограничения. -
systemd.unit(5)
Подстановки systemd, доступные во всех параметрах. -
Воспроизведено на тестовой машине, systemd 255 (Ubuntu 24.04)
Проверено: значение с $VAR без заданной переменной уходит программе буквально.