Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: include environment variables from external file #242

Closed
mkotsalainen opened this issue May 31, 2013 · 32 comments
Closed

Comments

@mkotsalainen
Copy link

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?

@mnaberez
Copy link
Member

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.

@mkotsalainen
Copy link
Author

Ok thanks for the info!

@blueyed
Copy link
Contributor

blueyed commented Jan 20, 2014

@mkotsalainen
You might also be interested in envdir, which calls programs using env vars from a directory: https://github.com/jezdez/envdir

@mkotsalainen
Copy link
Author

Thanks Daniel! That’s a really smart tool.

@surjikal
Copy link

surjikal commented Jun 6, 2014

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.

@jvoorhis
Copy link

@surjikal Your distro's init script may already provide this capability via /etc/defaults or /etc/sysconfig.

@surjikal
Copy link

@jvoorhis Correct! Gentoo has this cool /etc/env.d thing that lets me set system wide environment variables. Works perfectly.

@tuuling
Copy link

tuuling commented Jun 1, 2015

I found the init script at: /etc/default/supervisor

@robolivable
Copy link

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?

@odedfos
Copy link

odedfos commented Jan 24, 2017

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

@jonathan-golorry
Copy link

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.

@iongion
Copy link

iongion commented Apr 7, 2017

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.

@jonathan-golorry
Copy link

@iongion
Have you tried killasgroup=true and stopasgroup=true?

@apollo13
Copy link
Contributor

@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
Copy link
Member

@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).

@nhamlh
Copy link

nhamlh commented May 12, 2017

@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

@apollo13
Copy link
Contributor

@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.

@gabn88
Copy link

gabn88 commented Jul 30, 2017

@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!

@apollo13
Copy link
Contributor

apollo13 commented Aug 4, 2017 via email

@apollo13
Copy link
Contributor

apollo13 commented Aug 4, 2017 via email

@tuuling
Copy link

tuuling commented Aug 15, 2017

My solution was to add
. /etc/environment
as the last line into /etc/default/supervisor

@tony
Copy link

tony commented Oct 6, 2017

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.

@farridav
Copy link

farridav commented Mar 16, 2018

+1 systemd gives you either Environment and/or EnvironmentFile id love to see something similar here

@MeTaNoV
Copy link

MeTaNoV commented Jun 11, 2019

@mnaberez , can you reopen this issue since it seems to be a popular one, and the current workaround are not really satisfying...

@boussou
Copy link

boussou commented Aug 8, 2019

the solution by @tuuling is perfect IMHO

@pirate
Copy link

pirate commented Aug 15, 2019

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.

@tuuling
Copy link

tuuling commented Aug 15, 2019

That's what I did, the problem was that supervisord by default did not include it.

@rbellamy
Copy link

rbellamy commented Apr 23, 2020

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 #242 (comment) 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:

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 first sed 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?

@ShivKJ
Copy link

ShivKJ commented Aug 19, 2021

Hi there,
Is there a way to provide the env file directly and let supervisor read it?

@hyperair
Copy link

Sorry for necro-bumping this issue, but I just wanted to report a bug in the run_with_env.sh script posted above: CMD=${@:2} does not quote arguments properly, and will split arguments by string, as does simply running $CMD.

The correct way to do this would either be to use shift to remove the env file argument, or to quote the array slice, and exec the array quoted.

run_with_env_fixed.sh
#!/bin/bash

ENV_FILE="$1"
shift

set -o allexport
source $ENV_FILE
set +o allexport

exec "$@"
run_with_env_fixed2.sh
#!/bin/bash

ENV_FILE="$1"
CMD=("${@:2}")

set -o allexport
source $ENV_FILE
set +o allexport

exec "${CMD[@]}"
Test output
% ./run_with_env.sh /dev/null showargs foo 'bar baz'
foo
bar
baz
% ./run_with_env_fixed.sh /dev/null showargs foo 'bar baz'
foo
bar baz
% ./run_with_env_fixed2.sh /dev/null showargs foo 'bar baz'
foo
bar baz
% cat $(which showargs)
#!/bin/bash

while [ ${#@} -ne 0 ]; do
    echo "$1";
    shift
done

@leanmontesoro
Copy link

My solution was to add . /etc/environment as the last line into /etc/default/supervisor

hi @tuuling can you pass an example of what your /etc/default/supervisor file looks like please?

Thank you!

@tuuling
Copy link

tuuling commented Jul 25, 2022

My solution was to add . /etc/environment as the last line into /etc/default/supervisor

hi @tuuling can you pass an example of what your /etc/default/supervisor file looks like please?

Thank you!

Hi. That was 5 years ago. I don't remember what I did there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests