I would like to keep my environment variables out the the supervisord.conf file for security reasons (I keep the supervisord.conf under version control. I've looked at the documentation and I don't see any way of doing this with supervisor. Am I missing something?
If you run this Python script under supervisord, it will dump its environment:
#!/usr/bin/env python -u
import os
print(os.environ)
You will see that subprocesses inherit the environment of supervisord.
If you want variables in the environment of all subprocesses but don't want to put them in supervisord.conf, you can put them into the environment before supervisord is started in your init script:
export FOO=BAR
supervisord
If you want variables on a per-program basis, you can have supervisord start a shell script to run your program. The shell script would load the variables into the environment and then launch the program.
We have an active mailing list where you can ask questions and get tips for using Supervisor.
Ok thanks for the info!
@mkotsalainen
You might also be interested in envdir, which calls programs using env vars from a directory: https://github.com/jezdez/envdir
Thanks Daniel! That鈥檚 a really smart tool.
Eh it would still be nice to have an option to do this...
If I have to create a script which runs supervisor with some env variables, then it means I can't use my distro's supervisor init script.
@surjikal Your distro's init script may already provide this capability via /etc/defaults or /etc/sysconfig.
@jvoorhis Correct! Gentoo has this cool /etc/env.d thing that lets me set system wide environment variables. Works perfectly.
I found the init script at: /etc/default/supervisor
Use case:
A production server with 10 or so processes configured under supervisor. These processes rely on IO from a remote database to complete transactions for users. Currently, any changes to environment variables outside of the config file requires restarting the service, which could interrupt any running processes that are in the middle of transactions.
My question in this case would be, would an "external environment variable file" feature make sense here, so that variables can be defined and reread within supervisor, or is this an issue of how the child process chooses how to terminate when sent the signal?
As suggested above, a simple workaround would be to wrap the target command with another script that will load the environment variables from a file.
You could have a local (or source controlled) script such as:
run_with_env.sh
#!/bin/bash
ENV_FILE="$1"
CMD=${@:2}
set -o allexport
source $ENV_FILE
set +o allexport
$CMD
And then have your supervisor command be something like this:
command=run_with_env.sh envfile some-program param1 param2
inspired by this answer on SO 30969768/1629696
The workaround script is nice, but this still feels like something that should just be built in. Its surprising this is still coming up 4 years later.
The workaround does not work if you need to launch a new process, processes launched from the bash file will not be killed.
I've expected the environment= config option to also support files, not only K=V that are not so flexible.
Currently I am stuck as I cannot duplicate all the 60+ environment variables for the hook file, it simply does not make any sense.
@iongion
Have you tried killasgroup=true and stopasgroup=true?
@mnaberez Is there any chance that you would accept a PR to add environment_file? Or is there any chance for a plugin interface which could update the config after the initial read (or something similar).
@jonathan-golorry killasgroup/stopasgroup have their own downsides (namely that they kill the whole group ;)). A better workaround would probably be to use the bash exec builtin which would replace the bash process with the new program.
@mnaberez Is there any chance that you would accept a PR to add environment_file?
No. Writing a short shell script to set the environment variables is pretty much the same amount of work for the end user as writing an INI file of environment variables would be, only the shell script is more powerful and can do other things as well.
With reference to this comment, use exec to run the command as mentioned by @apollo13. That will cause the bash process to replace itself with the new program, and that program will become a direct child of supervisord (you can verify it with pstree or similar).
@mnaberez about the PR #934 yes I fully understand that we could wrap the process inside a bash script to load ENV from a file. But doing this get our setup become hairy. Wouldn't it be nice if we deligate the job to supervisor? e.g:
[program:foo]
env_file = bar.env
command = true
@nhamlh He already clearly said that he does not want to support it. At this time it seems to be a waste of your and his time to continue down this venue.
@mnaberez
It would be great to have a fully working example in this thread. It might be obvious for you, but it certainly is not for everyone. And this thread comes up first in Google.
Thanks for the great program and keep up the good work!
Hi,
On Sun, Jul 30, 2017, at 09:16 AM, gabn88 wrote:
It would be great to have a fully working example in this thread. It
might be obvious for you, but it certainly is not for everyone. And this
thread comes up first in Google.
The example is basically already there (see a few comments above + my
slight modification suggestion via exec):
#!/bin/bash
ENV_FILE="$1"
CMD=${@:2}
set -o allexport
source $ENV_FILE
set +o allexport
exec $CMD
Call with
command=run_with_env.sh envfile some-program param1 param2
Untested, please try it and report back; I'll update the post
accordingcly.
On Fri, Aug 4, 2017, at 07:49 AM, Nino Walker wrote:
Reading the
internals,
perhaps an alternative is to implement a plugin which listens for the
ProcessStarting state, and have the plugin do its magic to manipulate the
ProcessConfig.
Based on my understanding event listeners (which I assume you meant with
plugins) are running as programs themself and cannot update state in
the supervisor master process (unless I've been missing a way to write
plugins all the time -- but then I did not look to closely).
My solution was to add
. /etc/environment
as the last line into /etc/default/supervisor
Gotta echo this, purity is great, but there is a practical use for seeding/passing through those environmental variables that'd save me a lot of headaches. Gotta find a hack now.
Thanks again for the great software.
+1 systemd gives you either Environment and/or EnvironmentFile id love to see something similar here
@mnaberez , can you reopen this issue since it seems to be a popular one, and the current workaround are not really satisfying...
the solution by @tuuling is perfect IMHO
Except it doesn't work in the case where you need different env variable files for different programs, which imo is the primary reason to do this. Otherwise you could just put it in /etc/environment//etc/default/supervisor or something.
That's what I did, the problem was that supervisord by default did not include it.
I realize I'm necro-bumping a closed issue, but figured I'd put this here to help out those that arrive here via Google (as I did).
My use-case is that I wanted something a bit more robust than tini for dealing with zombie reaping in Docker. Specifically, running the self-hosted GitHub runner process that can exit and restart itself during update - something that tini can't handle.
In other words, I need supervisord to be PID 1 and have an easily plugged environment.
I tried several solutions to getting the /etc/environment file loaded as an environment via supervisord.
I tried the solution @tuuling mentioned in https://github.com/Supervisor/supervisor/issues/242#issuecomment-322421857 with no luck.
I also tried:
command=/bin/bash -c 'source "$0" && exec "$@"' /etc/environment /home/runner/actions-runner/bin/runsvc.sh
I could have wrapped the wrapper script, or modified the wrapper script. The problem with the former is that little thing with the runner stopping and restarting itself during updates, so I'd have to reproduce the necessary signal handling in my wrapper. The problem with the latter is also about that restarting business, only this time I'd have to detect the restart, and re-inject my changes to the script BEFORE it restarted.
NONE of the solutions I found worked EXCEPT adding the variables to the supervisord.conf via the environment configuration option.
Here's the magic shell one-liner that munges the /etc/environment file into a single, comma-separated line with quoted values:
```shell script
cat /etc/environment \
| sed -e 's/"//g' \
| awk -F= '{key=$1}{value=$2} BEGIN {printf "environment="} NR>1 {printf ","} {printf key"=\42"value"\42"} END {printf "\n"}' \
/etc/supervisor/conf.d/supervisord.conf
``(that firstsed` command is to remove quotes - the file is inconsistently quoted - the awk command puts them back in consistently)
The suggested environmentfile configuration option exists in systemd for a reason, that being the need to load a large number of variables in a pluggable fashion. It's not an accident that a login shell uses /etc/environment and that that file is capable of doing double duty in a systemd unit file. Loading key-value pairs as environment variables via a simple file is a pattern repeated in Docker, systemd, k8s, and in many other systems. @mnaberez I'm super confused why #934 was rejected?
Most helpful comment
+1 systemd gives you either
Environmentand/orEnvironmentFileid love to see something similar here