Lesson 2.3: Environment Variables and Arguments
Welcome to Lesson 2.3! Building on your Dockerfile knowledge, we now explore how to make your images more flexible and configurable. Environment variables and build arguments are essential tools for parameterizing your builds and containers. They allow you to change behavior without modifying the Dockerfile, making your images reusable across different environments.
Learning Objectives
TIP
By the end of this lesson, you will be able to:
- Differentiate between
ENVandARGinstructions. - Set and use environment variables in a Dockerfile and at runtime.
- Pass build-time variables with
--build-arg. - Understand the scope and persistence of variables.
- Apply best practices for using variables securely.
1. Environment Variables (ENV)
The ENV instruction sets an environment variable that persists in the image and is available to all subsequent instructions and to running containers.
Syntax:
ENV <key>=<value> ...- You can set multiple variables in one line:
ENV key1=value1 key2=value2. - The variable is available in any
RUN,CMD,ENTRYPOINTinstructions that follow.
Example:
FROM alpine
ENV APP_HOME=/app
WORKDIR $APP_HOME
RUN echo "Home is $APP_HOME" > info.txt
CMD cat info.txtWhen you run the container, it prints Home is /app.
1.1. Using ENV in Subsequent Instructions
Variables are expanded in RUN, CMD, and ENTRYPOINT when using the shell form. In exec form, they are not automatically expanded; you need to invoke a shell explicitly or use the form ["sh", "-c", "command"].
Example of exec form with variable expansion:
CMD ["sh", "-c", "echo $APP_HOME"]1.2. Overriding ENV at Runtime
You can override or add environment variables when starting a container using the -e or --env flag with docker run.
docker run -e APP_HOME=/newpath myimageThis overrides the APP_HOME variable for that container only. You can also pass multiple -e flags or use an env file (--env-file).
1.3. Viewing Environment Variables in a Container
- Inside a running container, run
envorprintenv. - Inspect the image or container:
docker inspectshows theConfig.Envfield.
2. Build Arguments (ARG)
The ARG instruction defines a variable that users can pass at build time. Unlike ENV, ARG variables are not available in the running container unless you explicitly copy them into ENV.
Syntax:
ARG <name>[=<default value>]- You can set a default value; if not provided, the variable is optional.
- To pass a value at build time:
docker build --build-arg <name>=<value> -t myimage .
Example:
FROM alpine
ARG VERSION=latest
RUN echo "Building version ${VERSION}" > /version.txtBuild with default: docker build -t myapp . → version.txt contains "Building version latest". Build with custom: docker build --build-arg VERSION=1.2.3 -t myapp . → version.txt contains "1.2.3".
2.1. Scope of ARG
ARGvariables are only available during the build, from the line where they are defined to the end of the build stage.- They are not persisted in the final image (unless used to set an
ENV).
2.2. Predefined ARGs
Docker automatically provides a few built-in build arguments:
HTTP_PROXY/http_proxyHTTPS_PROXY/https_proxyFTP_PROXY/ftp_proxyNO_PROXY/no_proxyTARGETPLATFORM,TARGETOS,TARGETARCH,TARGETVARIANT(for multi-platform builds)BUILDPLATFORM, etc.
These can be used without declaring them, useful in multi-stage builds.
3. Key Differences: ENV vs ARG
| Feature | ENV | ARG |
|---|---|---|
| Scope | Image and running container | Build only (not in final image) |
| Persistence | Yes, remains in image | No, disappears after build |
| Override at build | Not directly | Yes, with --build-arg |
| Override at runtime | Yes, with -e | No |
| Use case | Runtime configuration, default settings | Build-time parameters (versions, flags) |
4. Combining ARG and ENV
A common pattern is to use an ARG to set an ENV variable. This allows the value to be customized at build time and also persist into the container.
FROM alpine
ARG APP_VERSION
ENV APP_VERSION=${APP_VERSION}
RUN echo "App version: $APP_VERSION" > /version.txtNow:
- Build with
--build-arg APP_VERSION=2.0→ the container will haveAPP_VERSION=2.0set. - The variable is available at runtime and can still be overridden with
-e.
INFO
Important: The ENV instruction is evaluated at build time. The value of ARG is substituted into ENV at that moment.
5. Using Environment Variables in Commands
5.1. In Shell Form
ENV NAME=John
RUN echo "Hello, $NAME" > /greeting5.2. In Exec Form
Exec form does not invoke a shell, so variable expansion does not happen automatically. You have two options:
- Use the shell form for
CMD/ENTRYPOINT(less secure for signals, but simple). - Explicitly invoke a shell:dockerfile
CMD ["sh", "-c", "echo $NAME"]
5.3. Using ENV in COPY and ADD
WARNING
Environment variables are not expanded in COPY or ADD instructions. You cannot do COPY $APP_HOME /something.
6. Best Practices and Security
DANGER
Never store secrets (passwords, API keys) in ENV or ARG. They can be inspected via docker history and docker inspect. Use Docker secrets (in Swarm) or external secret management.
- Use
ARGfor non-sensitive build parameters like versions, flags. - Use
ENVfor runtime configuration that might change per environment. - Provide default values for
ARGwhere possible to make builds predictable. - Combine
ARGandENVcarefully to avoid leaking build-time values into the final image unnecessarily.
Example of a Sensitive Leak
ARG SECRET_TOKEN
ENV SECRET_TOKEN=${SECRET_TOKEN}If you then push this image, anyone pulling it can see SECRET_TOKEN in docker inspect. Never do this with real secrets.
7. Hands-On Tasks
Task 1: Basic ENV Usage
- Create a Dockerfile:dockerfile
FROM alpine ENV GREETING="Hello from Docker" CMD echo $GREETING - Build and run:
docker build -t greet . && docker run greet - Override at runtime:
docker run -e GREETING="Custom hello" greet - Check the environment inside the container (optional):
docker run -it greet shand runenv.
Task 2: Build Arguments
- Create a Dockerfile that accepts an argument
VERSIONand creates a file with the version.dockerfileFROM alpine ARG VERSION=1.0 RUN mkdir /app && echo "Version: $VERSION" > /app/version.txt CMD cat /app/version.txt - Build with default:
docker build -t version-app .and run. - Build with custom version:
docker build --build-arg VERSION=2.5 -t version-app2 .and run. - Run
docker history version-app2and observe that theARGdoes not create a persistent layer? (It does create a layer, but the variable is not in the final image.)
Task 3: Combine ARG and ENV
- Create a Dockerfile that accepts
APP_ENVas a build argument and sets it as an environment variable.dockerfileFROM alpine ARG APP_ENV=production ENV APP_ENV=${APP_ENV} RUN echo "Environment: $APP_ENV" > /env.txt CMD cat /env.txt - Build for development:
docker build --build-arg APP_ENV=development -t myapp-dev . - Run it:
docker run myapp-dev→ should print "Environment: development". - Override at runtime:
docker run -e APP_ENV=staging myapp-dev→ prints "staging" (runtime override wins).
Task 4: Inspect Environment Variables
Build any image with an
ENV.Use
docker inspectto view the environment:bashdocker inspect <image> | grep -A 5 EnvOr format:
bashdocker inspect --format='{{json .Config.Env}}' <image>For a running container, use
docker exec <container> env.
Task 5: Multi-Platform ARG (Optional)
- If you have Docker Buildx set up, try building for multiple platforms and use
TARGETPLATFORMin your Dockerfile:dockerfileFROM --platform=$BUILDPLATFORM alpine ARG TARGETPLATFORM RUN echo "Building for $TARGETPLATFORM" > /platform CMD cat /platform - Build with
docker buildx build --platform linux/amd64,linux/arm64 -t platform-test .(or just a single platform to see the variable).
Summary
Key Takeaways
ENVsets environment variables that persist into the running container and can be overridden at runtime.ARGdefines build-time variables that can be passed with--build-arg; they do not survive into the final image.- Use
ARGfor build customization (e.g., version numbers, proxy settings). - Use
ENVfor runtime configuration and default values. - Combine
ARGandENVto make build-time values available at runtime, but beware of leaking secrets. - Never store secrets in
ENVorARGif you plan to share the image.
Check Your Understanding
- What is the main difference between
ENVandARGin terms of persistence? - If you set an environment variable with
ENVin a Dockerfile, can you change it when running the container? How? - How do you pass a build-time variable named
GIT_COMMITtodocker build? - Will a variable defined with
ARGbe available inside a running container? Why or why not? - Why is it unsafe to use
ARGorENVfor sensitive data like passwords? - Write a Dockerfile instruction that sets a default build argument
PORTto 8080.
Click to see answers
ENVvariables persist in the image and are available at runtime.ARGvariables exist only during the build process and do not persist into the final image.- Yes, use the
-eor--envflag withdocker run, e.g.,docker run -e VAR_NAME=value myimage. - With the
--build-argflag:docker build --build-arg GIT_COMMIT=<hash> -t myimage . - No.
ARGis only available during the build. Unless you copy its value into anENVvariable, it won't exist inside the running container. - Both
ARGandENVvalues are visible indocker historyanddocker inspect. Anyone who pulls the image can read them. Even if you remove them in a later layer, the filesystem layers still contain the original data. ARG PORT=8080or simplyARG PORT(without a default).
Additional Resources
- Dockerfile reference: ENV
- Dockerfile reference: ARG
- Environment variables in Docker (overview)
- Best practices for ENV and ARG
- Build arguments and environment variables (blog)
Next Up
In the next lesson, we'll dive into multi-stage builds, a powerful technique to keep your images small and efficient. See you there!