У меня есть служба, реализованная в виде сценария Bash. Внутри это на самом деле приложение node.js, но для целей этого вопроса это может быть что угодно.
Основной вариант использования состоит в том, что мы разрабатываем / отлаживаем сценарий в интерактивной оболочке, а затем включаем его как службу.
Если я подключусь к своему устройству по ssh (вход в систему), вся моя среда будет там, и я могу запустить свой сценарий из командной строки, без проблем. Оболочка, в которой я нахожусь, подобрала правильную среду из .bashrc
, .profile
и т. Д., И все работает.
Но если я запускаю его из службы systemd, он источник
среды, как и для интерактивной оболочки. Есть условия для добавления переменных среды в модуль, но то, что я здесь делаю, просто дублирует то, что делает моя интерактивная среда, и становится простым способом что-то забыть.
Я уверен, что для реальной производственной службы есть правильный способ сделать это, но это лабораторное приложение, и мне нужно упростить его, чтобы никто, работающий над сценарием, не знал, как работает systemd.
Итак, вопрос: что мне нужно сделать, чтобы сценарий, написанный для запуска в интерактивной оболочке Bash, запускался из systemd?
Я пытался запустить bash с помощью - login
, но это не работает. Также явно не делается источник .bashrc
во внешнем скрипте.
Вот пример, над которым я работаю, чтобы выделить проблему:
основной скрипт ( job.sh
):
#!/bin/bash
cd
while [ 1 ]
do
pwd
echo USER is $USER
echo PATH is $PATH
which node
node --version
sleep 1
done
Я вызываю его из другого скрипта ( wrapper.sh
):
#!/bin/bash
echo starting wrapper...
bash --login /home/droid/job.sh
и вот мой модуль job.service
в /etc/systemd/system/job.service
:
[Unit]
Description=Job Daemon
[Service]
User=droid
ExecStart=/home/droid/wrapper.sh
[Install]
WantedBy=multi-user.target
Что я не понимаю в systemd, что мешает мне заставить это работать?
Разница между выполнением скрипта через systemd
и его непосредственным выполнением заключается в окружении. Вы можете протестировать его таким образом. В файле Unit добавьте это в раздел [Service] для тестирования:
StandardOutput=console
Затем в вашем скрипте bash, в верхней части добавьте эту строку для сброса окружения:
env
Теперь запустите скрипт внутри и вне systemd и сравните переменные окружения, которые были сброшены.
Это особенность systemd в том, что он жестко контролирует окружение. Это повышает безопасность и обеспечивает согласованность.
Вы можете прочитать больше о том, как systemd управляет окружением в systemd.exec.
Получить что-то одинаковое для запуска через CLI и через систему очень просто, как только вы запустите его, как только вы захотите из systemd. Запустите его через CLI следующим образом:
systemctl start your-unit-name
Тогда systemd будет работать с точно таким же окружением.
Вы просили обратного: Заставить systemd запустить службу, используя ваше "bash" окружение. Но это грязное, меняющееся окружение, которое может привести к противоречивым результатам. Напротив, окружение выполнения systemd строго контролируется, что приводит к последовательным, воспроизводимым результатам. Вот почему следует вывернуть вопрос наизнанку и спросить, как вы можете использовать ваши службы на CLI, используя ту же самую, последовательную, контролируемую среду выполнения, которую использует systemd.
Хотя .profile
читается любым экземпляром оболочки, .bashrc
явно предназначен только для интерактивных оболочек без входа в систему. Действительно, в зависимости от вашего дистрибутива, по умолчанию .bashrc
может иметь что-то вроде этого вверху, чтобы дополнительно убедиться, что файл обрабатывается только интерактивными оболочками:
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
Вероятно, поэтому ручной поиск .bashrc
не помог. т работать.
Вероятно, вы могли бы заставить его работать, указав --login
и убедившись, что необходимые переменные среды установлены в .profile
, а не в .bashrc
. Однако, вероятно, лучше было бы иметь отдельный файл переменных среды специально для этой службы и убедиться, что файл получен как из службы systemd, так и при ее запуске вручную.