Is there a way to dynamically assign environment variables in a systemd service unit file?
We have a machine that has 4 GPUs, and we want to spin up multiple instances of a certain service per GPU. E.g.:
- [email protected]:1.service
- [email protected]:1.service
- [email protected]:1.service
- [email protected]:1.service
- [email protected]:2.service
- [email protected]:2.service
- [email protected]:2.service
- [email protected]:2.service
- ad nauseam
So the 1:1, 2:1, etc. are effectively the %i in the service unit file.
In order for the service to bind to a particular GPU, the service executable checks a certain environment variable, e.g.:
USE_GPU=4
Is there a way I can take %i inside the service unit file and run it through some (shell) function to derive the GPU number, and then I can set the USE_GPU environment variable accordingly?
Most importantly, I don’t want the hassle of writing multiple /etc/systemd/system/[email protected]:y.service/local.conf files just so I can spin up more instances.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
If you are careful you can incorporate a small bash script sequence as your exec command in the instance service file. Eg
ExecStart=/bin/bash -c 'v=%i; USE_GPU=$${v%:*} exec /bin/mycommand'
The $$ in the string will become a single $ in the result passed to bash, but more importantly will stop ${...} from being interpolated by systemd. (Earlier versions of systemd did not document the use of $$, so I don’t know if it was supported then).
Method 2
No built in way. You need to do these things before your service starts. One way would be putting it to an environment file.
[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=...
Method 3
It looks like you can indeed set environment variables inside a systemd unit file…
Per suggestions from commenters, here is the solution:
Using environment variables in systemd units
Environment directive
systemd has an Environment directive which sets environment variables for executed processes. It takes a space-separated list of variable assignments. This option may be specified more than once in which case all listed variables will be set. If the same variable is set twice, the later setting will override the earlier setting. If the empty string is assigned to this option, the list of environment variables is reset, all prior assignments have no effect. Environments directives are used in built-in Container Linux systemd units, for example in etcd2 and flannel.
With the example below, you can configure your etcd2 daemon to use encryption. Just create
/etc/systemd/system/etcd2.service.d/30-certificates.confdrop-in for 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.keyThen run
sudo systemctl daemon-reloadandsudo systemctl restart etcd2.serviceto apply new environments to etcd2 daemon.
Quoted text taken from the following URL:
https://coreos.com/os/docs/latest/using-environment-variables-in-systemd-units.html
Method 4
It’s ugly and not quite what you asked for, nor does it allow for autostart, but for followers it is possible to do something using the systemctl environment:
$ sudo systemctl set-environment USE_GPU=4 # add it to the env. variables for future services $ sudo systemctl start <a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d0b7a0a58fa3b5a2a6b9b3b590e4">[email protected]</a>:2.service
One problem is if you run/start more than one “at once” (in parallel) then it could cause confusion/race conditions.
Just trying to list all the options possible, some of the other answers work as well 🙂
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0