Use Environment Variables¶
Right now your app always says the same thing, because the message is baked into the code. In this lesson you'll move that setting out of the code, so the same image can behave differently depending on where it runs. This is one of the most important habits in real Docker work. ⚙️
What we will do (in very simple steps)¶
- Make the app read a setting from its environment
- Change that setting at run time, without rebuilding
- Set a default inside the Dockerfile
- Manage several settings with an env file
Why move settings out of code?¶
Think of your image as a recipe. You don't want to rewrite the recipe every time you fancy a different seasoning. You want to season to taste when you cook. 🧂
Settings like messages, modes, and (soon) database passwords are that seasoning. They change from place to place, dev versus production, your laptop versus a server. If they're hard-coded, you'd need a different image for each place. With environment variables, one image serves them all.
Step 1: Make the app read a setting¶
Open ~/my-docker-app/app.py and update it to read a GREETING value from the environment:
import os
from flask import Flask
app = Flask(__name__)
@app.route("/")
def home():
greeting = os.environ.get("GREETING", "Hello")
return {"message": f"{greeting} from my first Docker image!"}
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
os.environ.get("GREETING", "Hello") reads the environment variable GREETING. If it isn't set, it falls back to "Hello".
Because you changed the code, you must rebuild the image:
⚠️ Forgetting to rebuild after a code change is the most common mistake here. If your change doesn't appear, rebuild first.
Step 2: Change the setting at run time¶
First run it normally, with no setting passed:
You'll get the fallback:
Now remove it and run again, this time passing a value with -e:
docker rm -f myapp
docker run -d -p 8000:5000 -e GREETING="Bonjour" --name myapp my-first-app
curl http://localhost:8000
The message changes:
Same image, different behaviour, no rebuild. 🎯 That -e GREETING="Bonjour" is the seasoning added at serving time.
Clean up:
Step 3: Set a default inside the Dockerfile¶
Passing -e every single time is tedious. You can bake a sensible default into the image with ENV. Add this line to your Dockerfile, just above the CMD line:
So the end of your Dockerfile now reads:
Rebuild and run with no -e:
docker build -t my-first-app .
docker run -d -p 8000:5000 --name myapp my-first-app
curl http://localhost:8000
Now the default is Hi, coming from the Dockerfile:
You can still override it at run time with -e. The order of priority, from weakest to strongest, is:
- The fallback in your code (
"Hello") - The
ENVdefault in the Dockerfile (Hi) - The
-evalue passed at run time (wins over everything)
Clean up again:
Step 4: Use an env file for several settings¶
Real apps have many settings. Listing a dozen -e flags gets messy, so Docker can read them from a file instead.
In ~/my-docker-app, create a file named app.env:
Then point Docker at it:
You'll see Hola. As your settings grow, you just add more lines to that file. Clean up:
🔒 A note on secrets: environment variables are perfect for ordinary settings, and they're commonly used for passwords too. Just be aware that for truly sensitive values in production, there are safer tools than plain env vars. We'll touch on that later. For now, keep any real secrets out of files you commit to Git.
Where this is heading 🔜¶
In the next two lessons your app gains a database. Its location and password will be passed in as environment variables, exactly the pattern you just learned, never hard-coded. So this small lesson is the foundation for connecting real services together.
✅ Checkpoint¶
You've finished this lesson if:
- Your app returns the fallback message when no setting is passed
-e GREETING="Bonjour"changes the message without a rebuild- An
ENVline in the Dockerfile sets a default ofHi --env-file app.envsets the message toHola
🩹 Common hiccups¶
- Your change doesn't show up: you edited
app.pybut didn't rebuild. Rundocker build -t my-first-app .again. - The value still looks like the old one: an old container is still running.
docker rm -f myappand start fresh. - Env file not applied: check you're in the folder containing
app.env, and that the filename matches exactly. - Spaces around the equals sign: in the env file, write
GREETING=Hola, notGREETING = Hola. Spaces become part of the value.
Next up: Docker Volumes in Practice, where your app meets a database and you make sure its data survives even when the container is removed.