Динамические переменные в файлах системного сервисного модуля

14

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

У нас есть машина с 4 графическими процессорами, и мы хотим увеличить количество экземпляров определенного сервиса на один графический процессор. Например:

  • gpu_service @ 1: 1.service
  • gpu_service @ 2: 1.service
  • gpu_service @ 3: 1.service
  • gpu_service @ 4: 1.service
  • gpu_service @ 1: 2.Service
  • gpu_service @ 2: 2.Service
  • gpu_service @ 3: 2.Service
  • gpu_service @ 4: 2.Service
  • до тошноты

Таким образом, 1: 1, 2: 1 и т. Д. Фактически являются% i в файле единицы обслуживания.

Чтобы служба связывалась с конкретным графическим процессором, исполняемый файл службы проверяет определенную переменную среды, например:

USE_GPU=4

Есть ли способ, которым я могу взять% i внутри файла сервисного модуля и запустить его через некоторую (shell) функцию для получения номера GPU, а затем я могу соответственно установить переменную среды USE_GPU?

Самое главное, я не хочу, чтобы написание нескольких /etc/systemd/system/gpu_service@x:y.service/local.confфайлов было просто так, чтобы я мог раскрутить больше экземпляров.

Кал
источник

Ответы:

10

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

ExecStart=/bin/bash -c 'v=%i; USE_GPU=$${v%:*} exec /bin/mycommand'

Значение $$in в строке станет единичным $в результате, переданном в bash, но, что более важно, перестанет ${...}интерполироваться systemd. (Более ранние версии systemd не документировали использование $$, поэтому я не знаю, поддерживалось ли оно тогда).

meuh
источник
Я закончил тем, что делал что-то подобное. :)
Кал
1
Позвонить, bash -cчтобы запустить программу из файла модуля? Звонить exec? Это похоже на использование вилочного погрузчика поверх вилочного погрузчика (может быть, с другим грузоподъемником сверху), потому что первый вилочный погрузчик имеет проблемы с фактической погрузкой.
Дэвид Тонхофер
К сожалению, вы не можете использовать ExecStartPre для записи файла env, а затем использовать его, по-видимому, это должно быть написано заранее, поэтому что-то вроде этого будет работать. Или скрипт-обертка для выполнения разбиения :) Другой причудливый вариант - создать другой сервис для настройки env. файл, не уверен, как это будет работать с шаблонами tho: stackoverflow.com/a/42841480/32453
rogerdpack
8

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

[Service]
# Note you need to escape percentage sign
ExecStartPre=/bin/sh -c "my_awesome_parser %%i > /run/gpu_service_%i"
EnvironmentFile=/run/gpu_service_%i
ExecStart=...
Умут
источник
4

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

Согласно предложениям комментаторов, вот решение:

Использование переменных среды в единицах systemd

Директива об окружающей среде

systemd имеет директиву Environment, которая устанавливает переменные среды для выполняемых процессов. Он занимает разделенный пробелами список назначений переменных. Эта опция может быть указана более одного раза, в этом случае все перечисленные переменные будут установлены. Если одна и та же переменная установлена ​​дважды, более поздняя настройка переопределяет более раннюю настройку. Если для этой опции назначена пустая строка, список переменных среды сбрасывается, все предыдущие назначения не имеют никакого эффекта. Директивы среды используются во встроенных системных модулях Container Linux, например, в etcd2 и фланеле.

В приведенном ниже примере вы можете настроить свой демон etcd2 для использования шифрования. Просто создайте /etc/systemd/system/etcd2.service.d/30-certificates.confплагин для etcd2.service:

[Service]
# Client Env Vars
Environment=ETCD_CA_FILE=/path/to/CA.pem
Environment=ETCD_CERT_FILE=/path/to/server.crt
Environment=ETCD_KEY_FILE=/path/to/server.key
# Peer Env Vars
Environment=ETCD_PEER_CA_FILE=/path/to/CA.pem
Environment=ETCD_PEER_CERT_FILE=/path/to/peers.crt
Environment=ETCD_PEER_KEY_FILE=/path/to/peers.key

Затем запустите sudo systemctl daemon-reloadи sudo systemctl restart etcd2.serviceпримените новые среды к демону etcd2.

Цитируемый текст взят со следующего URL: https://coreos.com/os/docs/latest/using-environment-variables-in-systemd-units.html

CyberK
источник
2
Хотя это может теоретически ответить на вопрос, было бы предпочтительным включить сюда основные части ответа и предоставить ссылку для справки.
Стивен Раух
1
Хотя ваш комментарий теоретически может улучшить мои будущие ответы в stackexchange, было бы желательно, чтобы вы включили в свой комментарий основные части ответа, а не просто комментировали, чтобы указать, насколько некомпетентным может быть кто-то :)
CyberK
1
Добро пожаловать в Stack Exchange! Спасибо за комментарий, ты заставил меня улыбнуться. Также спасибо, что нашли время, чтобы отредактировать свой ответ. Мы пытаемся создать что-то, что будет иметь ценность с течением времени, и ответы только на ссылки просто не очень хорошо стареют.
Стивен Раух
Если вы добавляете, Environment=ABC=%iон устанавливает этот env. переменная "в целом% я". Я полагаю, вы могли бы сделать обертку для удаления ненужных «вещей, выходящих за рамки цитаты», и это вызвало бы настоящий исполняемый файл. Но если вы делаете обертку, вы можете просто передать ее %iв качестве аргумента, например:ExecStart=my_wrapper %i
rogerdpack
0

Это ужасно и не совсем то, о чем вы просили, и при этом не допускает автозапуска, но для фолловеров возможно сделать что-то, используя среду systemctl :

$ sudo systemctl set-environment USE_GPU=4 # add it to the env. variables for future services
$ sudo systemctl start gpu_service@4:2.service

Просто пытаюсь перечислить все возможные пути :)

rogerdpack
источник