Variabili dinamiche nei file delle unità di servizio systemd


14

Esiste un modo per assegnare dinamicamente le variabili di ambiente in un file di unità di servizio systemd?

Abbiamo una macchina con 4 GPU e vogliamo creare più istanze di un determinato servizio per GPU. Per esempio:

  • 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
  • Fino alla nausea

Quindi 1: 1, 2: 1, ecc. Sono effettivamente% i nel file dell'unità di servizio.

Affinché il servizio si associ a una determinata GPU, l'eseguibile del servizio controlla una determinata variabile d'ambiente, ad esempio:

USE_GPU=4

Esiste un modo in cui posso prendere% i all'interno del file dell'unità di servizio ed eseguirlo tramite alcune funzioni (shell) per derivare il numero GPU, e quindi posso impostare la variabile d'ambiente USE_GPU di conseguenza?

/etc/systemd/system/gpu_service@x:y.service/local.confAncora più importante, non voglio il fastidio di scrivere più file solo per poter girare più istanze.

Risposte:


10

Se stai attento puoi incorporare una piccola sequenza di script bash come comando exec nel file di servizio dell'istanza. Per esempio

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

Il $$nella stringa diventerà un singolo $nel risultato passato a bash, ma soprattutto smetterà ${...}di essere interpolato da systemd. (Le versioni precedenti di systemd non documentavano l'uso di $$, quindi non so se fosse supportato allora).


Ho finito per fare qualcosa del genere. :)
Kal,

1
Chiamare a bash -cper avviare un programma dal file dell'unità? Chiama exec? È come usare un carrello elevatore sopra un carrello elevatore (forse con un altro carrello elevatore in cima) perché il primo carrello elevatore ha effettivamente problemi con il carrello elevatore.
David Tonhofer,

Sfortunatamente non puoi usare un ExecStartPre per scrivere un file env, quindi usarlo, apparentemente deve essere scritto in anticipo, quindi qualcosa del genere funzionerebbe. O uno script wrapper per eseguire la divisione :) L'altra bizzarra opzione sarebbe quella di creare un altro servizio per impostare l'ENV. di file, non è sicuro come dovrebbe funzionare con i modelli tho: stackoverflow.com/a/42841480/32453
rogerdpack

8

Non integrato. È necessario eseguire queste operazioni prima dell'inizio del servizio. Un modo sarebbe quello di metterlo in un file di ambiente.

[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

Sembra che tu possa davvero impostare variabili d'ambiente all'interno di un file di unità systemd ...

Per suggerimenti dei commentatori, ecco la soluzione:

Utilizzo delle variabili di ambiente in unità di sistema

Direttiva sull'ambiente

systemd ha una direttiva Environment che imposta le variabili d'ambiente per i processi eseguiti. Prende un elenco separato da spazi di assegnazioni di variabili. Questa opzione può essere specificata più di una volta, nel qual caso verranno impostate tutte le variabili elencate. Se la stessa variabile viene impostata due volte, l'impostazione successiva avrà la precedenza su quella precedente. Se la stringa vuota è assegnata a questa opzione, l'elenco delle variabili di ambiente viene ripristinato, tutte le assegnazioni precedenti non hanno alcun effetto. Le direttive sugli ambienti vengono utilizzate nelle unità systemd Linux container incorporate, ad esempio in etcd2 e flanella.

Con l'esempio seguente, puoi configurare il tuo demone etcd2 per usare la crittografia. Basta creare un /etc/systemd/system/etcd2.service.d/30-certificates.confdrop-in per 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

Quindi eseguire sudo systemctl daemon-reloade sudo systemctl restart etcd2.serviceapplicare nuovi ambienti al demone etcd2.

Testo tra virgolette tratto dal seguente URL: https://coreos.com/os/docs/latest/using-environment-variables-in-systemd-units.html


2
Sebbene ciò possa teoricamente rispondere alla domanda, sarebbe preferibile includere qui le parti essenziali della risposta e fornire il collegamento come riferimento.
Stephen Rauch,

1
Mentre il tuo commento potrebbe teoricamente migliorare le mie future risposte in stackexchange, sarebbe preferibile che tu abbia incluso le parti essenziali della risposta nel tuo commento invece di commentare solo per sottolineare quanto qualcuno possa essere incompetente :)
CyberK

1
Benvenuto in Stack Exchange! Grazie per il commento, mi hai fatto sorridere. Grazie anche per aver dedicato del tempo per modificare la tua risposta. Stiamo cercando di costruire qualcosa che abbia valore nel tempo, e link solo le risposte non invecchiano molto bene.
Stephen Rauch,

Se lo aggiungi Environment=ABC=%i, imposta quell'ambiente. variabile "per l'intero% i". Immagino che potresti creare un wrapper per eliminare le "cose ​​oltre la citazione" che non vuoi, e chiama il vero eseguibile. Ma se stai realizzando un wrapper, potresti anche solo passare %icome argomento ad esso ex:ExecStart=my_wrapper %i
rogerdpack

0

È brutto e non è esattamente quello che hai chiesto, né consente l'avvio automatico, ma per i follower è possibile fare qualcosa usando l' ambiente 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

Sto solo cercando di elencare tutti i modi possibili :)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.