Как установить переменную окружения в сервисе systemd?


162

У меня есть система Arch Linux с systemd, и я создал свой собственный сервис. Сервис конфигурации /etc/systemd/system/myservice.serviceвыглядит следующим образом:

[Unit]
Description=My Daemon

[Service]
ExecStart=/bin/myforegroundcmd

[Install]
WantedBy=multi-user.target

Теперь я хочу, чтобы переменная окружения была установлена ​​для /bin/myforegroundcmd. Как мне это сделать?

Ответы:


197

Времена меняются, как и лучшие практики.

На данный момент лучший способ сделать это - запустить systemctl edit myserviceфайл, который создаст для вас файл переопределения или позволит вам отредактировать существующий.

В обычных установках это создаст каталог /etc/systemd/system/myservice.service.d, а внутри этого каталога создаст файл, имя которого оканчивается .conf(обычно override.conf), и в этом файле вы можете добавить или переопределить любую часть устройства, поставляемую дистрибутивом.

Например, в файле /etc/systemd/system/myservice.service.d/myenv.conf:

[Service]
Environment="SECRET=pGNqduRFkB4K9C2vijOmUDa2kPtUhArN"
Environment="ANOTHER_SECRET=JP8YLOc2bsNlrGuD6LVTq7L36obpjzxd"

Также обратите внимание, что если каталог существует и пуст, ваш сервис будет отключен! Если вы не собираетесь помещать что-либо в каталог, убедитесь, что оно не существует.


Для справки, старый способ был:

Рекомендуемый способ сделать это - создать файл, /etc/sysconfig/myserviceсодержащий ваши переменные, а затем загрузить их EnvironmentFile.

Для получения полной информации см. Документацию Fedora о том, как написать сценарий systemd .


4
Я предполагаю, что sysconfigпуть специфичен для Fedora, но вопрос об Arch Linux. Я думаю, что ответ от Paluh более интересен
Ludovic Kuty

1
/etc/sysconfigявляется специфичным для Fedora. AFAIR Arch Linux настаивала на том, чтобы файлы конфигурации были где-то в зависимости от пакета, /etcа не в этом специфичном для Fedora месте. Мол /etc/myservice.conf, хотя использование дополнительного файла не кажется правильным здесь.
Михал Гурни

5
Нет нет нет. / etc / sysconfig не рекомендуется. Это не рекомендуется, наряду с / etc / default / * от debian, потому что они бессмысленны, а имена бессмысленны и имеют смысл только по причинам обратной совместимости (все / etc относится к конфигурации системы, а не только к / etc / sysconfig и / etc / defaults предназначены для переопределений, а не для значений по умолчанию). Просто поместите определения непосредственно в файл модуля, или, если это невозможно, в файле среды, который имеет определенное местоположение пакета (как предлагает комментарий Михала).
zbyszek

1
@FrederickNord Это просто пары переменная = значение, например DJANGO_SETTINGS_MODULE=project.settings, по одной на строку.
Майкл Хэмптон

1
@MichaelHampton Не могли бы вы добавить ссылку на документацию для «текущего лучшего способа»?
JB.

77

Ответ зависит от того, должна ли переменная быть постоянной (то есть не должна изменяться пользователем, получающим единицу) или переменной (должна быть установлена ​​пользователем).

Поскольку это ваша локальная единица, граница довольно размыта и в любом случае будет работать. Однако, если вы начнете распространять его, и это закончится /usr/lib/systemd/system, это станет важным.

Постоянное значение

Если значение не нужно изменять для каждого экземпляра, предпочтительным способом было бы разместить его как Environment=непосредственно в файле модуля:

[Unit]
Description=My Daemon

[Service]
Environment="FOO=bar baz"
ExecStart=/bin/myforegroundcmd

[Install]
WantedBy=multi-user.target

Преимущество этого заключается в том, что переменная хранится в одном файле с модулем. Поэтому файл модуля легче перемещать между системами.

Значение переменной

Однако вышеприведенное решение не работает, когда предполагается, что sysadmin локально изменяет значение переменной среды. Более конкретно, новое значение необходимо будет устанавливать каждый раз, когда обновляется файл модуля.

Для этого случая должен использоваться дополнительный файл. Как - обычно зависит от политики распространения.

Одним из особенно интересных решений является использование /etc/systemd/system/myservice.service.dкаталога. В отличие от других решений, этот каталог поддерживается самой системой systemd и поэтому не содержит путей, специфичных для дистрибутива.

В этом случае вы помещаете такой файл, /etc/systemd/system/myservice.service.d/local.confкоторый добавляет недостающие части файла модуля:

[Service]
Environment="FOO=bar baz"

После этого systemd объединяет эти два файла при запуске службы (не забудьте systemctl daemon-reloadпосле изменения любого из них). И так как этот путь используется непосредственно systemd, вы не используете EnvironmentFile=для этого.

Если предполагается, что значение будет изменено только в некоторых из затронутых систем, вы можете объединить оба решения, предоставив значение по умолчанию непосредственно в модуле и локальное переопределение в другом файле.


systemctl daemon-reloadэто команда для перезагрузки systemd
Дмитрий Бузолин

EnvironmentFile=лучше, когда значения являются секретами, такими как пароли. Смотрите мой ответ для деталей.
Дон Киркби


17

Ответы Михаэля и Михала полезны и отвечают на оригинальный вопрос о том, как установить переменную окружения для службы systemd. Тем не менее, одним из распространенных применений переменных среды является конфигурирование конфиденциальных данных, таких как пароли, в месте, которое не будет случайно зафиксировано для контроля версий с помощью кода вашего приложения.

Если именно поэтому вы хотите передать переменную среды в вашу службу, не используйте ее Environment=в файле конфигурации устройства. Используйте EnvironmentFile=и укажите его для другого файла конфигурации, который доступен для чтения только учетной записи службы (и пользователям с правами root).

Детали файла конфигурации устройства видны любому пользователю с помощью этой команды:

systemctl show my_service

Я поместил файл конфигурации в /etc/my_service/my_service.confи вложил туда свои секреты:

MY_SECRET=correcthorsebatterystaple

Затем в моем файле сервисного блока я использовал EnvironmentFile=:

[Unit]
Description=my_service

[Service]
ExecStart=/usr/bin/python /path/to/my_service.py
EnvironmentFile=/etc/my_service/my_service.conf
User=myservice

[Install]
WantedBy=multi-user.target

Я проверил, что ps auxeне может видеть эти переменные среды, и другие пользователи не имеют доступа к /proc/*/environ. Проверьте на своей системе, конечно.


8

Майкл дал одно чистое решение, но я хотел получить обновленную переменную env из скрипта. К сожалению, выполнение команд bash невозможно в системном файле systemd. К счастью, вы можете запустить bash внутри ExecStart:

http://www.dsm.fordham.edu/cgi-bin/man-cgi.pl?topic=systemd.service&sect=5

Обратите внимание, что этот параметр напрямую не поддерживает командные строки оболочки. Если нужно использовать командные строки оболочки, они должны быть явно переданы какой-либо реализации оболочки.

Пример в нашем случае это:

[Service]
ExecStart=/bin/bash -c "ENV=`script`; /bin/myforegroundcmd"

7
Это не будет работать по нескольким причинам (если только это не «одноразовый» сервис, который довольно бессмыслен). Мне удалось получить следующие к работе: /bin/bash -a -c 'source /etc/sysconfig/whatever && exec whatever-program'. В -aГарантирует среда экспортируется в подпроцесса (если вы не хотите , чтобы префикс все переменные whateverс export)
Otheus

почему это не сработает? Он всегда должен запускать всю команду, которая включает в себя выполнение скрипта, не так ли?
user1830432

Возможно ExecStart=/usr/bin/env ENV=script /bin/myforegroundcmd, это немного лучшее решение в этом случае.
kstep

@Otheus: Отличный ответ, сохраненный днем, когда мне пришлось создавать файл Tomcat 8 Unit.
Даниэль

1
Существует способ выполнить команду bash "в" файле службы systemd. Смотрите эту ссылку: coreos.com/os/docs/latest/…
Марк Лаката
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.