Come impostare la variabile d'ambiente nel servizio systemd?


162

Ho un sistema Arch Linux con systemd e ho creato il mio servizio. Il servizio di configurazione /etc/systemd/system/myservice.serviceè simile al seguente:

[Unit]
Description=My Daemon

[Service]
ExecStart=/bin/myforegroundcmd

[Install]
WantedBy=multi-user.target

Ora voglio avere una variabile d'ambiente impostata per /bin/myforegroundcmd. Come lo faccio?

Risposte:


197

I tempi cambiano e anche le migliori pratiche.

La corrente modo migliore per farlo è quello di eseguire systemctl edit myservice, che creerà un file di override per te o lasciare che si modifica uno esistente.

Nelle installazioni normali ciò creerà una directory /etc/systemd/system/myservice.service.de all'interno di quella directory creerà un file il cui nome termina in .conf(in genere override.conf) e in questo file è possibile aggiungere o sovrascrivere qualsiasi parte dell'unità spedita dalla distribuzione.

Ad esempio, in un file /etc/systemd/system/myservice.service.d/myenv.conf:

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

Inoltre, se la directory esiste ed è vuota, il tuo servizio sarà disabilitato! Se non si intende inserire qualcosa nella directory, assicurarsi che non esista.


Per riferimento, il vecchio modo era:

Il modo consigliato per farlo è creare un file /etc/sysconfig/myserviceche contenga le variabili e quindi caricarle EnvironmentFile.

Per i dettagli completi, consultare la documentazione di Fedora su come scrivere uno script systemd .


4
Immagino che il sysconfigpercorso sia specifico per Fedora ma la domanda riguarda Arch Linux. Penso che la risposta di Paluh sia più interessante
Ludovic Kuty il

1
/etc/sysconfigè specifico di Fedora. AFAIR Arch Linux stava spingendo per avere i file di configurazione da qualche parte specifici del pacchetto /etcpiuttosto che in quella specifica posizione di Fedora. Ad esempio /etc/myservice.conf, sebbene l'utilizzo di file extra non sembri il modo giusto qui.
Michał Górny,

5
No, no, no. / etc / sysconfig non è raccomandato. È scoraggiato, insieme a / etc / default / * da debian, perché sono inutili e i nomi sono privi di significato e hanno senso solo per motivi di compatibilità all'indietro (tutto / etc riguarda la configurazione del sistema, non solo / etc / sysconfig e / etc / defaults è per le sostituzioni, non quelle predefinite). Basta inserire le definizioni direttamente nel file di unità, o se non è possibile, in un file di ambiente che ha una posizione specifica del pacchetto (come suggerisce il commento di Michał).
zbyszek,

1
@FrederickNord È solo una coppia variabile = valore, ad esempio DJANGO_SETTINGS_MODULE=project.settingsuna per riga.
Michael Hampton

1
@MichaelHampton Potresti aggiungere un link alla documentazione per "il modo migliore attuale"?
jb.

77

La risposta dipende dal fatto che si supponga che la variabile sia costante (ovvero, non dovrebbe essere modificata dall'utente che ottiene l'unità) o variabile (che dovrebbe essere impostata dall'utente).

Dal momento che è la tua unità locale, il confine è piuttosto sfocato e in entrambi i casi funzionerebbe. Tuttavia, se hai iniziato a distribuirlo e sarebbe finito /usr/lib/systemd/system, questo sarebbe diventato importante.

Valore costante

Se non è necessario modificare il valore per istanza, il modo preferito sarebbe posizionarlo come Environment=, direttamente nel file dell'unità:

[Unit]
Description=My Daemon

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

[Install]
WantedBy=multi-user.target

Il vantaggio è che la variabile viene mantenuta in un singolo file con l'unità. Pertanto, il file di unità è più semplice da spostare tra i sistemi.

Valore variabile

Tuttavia, la soluzione di cui sopra non funziona bene quando si suppone che sysadmin cambi il valore della variabile di ambiente a livello locale. Più specificamente, il nuovo valore dovrebbe essere impostato ogni volta che il file di unità viene aggiornato.

In questo caso, è necessario utilizzare un file aggiuntivo. Come - di solito dipende dalla politica di distribuzione.

Una soluzione particolarmente interessante è usare la /etc/systemd/system/myservice.service.ddirectory. A differenza di altre soluzioni, questa directory è supportata dallo stesso systemd e quindi non ha percorsi specifici per la distribuzione.

In questo caso, si inserisce un file simile /etc/systemd/system/myservice.service.d/local.confche aggiunge le parti mancanti del file di unità:

[Service]
Environment="FOO=bar baz"

Successivamente, systemd unisce i due file all'avvio del servizio (ricordarsi di systemctl daemon-reloaddopo aver cambiato uno di essi). E poiché questo percorso è usato direttamente da systemd, non lo usi EnvironmentFile=per questo.

Se il valore deve essere modificato solo su alcuni dei sistemi interessati, è possibile combinare entrambe le soluzioni, fornendo un valore predefinito direttamente nell'unità e un override locale nell'altro file.


systemctl daemon-reloadè il comando per ricaricare systemd
Dmitry Buzolin il

EnvironmentFile=è meglio quando i valori sono segreti come le password. Vedi la mia risposta per i dettagli.
Don Kirkby,


17

Le risposte di Michael e Michał sono utili e rispondono alla domanda originale su come impostare una variabile d'ambiente per un servizio systemd. Tuttavia, un uso comune delle variabili di ambiente è configurare dati sensibili come le password in un luogo che non si impegna accidentalmente al controllo del codice sorgente con il codice dell'applicazione.

Se è per questo che vuoi passare una variabile d'ambiente al tuo servizio, non utilizzare Environment=nel file di configurazione dell'unità. Utilizzare EnvironmentFile=e puntare a un altro file di configurazione che è leggibile solo dall'account del servizio (e dagli utenti con accesso root).

I dettagli del file di configurazione dell'unità sono visibili a qualsiasi utente con questo comando:

systemctl show my_service

Ho inserito un file di configurazione /etc/my_service/my_service.confe ho inserito i miei segreti:

MY_SECRET=correcthorsebatterystaple

Quindi nel mio file di unità di servizio, ho usato 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

Ho controllato che ps auxenon possono vedere quelle variabili di ambiente e altri utenti non hanno accesso /proc/*/environ. Controlla sul tuo sistema, ovviamente.


8

Michael ha dato una soluzione pulita ma volevo ottenere una variabile env aggiornata dallo script. Sfortunatamente l'esecuzione di comandi bash non è possibile nel file di unità di systemd. Fortunatamente puoi attivare bash all'interno di ExecStart:

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

Si noti che questa impostazione non supporta direttamente le righe di comando della shell. Se devono essere utilizzate le righe di comando della shell, devono essere passate esplicitamente a un'implementazione della shell di qualche tipo.

Esempio nel nostro caso è quindi:

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

7
Questo non funzionerà per diversi motivi (a meno che non sia un servizio "one-shot", che è piuttosto inutile). Sono riuscito a ottenere il seguente al lavoro: /bin/bash -a -c 'source /etc/sysconfig/whatever && exec whatever-program'. Le -aassicura l'ambiente viene esportato nel sotto-processo (a meno che non si desidera prefisso tutte le variabili in whatevercon export)
Otheus

perché non funzionerà? Dovrebbe sempre innescare l'intero comando che include l'esecuzione dello script, non è vero?
user1830432

Forse ExecStart=/usr/bin/env ENV=script /bin/myforegroundcmdè una soluzione leggermente migliore in questo caso.
kstep,

@Otheus: ottima risposta, salvata di giorno quando ho dovuto creare un file Tomcat 8 Unit.
Daniel,

1
Esiste un modo per eseguire un comando bash "in" un file di servizio systemd. Vedi questo link: coreos.com/os/docs/latest/…
Mark Lakata
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.