Variables dynamiques dans les fichiers d'unité de service systemd

14

Existe-t-il un moyen d'affecter dynamiquement des variables d'environnement dans un fichier d'unité de service systemd?

Nous avons une machine qui possède 4 GPU, et nous voulons faire tourner plusieurs instances d'un certain service par GPU. Par exemple:

  • 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
  • à satiété

Ainsi, les 1: 1, 2: 1, etc. sont effectivement le% i dans le fichier d'unité de service.

Pour que le service se lie à un GPU particulier, l'exécutable du service vérifie une certaine variable d'environnement, par exemple:

USE_GPU=4

Existe-t-il un moyen de prendre% i dans le fichier d'unité de service et de l'exécuter via une fonction (shell) pour dériver le numéro de GPU, puis je peux définir la variable d'environnement USE_GPU en conséquence?

Plus important encore, je ne veux pas les tracas de l'écriture de plusieurs /etc/systemd/system/gpu_service@x:y.service/local.conffichiers juste pour pouvoir faire tourner plus d'instances.

Kal
la source

Réponses:

10

Si vous faites attention, vous pouvez incorporer une petite séquence de script bash comme commande exec dans le fichier de service d'instance. Par exemple

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

Le $$dans la chaîne deviendra un simple $dans le résultat passé à bash, mais plus important encore, il cessera ${...}d'être interpolé par systemd. (Les versions antérieures de systemd ne documentaient pas l'utilisation de $$, donc je ne sais pas si cela était alors pris en charge).

meuh
la source
J'ai fini par faire quelque chose comme ça. :)
Kal
1
Appeler un bash -cpour démarrer un programme à partir du fichier d'unité? Appeler exec? C'est comme utiliser un chariot élévateur sur un chariot élévateur (peut-être avec un autre chariot élévateur sur le dessus) parce que le premier chariot élévateur a du mal à le faire.
David Tonhofer
Malheureusement, vous ne pouvez pas utiliser un ExecStartPre pour écrire un fichier env, puis utilisez-le, apparemment il doit être écrit à l'avance, donc quelque chose comme ça fonctionnerait. Ou un script wrapper pour faire le fractionnement :) L'autre option bizarre serait de créer un autre service pour configurer l'env. fichier, je ne sais pas comment cela fonctionnerait avec les modèles tho: stackoverflow.com/a/42841480/32453
rogerdpack
8

Pas de manière intégrée. Vous devez effectuer ces opérations avant le début de votre service. Une façon serait de le placer dans un fichier d'environnement.

[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=...
Umut
la source
4

Il semble que vous puissiez en effet définir des variables d'environnement dans un fichier d'unité systemd ...

Selon les suggestions des commentateurs, voici la solution:

Utilisation de variables d'environnement dans les unités systemd

Directive environnement

systemd a une directive Environnement qui définit les variables d'environnement pour les processus exécutés. Il prend une liste d'affectations de variables séparées par des espaces. Cette option peut être spécifiée plusieurs fois, auquel cas toutes les variables répertoriées seront définies. Si la même variable est définie deux fois, le dernier paramètre remplacera le précédent. Si la chaîne vide est affectée à cette option, la liste des variables d'environnement est réinitialisée, toutes les affectations antérieures n'ont aucun effet. Les directives sur les environnements sont utilisées dans les unités Systemd Container Linux intégrées, par exemple dans etcd2 et flannel.

Avec l'exemple ci-dessous, vous pouvez configurer votre démon etcd2 pour utiliser le chiffrement. Créez simplement un /etc/systemd/system/etcd2.service.d/30-certificates.confdrop-in pour 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

Exécutez ensuite sudo systemctl daemon-reloadet sudo systemctl restart etcd2.servicepour appliquer de nouveaux environnements au démon etcd2.

Texte cité à partir de l'URL suivante: https://coreos.com/os/docs/latest/using-environment-variables-in-systemd-units.html

CyberK
la source
2
Bien que cela puisse théoriquement répondre à la question, il serait préférable d'inclure les éléments essentiels de la réponse ici, et de fournir le lien de référence.
Stephen Rauch
1
Bien que votre commentaire puisse théoriquement améliorer mes futures réponses dans stackexchange, il serait préférable que vous ayez inclus les parties essentielles de la réponse dans votre commentaire au lieu de simplement commenter pour souligner à quel point une personne peut être incompétente :)
CyberK
1
Bienvenue sur Stack Exchange! Merci pour le commentaire, tu m'as fait sourire. Merci également d'avoir pris le temps de modifier votre réponse. Nous essayons de construire quelque chose qui aura de la valeur au fil du temps, et les seules réponses de lien ne vieillissent pas très bien.
Stephen Rauch
Si vous ajoutez Environment=ABC=%icela définit cet env. variable "à l'intégralité de% i". Je suppose que vous pourriez faire un wrapper pour supprimer les "trucs au-delà de la citation" que vous ne voulez pas, et il appelle le véritable exécutable. Mais si vous faites un wrapper, vous pouvez même simplement le passer %icomme argument ex:ExecStart=my_wrapper %i
rogerdpack
0

C'est moche et pas tout à fait ce que vous avez demandé, ni autoriser le démarrage automatique, mais pour les followers, il est possible de faire quelque chose en utilisant l' environnement 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

J'essaie juste d'énumérer toutes les façons possibles :)

rogerdpack
la source