Is it good practice to pass arguments to Docker containers through environment variables? - python

I have an image whose task is to run a simulation. However there are some settings that I want to change in different simulations.
To achieve this, I set some environment variables when starting a container, which then I pass as command line arguments to my main simulation script.
Is this considered good practice for creating "customized" containers from the same image?

The typical ways to configure a container include:
command line arguments (often paired with an entrypoint)
environment variables
config file mounted as a volume or docker config
There's no one best way, though the config file method is typically used for passing a larger amount of configuration into a container that may also be checked into version control. Environment variables are perfectly acceptable and are also described in the 12 factor app design.

Related

Most secure way to store secrets while building a docker image (Python flask server)

So currently I am building a docker image for my python flask server, and the way that I am accessing the secret variable inside the code is
app.config["SECRET_KEY"] = os.environ.get("todo_secret_key") or "secret"
Now if I want to run the code without the container, I'd use export command(linux) to temporarily have the secret key in the environment, but I need it to be in the environment of the container.
Now, a few methods that I am aware of are
Pass it with -e in the docker run command docker run {imageName} -e {name}={value} (insecure as I dont want it to be in terminal logs)
Pass it in the dockerfile by specifying the environment variable (definitely insecure as this file would be public)
Apart from these methods, is there a more secure way to pass the variable
P.s It is my first time buidling an image so apologies if it is a silly question
You're trying to tie your runtime configuration to your build time configuration much too tightly if you're worrying about this as you're building your docker image!
Remember that these are discrete, if interconnected, stages.
Develop -> Build -> Test -> Deploy -> Test (Non-functional) -> repeat...
No stage should dictate what future stages do. docker build is the "Build" stage, and so should have no idea what configuration is correct in the environment for when the image is eventually deployed. How could it? That configuration could change over time!
Instead, look to configuration management to handle these sorts of decisions. Your docker scheduler (Kubernetes is common, but other flyweight executors like Docker Swarm or ECS should do this too) should have a way to read a configuration file and inject it into the environment. A full discussion of configuration management could (and has) filled textbooks.

Is storing project configuration in environment variables a bad practice?

Some background first:
i am currently testing a class that sends a GET request with a configurable url, which is built like this
url = f"{os.environ["TARGET_URL"]}/api/etc"
For normal operation, my TARGET_URL environment variable is set at project startup from a .env file and everything works. When testing locally, everything is still fine, tests passes and everyone is happy. My issue arose when I discovered that my Drone CI server failed to complete the project's build because the TARGET_URL environment variable wasn't found.
After some digging I found out that I had the wrong (dumb) idea that environment variables were reset at every project/test startup, and I basically was using my production environment variable all this time (even during tests) because it was set at first project startup.
From this story comes my question: given that environment variables are kept between executions, would storing configurations in them result in a bad practice? Is there an equally convenient alternative (no global objects and access from everywhere in the code) that can be used instead?
Thanks everyone for the quick responses, here's a bit of what-happened-next:
environment variables stay loaded after the first initialization, so I needed a way to test my code after loading only the variables I needed, with values that were expected. This would allow me to keep using environment variables loaded from a .env file and keep building my project remotely, where no .env files are present.
The solution was to add a pytest plugin called pytest-dotenv, which when properly configured would allow me to overwrite every variable in my .env files with a custom variable from another file (.env.test in my case). I filled the .env.test file with all the variables found in the .env file, and assigned empty values to each of them.
This allowed my tests to run ensuring no weird edge cases are missed because something had the wrong value.
example .env file
TARGET_URL="http://my.api.dev
example .env.test file
TARGET_URL=
pytest.ini configuration
[pytest]
env_override_existing_values = 1
env_files =
.env.test
Environment variables stored in config files or .env files is not a bad practice.
However, it is recommended that you use a key vault such as Azure Key Vault or AWS Key Management System for production deployments.
This way you further remove the keys away from your server (if env files) as well as code (if it is in config files)

Setting environment variables in Google Cloud Platform using Cloud Functions

I'm following the guide here and can't seem to get my Python app (which is deployed fine on GCP) to read the environment variables I've created in Cloud Functions.
The REST endpoint for the function returns the environment variables fine as I've coded up the Python method in the function to just do os.environ.get() on a request parameter that is passed in. However, in my actual deployed application, I don't want to do a REST GET call every time I need an environment variable. I would expect using os.environ.get() in my application would be enough, but that returns blank.
How does one go about retrieving environment variables on GCP with just a simple os.environ.get() or do I really have to make a call to an endpoint every time?
I have been struggling with this for some time. The only solution I have found to set environment variables for the whole app is to define them in app.yaml. See the env_variables section here.
But then you cannot commit app.yaml to any version control repository if you don't want people to see the environment variables. You could add it to .gitignore. There are more secure ways to handle secrets storage if these variables contain sensitive data. If you need more robust security, you might find some inspiration here.

Is it possible to override uwsgi ini-file with environment variables

I'm trying to build a "base" docker image for running a python framework with uwsgi. The goal is to have others build their own docker images where they dump their application logic and any configuration overrides they need.
I thought it might be nice to be able to override any default settings from a uwsgi.ini file by supplying UWSGI_* environment variables passed to uwsgi at startup.
I've tried this approach, and setting a value via env var works if it's not in the ini-file at all (e.g UWSGI_WORKERS=4). But if I put a workers=1 line in the ini-file, it seems to override the env var.
Is this expected behaviour? I'm having trouble finding anything about config resolution order in the docs.
Do I have to resort to something like this? Using env vars seems so much cleaner.
if-exists = ./override.ini
include = %(_)
endif =
First, make all environment variables in the .ini file refer to the environment variables like below:
[uwsgi]
http = $(HTTP_PORT)
processes = $(UWSGI_WORKERS)
threads = $(UWSGI_THREADS)
...
Then set whatever default values you want for these environment variables inside the Dockerfile.
Now, anyone using your base image can overwrite any config by setting the specific env variable.

'environment' and 'directory' options in Supervisord

I am using Supervisord to manage a uwsgi process on a server, and I came across these two options: environment and directory for running a program using Supervisord.
I look at the docs, but still not sure what exactly they do. To clarify, the context here is that I am running a web2py app with uwsgi. And inside the config for uwsgi, I've already set the PYTHONPATH and the virtualenv it should run with.
Can someone please explain what these two options are for and how do I set them if necessary?
Both options are well documented (see Subprocess Environment and the configuration file documentation).
What it comes down to is that these two options let you set the current working directory and the full environment for the subprocesses that supervisord starts. These are two basic UNIX concepts and many processes may behave differently depending on how these are set. See Working directory and Environment variable on Wikipedia for in-depth discussion of those concepts.
Generally, if your uwsgi process is running properly, there is no need to tinker with these at all.
If you do need to set them, just add the entries to your configuration, setting directory to an existing path on your system and the environment value to a set of KEY=VALUE pairs joined by commas.

Categories

Resources