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.