Complete Guide to Environment Variable Passing in Docker Build: Deep Analysis of ARG and ENV Instructions

Nov 17, 2025 · Programming · 24 views · 7.8

Keywords: Docker build arguments | Environment variable passing | ARG instruction | ENV instruction | Multi-stage builds

Abstract: This article provides an in-depth exploration of environment variable passing mechanisms in Docker build processes, focusing on the distinctions and relationships between ARG and ENV instructions. Through detailed code examples and practical application scenarios, it explains how to correctly use build arguments to pass host environment variables in Dockerfile, and offers advanced techniques including multi-stage builds, scope management, and default value settings. The article also covers security considerations, best practice recommendations, and solutions to common problems, providing Docker users with a comprehensive methodology for environment variable management.

Fundamental Concepts of Docker Build Arguments and Environment Variables

In Docker build processes, environment variable passing is a common but often confusing technical aspect. Many developers attempt to directly reference host environment variables using the ENV instruction in Dockerfile, but frequently encounter issues with incorrect value transmission. In reality, Docker provides the specialized ARG instruction to handle build-time parameter passing.

Core Functions and Syntax of ARG Instruction

The ARG instruction is specifically designed for defining build-time parameters, which can be set during the docker build command using the --build-arg flag. Its basic syntax is as follows:

# Define build argument without default value
ARG request_domain

# Define build argument with default value
ARG request_domain=127.0.0.1

When building the image, parameter values can be passed using:

docker build --build-arg request_domain=example.com .

Environment Variable Persistence and Runtime Configuration

While the ARG instruction is used for build-time parameter passing, these parameters are not available in runtime containers by default. If access to these values is required in runtime containers, they need to be converted to environment variables:

ARG request_domain
ENV REQUEST_DOMAIN=$request_domain

This combined approach ensures both build-time flexibility and runtime availability.

Scope Management and Multi-stage Builds

In complex multi-stage build scenarios, build argument scope management becomes particularly important. Globally defined ARG parameters are not automatically inherited into individual build stages and need to be explicitly declared within each stage:

# syntax=docker/dockerfile:1
# Global scope definition
ARG APP_VERSION="1.0.0"

FROM alpine AS base
# Need to redeclare within stage to use
ARG APP_VERSION
RUN echo "Building version: $APP_VERSION"

FROM base AS production
# Child stages automatically inherit parent stage parameters
RUN echo "Production version: $APP_VERSION"

Security Considerations and Best Practices

When using build arguments, security considerations are crucial. Since build arguments remain in image history records, they are unsuitable for passing sensitive information such as passwords or API keys. For sensitive data transmission, Docker's secret mechanism should be used:

# Insecure approach
ARG DB_PASSWORD

# Secure approach: using Docker secrets
RUN --mount=type=secret,id=db_password \
    export DB_PASSWORD=$(cat /run/secrets/db_password) && \
    ./configure-database.sh

Practical Application Scenarios and Code Examples

Consider a practical application scenario: building a Ruby application container that requires DNS resolution configuration during build. Here's the complete solution:

# Dockerfile
FROM ruby:3.2

# Define build arguments
ARG request_domain
ARG app_environment="production"

# Convert to environment variables
ENV REQUEST_DOMAIN=$request_domain
ENV RAILS_ENV=$app_environment

# Install dnsmasq and configure
RUN apt-get update && apt-get install -y dnsmasq
RUN echo "address=/$REQUEST_DOMAIN/127.0.0.1" >> /etc/dnsmasq.conf

WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle install

COPY . .
CMD ["dnsmasq", "-d"]

Build command:

docker build \
  --build-arg request_domain=myapp.example.com \
  --build-arg app_environment=staging \
  -t my-ruby-app .

Error Handling and Debugging Techniques

When using build arguments, common errors include undefined parameters or spelling mistakes. Docker provides clear error messages to help diagnose issues:

# If referencing undefined ARG parameter, build will fail
ENV UNKNOWN_VAR=$undefined_arg  # Error: undefined_arg not defined

# If passing unused build arguments, warning will be received
docker build --build-arg unused_arg=value .
# Output: [Warning] One or more build-args [unused_arg] were not consumed.

Advanced Features: Predefined Build Arguments

Docker provides a series of predefined build arguments, particularly useful for multi-platform build scenarios:

# Using predefined multi-platform parameters
FROM --platform=$BUILDPLATFORM golang:1.21 AS builder
ARG TARGETOS
ARG TARGETARCH
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /app .

FROM alpine
COPY --from=builder /app /app
CMD ["/app"]

Performance Optimization and Caching Strategies

Proper use of build arguments can significantly optimize build caching. When build argument values change, Docker re-executes all subsequent instructions starting from where the parameter is used:

# Place frequently changing parameters later in Dockerfile
FROM node:20

# Dependency installation that doesn't change frequently
COPY package*.json ./
RUN npm ci

# Build arguments that might change frequently
ARG BUILD_TIMESTAMP
ENV BUILD_TIMESTAMP=$BUILD_TIMESTAMP

COPY . .
RUN npm run build

Summary and Best Practice Recommendations

Through the detailed analysis in this article, we can summarize the following best practices: always use the ARG instruction for build-time parameter passing; convert build arguments to runtime environment variables using the ENV instruction; pay attention to parameter scope management in multi-stage builds; avoid using build arguments for sensitive information transmission; and properly organize Dockerfile structure to optimize build caching. These practices will help developers build more flexible, secure, and efficient Docker images.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.