J'ai un système Arch Linux avec systemd et j'ai créé mon propre service. Le service de configuration à /etc/systemd/system/myservice.service
ressemble à ça:
[Unit]
Description=My Daemon
[Service]
ExecStart=/bin/myforegroundcmd
[Install]
WantedBy=multi-user.target
Maintenant, je veux avoir une variable d'environnement définie pour le /bin/myforegroundcmd
. Comment je fais ça?
Les temps changent et les meilleures pratiques aussi.
Le courant la meilleure façon de le faire est d'exécuter systemctl edit myservice
, qui créera pour vous un fichier de remplacement ou vous permettra d'en modifier un existant.
Dans les installations normales, cela créera un répertoire /etc/systemd/system/myservice.service.d
, et à l'intérieur de ce répertoire, créez un fichier dont le nom se termine par .conf
(généralement, override.conf
), et dans ce fichier, vous pouvez ajouter ou remplacer n'importe quelle partie de l'unité expédiée par la distribution.
Par exemple, dans un fichier /etc/systemd/system/myservice.service.d/myenv.conf
:
[Service]
Environment="SECRET=pGNqduRFkB4K9C2vijOmUDa2kPtUhArN"
Environment="ANOTHER_SECRET=JP8YLOc2bsNlrGuD6LVTq7L36obpjzxd"
Notez également que si le répertoire existe et est vide, votre service sera désactivé! Si vous n'avez pas l'intention de mettre quelque chose dans le répertoire, assurez-vous qu'il n'existe pas.
Pour référence, l'ancienne méthode était:
La manière recommandée pour ce faire est de créer un fichier /etc/sysconfig/myservice
qui contient vos variables, puis chargez-les avec EnvironmentFile
.
Pour plus de détails, consultez la documentation de Fedora sur comment écrire un script systemd .
La réponse dépend de la question de savoir si la variable est censée être constante (c'est-à-dire non censée être modifiée par l'utilisateur obtenant l'unité) ou variable (supposée être définie par l'utilisateur).
Puisque c'est votre unité locale, la frontière est assez floue et dans les deux cas, cela fonctionnerait. Cependant, si vous avez commencé à le distribuer et qu'il se retrouverait dans /usr/lib/systemd/system
, cela deviendrait important.
Si la valeur n'a pas besoin de changer par instance, la meilleure façon serait de la placer comme Environment=
, directement dans le fichier d'unité:
[Unit]
Description=My Daemon
[Service]
Environment="FOO=bar baz"
ExecStart=/bin/myforegroundcmd
[Install]
WantedBy=multi-user.target
L'avantage de cela est que la variable est conservée dans un seul fichier avec l'unité. Par conséquent, le fichier d'unité est plus facile à déplacer entre les systèmes.
Cependant, la solution ci-dessus ne fonctionne pas bien lorsque sysadmin est censé modifier la valeur de la variable d'environnement localement. Plus précisément, la nouvelle valeur devrait être définie à chaque mise à jour du fichier d'unité.
Dans ce cas, un fichier supplémentaire doit être utilisé. Comment - dépend généralement de la politique de distribution.
Une solution particulièrement intéressante consiste à utiliser /etc/systemd/system/myservice.service.d
répertoire. Contrairement à d'autres solutions, ce répertoire est pris en charge par systemd lui-même et n'est donc fourni avec aucun chemin spécifique à la distribution.
Dans ce cas, vous placez un fichier comme /etc/systemd/system/myservice.service.d/local.conf
qui ajoute les parties manquantes du fichier d'unité:
[Service]
Environment="FOO=bar baz"
Ensuite, systemd fusionne les deux fichiers au démarrage du service (n'oubliez pas de systemctl daemon-reload
après avoir changé l'un ou l'autre). Et puisque ce chemin est utilisé directement par systemd, vous n'utilisez pas EnvironmentFile=
pour ça.
Si la valeur est censée être modifiée uniquement sur certains des systèmes affectés, vous pouvez combiner les deux solutions, en fournissant une valeur par défaut directement dans l'unité et un remplacement local dans l'autre fichier.
http://0pointer.de/public/systemd-man/systemd.exec.html#Environment= - vous avez deux options (une déjà indiquée par Michael):
Environment=
et
EnvironmentFile=
Les réponses de Michael et Michał sont utiles et répondent à la question initiale de savoir comment définir une variable d'environnement pour un service systemd. Cependant, une tilisation courante pour les variables d'environnement consiste à configurer des données sensibles comme les mots de passe dans un endroit qui ne sera pas accidentellement engagé dans le contrôle de code source avec le code de votre application.
Si c'est pourquoi vous souhaitez transmettre une variable d'environnement à votre service, n'utilisez pas Environment=
dans le fichier de configuration de l'unité. Utilisation EnvironmentFile=
et pointez-le vers un autre fichier de configuration qui n'est lisible que par le compte de service (et les utilisateurs disposant d'un accès root).
Les détails du fichier de configuration de l'unité sont visibles par tout utilisateur avec cette commande:
systemctl show my_service
J'ai mis un fichier de configuration à /etc/my_service/my_service.conf
et y mettre mes secrets:
MY_SECRET=correcthorsebatterystaple
Ensuite, dans mon fichier d'unité de service, j'ai utilisé 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
J'ai vérifié que ps auxe
ne peut pas voir ces variables d'environnement et les autres utilisateurs n'ont pas accès à /proc/*/environ
. Vérifiez votre propre système, bien sûr.
Michael a donné une solution propre mais je voulais obtenir une variable env mise à jour à partir du script. Malheureusement, l'exécution des commandes bash n'est pas possible dans le fichier d'unité systemd. Heureusement, vous pouvez déclencher bash dans ExecStart:
http://www.dsm.fordham.edu/cgi-bin/man-cgi.pl?topic=systemd.service&sect=5
Notez que ce paramètre ne prend pas directement en charge les lignes de commande Shell. Si des lignes de commande Shell doivent être utilisées, elles doivent être transmises explicitement à une implémentation Shell d'une certaine sorte.
Exemple dans notre cas est alors:
[Service]
ExecStart=/bin/bash -c "ENV=`script`; /bin/myforegroundcmd"