课程
您的团队在开发环境中遇到 Docker 构建结果不一致的问题吗?构建参数(build args)或许正是您要找的。它们是创建灵活且标准化 Docker 镜像的常用方案。通过它们,您可以在构建过程中注入数值而无需硬编码,从而让 Dockerfile 更具可移植性且易于维护。
Docker 构建参数可解决常见问题,例如在不同环境间处理不同的基础镜像、软件包版本或配置设置。
Docker 官方文档建议使用构建参数对构建进行参数化,而不是误用环境变量。它们在 CI/CD 流水线中尤为有用,您可以从同一个 Dockerfile 构建出不同配置的镜像。
> 刚接触 Docker 和容器s?请参阅我们的指南,快速入门。
在本文中,我将向您展示如何使用 Docker 构建参数,打造更高效、更安全、更灵活的容器化工作流。
Docker 构建参数简介
构建参数(或 build args)是您在构建时传递给 Docker 的变量,它们仅在镜像构建过程中可用。
与在容器运行时仍然存在的环境变量不同,构建参数只在 docker build 命令的上下文中存在,镜像创建完成后即消失。它们的作用类似于函数参数,允许您在每次构建镜像时注入不同的值。
构建参数的主要用例,围绕着创建灵活且可复用的 Dockerfile。
您可以使用构建参数来指定不同的基础镜像(例如在 Alpine 与 Debian 间切换)、在不修改 Dockerfile 的情况下设置应用版本,或配置构建时设置(如代理服务器或仓库 URL)。这种灵活性在CI/CD 流水线中特别实用,您可以根据部署目标使用不同参数来构建同一个 Dockerfile。
当您需要自定义构建,却又不想维护多个 Dockerfile 变体时,构建参数就能大显身手。它们帮助您遵循 DRY(Don’t Repeat Yourself,不要重复自己)原则,在集中化容器配置逻辑的同时仍保留定制能力。
它们也非常适合处理开发、测试与生产环境之间的差异——这些差异只应影响镜像的构建方式,而非容器的运行方式。
既然您已经了解了什么是构建参数,接下来我们来看看如何使用它们。
定义与使用构建参数
现在让我们上手实践,了解如何实现构建参数。这里假设您已经在本机安装并配置好了 Docker。
基础语法与作用域
您可以在 Dockerfile 中使用 ARG 指令声明构建参数,根据使用时机可放在 FROM 指令之前或之后。以下是基本语法:
# Setting a build arg with a default value
ARG VERSION=latest
# Using the build arg
FROM ubuntu:${VERSION}
构建镜像时,您可以通过 --build-arg 选项提供数值:
docker build --build-arg VERSION=20.04 -t myapp:20.04 .

图 1 - 基本的 Docker 构建参数
构建参数的作用域遵循一些必须理解的规则。声明在 FROM 指令之前的参数只在 FROM 之前可用,如果之后还需要使用,必须重新声明。
原因在于,每个 FROM 指令都会开启一个新的构建阶段,并拥有自己的作用域。尤其在多阶段构建中,这一行为必须牢记。
高级声明技巧
让我们创建一个完整的 Flask “Hello World” 应用,使用构建参数来支持不同配置:
> 了解如何使用 Docker 对应用进行容器化。
首先,创建一个简单的 Flask 应用(app.py):
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_world():
return "Hello, World!"
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True)
同时,创建一个 requirements.txt 文件:
flask==3.1.0
现在让我们创建一个使用构建参数进行灵活配置的 Dockerfile:
# Define build arguments with default values
ARG PYTHON_VERSION=3.13
ARG ENVIRONMENT=production
# Use the PYTHON_VERSION arg in the FROM instruction
FROM python:${PYTHON_VERSION}-slim
# Redeclare args needed after FROM
ARG ENVIRONMENT
ENV FLASK_ENV=${ENVIRONMENT}
# Set working directory
WORKDIR /app
# Copy requirements file
COPY requirements.txt .
# Install dependencies based on environment
RUN if [ "$ENVIRONMENT" = "development" ]; then \
pip install -r requirements.txt && \
pip install pytest black; \
else \
pip install --no-cache-dir -r requirements.txt; \
fi
# Copy application code
COPY . .
# Expose port
EXPOSE 5000
# Set default command
CMD ["python", "app.py"]
> 上面的 Dockerfile 看起来是否有些费解?通过我们的指南从零学习 Docker。
要为特定 Python 版本构建开发环境镜像,可在终端运行以下命令:
# Building for development with Python 3.11
docker build \
--build-arg PYTHON_VERSION=3.11 \
--build-arg ENVIRONMENT=development \
-t flaskapp:dev .

图 2 - 在基础 Python 应用中使用构建参数
在多阶段构建中,构建参数需要特别处理。下面是一个完整示例,展示如何在多个阶段之间传递参数(以我们的 Flask 应用为例):
# Dockerfile for a multi-stage build
ARG PYTHON_VERSION=3.13
# Build stage
FROM python:${PYTHON_VERSION}-slim AS builder
ARG ENVIRONMENT=production
ENV FLASK_ENV=${ENVIRONMENT}
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# In a real app, you might run tests or build assets here
RUN echo "Building Flask app for ${ENVIRONMENT}"
# Production stage
FROM python:${PYTHON_VERSION}-slim
ARG ENVIRONMENT
ENV FLASK_ENV=${ENVIRONMENT}
WORKDIR /app
COPY --from=builder /usr/local/lib/python*/site-packages /usr/local/lib/python*/site-packages
COPY --from=builder /app .
# Add metadata based on build args
LABEL environment="${ENVIRONMENT}" \
python_version="${PYTHON_VERSION}"
EXPOSE 5000
CMD ["python", "app.py"]
现在,您可以使用特定的 Python 版本与环境来构建:
docker build \
--build-arg PYTHON_VERSION=3.12 \
--build-arg ENVIRONMENT=staging \
-t flaskapp:staging .

图 3 - 在多阶段构建中使用构建参数
简而言之,这种方法可以让您在构建的所有阶段保持一致的配置。
预定义构建参数
Docker 提供了若干可直接使用、无需事先声明的预定义构建参数,包括:
HTTP_PROXY和HTTPS_PROXY:适用于有代理服务器的企业网络环境。FTP_PROXY:与 HTTP 代理类似,但用于 FTP 连接。NO_PROXY:指定应绕过代理的主机。BUILD_DATE和VCS_REF:常用于镜像元数据与版本控制。
当您在具有特定网络配置的环境中构建镜像时,这些预定义参数会非常方便。例如,在代理要求严格的企业网络中,您可以使用:
docker build --build-arg HTTP_PROXY=http://proxy.example.com:8080 .
这种做法能让您的 Dockerfile 依然具备可移植性,同时在受限环境中也能正常工作。
安全影响与风险缓解
尽管构建参数提供了灵活性,但它们也会带来潜在的安全风险。要确保镜像安全,您需要理解这些风险点。
参数泄露途径
构建参数并不像您想的那样私密。许多开发者忽视了一些泄露途径。首先,Docker 镜像历史会暴露所有构建参数。任何有权访问镜像的人都可以运行 docker history 查看构建时使用的值,其中可能包含 API 密钥或令牌等敏感信息。
docker history flaskapp:dev

图 4 - Docker 历史记录
中间层同样可能泄露构建参数。即使您使用多阶段构建且未复制包含敏感信息的层,构建参数的值仍会留存在构建机上的层缓存中。这意味着任何能访问构建服务器上 Docker 守护进程的人,都可能提取这些信息。
CI/CD 日志也是一个重要风险点。大多数 CI/CD 系统会记录整条构建命令,包括通过命令行传入的构建参数。
例如,下面整条命令(包括 API_KEY)都会出现在 CI/CD 日志中:
docker build --build-arg API_KEY=secret123 -t myapp:latest .
这些日志往往对更大范围的开发者可见,甚至存储在第三方系统中,从而扩大了敏感信息的暴露面。
更安全的替代方案
对于敏感信息,您应使用 Docker BuildKit 的 secrets 功能,而不是构建参数。BuildKit 允许您在构建过程中挂载机密,但不会将其持久化到最终镜像或历史记录中。
以下是一个使用 Docker BuildKit secrets 的 Dockerfile 示例:
FROM python:3.13-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
# Use secret mount instead of build arg
RUN --mount=type=secret,id=api_key \
cat /run/secrets/api_key > api_key.txt
EXPOSE 5000
CMD ["python", "app.py"]
要使用机密构建镜像,首先创建 api_key.txt 文件:
echo "my-secret-api-key" > api_key.txt
然后携带机密构建镜像:
DOCKER_BUILDKIT=1 docker build \
--secret id=api_key,src=api_key.txt \
-t flaskapp:secure .

图 5 - 使用 BuildKit secrets 构建镜像
对于需要在运行时可用的配置,仍然优先使用环境变量。它们可以在启动容器时设置,而无需写入镜像:
# Set environment variables at runtime
docker run -e API_KEY=secret123 -p 5000:5000 flaskapp:latest
要在生产环境中安全地处理敏感配置,建议使用如 Kubernetes 等容器编排平台,它们提供如 Secrets 等安全方法来管理敏感信息。Docker Swarm 也提供类似的机密管理能力。
> Docker 不是唯一的容器化平台。阅读 Podman 的相关内容,找出更适合您的工具。
请记住,经验法则是:将构建参数用于非敏感的构建时配置;将 BuildKit secrets 用于敏感的构建时需求;将环境变量或编排平台的机密用于运行时配置。
与容器生态系统的集成
在掌握基础之后,让我们探讨如何在更广泛的 Docker 生态与现代构建工具中利用构建参数。
Docker Compose
借助 Docker Compose,您可以轻松地在多容器应用中定义与共享构建参数。
如果您想跟着操作,下面是两个简单 Flask 服务的完整项目结构:
flask-project/
├── docker-compose.yml # Main compose configuration
├── .env # Environment variables for compose
├── web/
│ ├── Dockerfile # Web service Dockerfile
│ ├── app.py # Flask application
│ └── requirements.txt # Python dependencies
├── api/
│ ├── Dockerfile # API service Dockerfile
│ ├── app.py # API Flask application
│ └── requirements.txt # API dependencies
我将快速逐个介绍文件内容:
web/app.py
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def index():
return render_template("index.html", title="Flask Web App")
@app.route("/about")
def about():
return "About page - Web Service"
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True)
web/requirements.txt
flask==3.1.0
web/Dockerfile
# Web service Dockerfile
ARG PYTHON_VERSION=3.13
FROM python:${PYTHON_VERSION}-slim
# Redeclare the build arg to use it after FROM
ARG PYTHON_VERSION
ARG ENVIRONMENT=production
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV FLASK_ENV=${ENVIRONMENT}
WORKDIR /app
# Copy and install requirements
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY . .
# Create a simple template folder and file if not exists
RUN mkdir -p templates && \
echo "<html><body><h1>Hello from Web Service</h1><p>Python version: ${PYTHON_VERSION}</p><p>Environment: ${ENVIRONMENT}</p></body></html>" > templates/index.html
EXPOSE 5000
CMD ["python", "app.py"]
api/app.py
from flask import Flask, jsonify
app = Flask(__name__)
@app.route("/api/health")
def health():
return jsonify({"status": "healthy"})
@app.route("/api/data")
def get_data():
return jsonify(
{"message": "Hello from the API service", "items": ["item1", "item2", "item3"]}
)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000, debug=True)
api/requirements.txt
flask==3.1.0
api/Dockerfile
ARG PYTHON_VERSION=3.13
FROM python:${PYTHON_VERSION}-slim
# Redeclare the build arg to use it after FROM
ARG PYTHON_VERSION
ARG ENVIRONMENT=production
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV FLASK_ENV=${ENVIRONMENT}
WORKDIR /app
# Copy and install requirements
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY . .
# Add metadata label based on build args
LABEL python.version="${PYTHON_VERSION}" \
app.environment="${ENVIRONMENT}"
EXPOSE 8000
CMD ["python", "app.py"]
.env
PYTHON_VERSION=3.10
ENVIRONMENT=development
docker-compose.yml
services:
web:
build:
context: ./web
dockerfile: Dockerfile
args:
PYTHON_VERSION: ${PYTHON_VERSION:-3.13}
ENVIRONMENT: ${ENVIRONMENT:-development}
ports:
- "5000:5000"
depends_on:
- api
api:
build:
context: ./api
dockerfile: Dockerfile
args:
PYTHON_VERSION: ${PYTHON_VERSION:-3.13}
ENVIRONMENT: ${ENVIRONMENT:-production}
ports:
- "8000:8000"
简而言之,这是一种非常简单的方式,可以同时在隔离环境中启动两个应用,并为它们分别指定一组构建参数。
您可以使用以下命令运行该多容器环境:
docker compose up --build

图 6 - 在 Docker Compose 中使用构建参数
几秒钟后,您将看到两个服务都已启动:

图 7 - 在 Docker Compose 中使用构建参数(2)
对于这两个简单应用而言,这样的设置略显冗长,但核心要点很清晰——构建参数在 compose 文件中设定,并在各自的 Dockerfile 中引用。
另外,您也可以将环境中的变量值传递给构建参数,这在 CI/CD 流水线中非常方便:
services:
web:
build:
context: .
args:
- PYTHON_VERSION=${PYTHON_VERSION:-3.10}
而在运行 docker-compose 时,如需覆盖这些值,可以使用环境变量:
PYTHON_VERSION=3.10 docker-compose up --build
这种方法既能在团队内保持构建一致性,又在需要时提供足够的灵活性。
BuildKit 功能
BuildKit 是 Docker 的现代构建引擎,它能大幅增强构建流程,使构建参数更加强大。启用 BuildKit(设置 DOCKER_BUILDKIT=1)后,您将解锁多项能力。
内联缓存可通过利用远程镜像的构建缓存来提升性能。您可以使用 --cache-from 指定一个缓存源镜像,BuildKit 将智能地复用其层:
DOCKER_BUILDKIT=1 docker build \
--build-arg PYTHON_VERSION=3.10 \
--cache-from flaskapp:dev \
-t flaskapp:latest .
另一项实用功能是确定性输出,确保构建可复现。无论何时何地构建,得到的镜像都完全相同:
# Build with deterministic output
DOCKER_BUILDKIT=1 docker build \
--build-arg PYTHON_VERSION=3.10 \
--build-arg BUILD_DATE=2025-05-01 \
--output type=docker,name=flaskapp:stable \
.
BuildKit 的日志机密脱敏功能可在构建过程中保护敏感信息。
与普通构建参数会出现在构建日志中不同,BuildKit 会自动隐藏机密的值:
# Create a file with the API key
echo "my-api-key-value" > ./api-key.txt
# Build with secret (value won't appear in logs)
DOCKER_BUILDKIT=1 docker build \
--secret id=api_key,src=./api-key.txt \
-t flaskapp:secure .
在 Dockerfile 中,您可这样访问该机密:
RUN --mount=type=secret,id=api_key \
cat /run/secrets/api_key > /app/config/api_key.txt
这些 BuildKit 功能与构建参数相辅相成,共同打造出更安全、高效且可复现的构建系统,几乎能适配任意容器化工作流。
企业级落地的最佳实践
要在大型团队中推广 Docker 构建参数,需要采用标准化方法,以尽量减少困惑并最大化安全与性能收益。
在企业环境中采用构建参数,应从完善的参数校验开始。
始终为每个构建参数提供合理的默认值,确保在未传递参数时构建不会意外失败。您还应在 Dockerfile 中加入校验,以验证关键构建参数是否满足要求。
以下示例用于校验 Python 版本:
ARG PYTHON_VERSION=3.9
# Validate Python version
RUN if [[ ! "$PYTHON_VERSION" =~ ^3\.[0-9]+$ ]]; then \
echo "Invalid Python version: ${PYTHON_VERSION}. Must be 3.x"; \
exit 1; \
fi
在 CI/CD 流水线中,优化层缓存对缩短构建时间至关重要。
按变更频率对 Dockerfile 指令进行排序:将不常变化的内容(如依赖安装)放在更前面,而将经常变化的内容(如应用代码)放在后面。
当使用可能频繁变更的构建参数时,将它们置于稳定操作之后,以避免使整个缓存失效:
FROM python:3.13-slim
WORKDIR /app
# Dependencies change less frequently - good cache utilization
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Build args that might change often come AFTER stable operations
ARG BUILD_NUMBER
ARG COMMIT_SHA
# Now these args won't invalidate the dependency cache
通过构建参数管理元数据,可提升可追溯性与合规性。使用构建参数将构建时元数据注入为标签:
ARG BUILD_DATE
ARG VERSION
ARG COMMIT_SHA
ARG BUILD_URL
LABEL org.opencontainers.image.created="${BUILD_DATE}" Can you please provide me with access to this document?
org.opencontainers.image.version="${VERSION}" \
org.opencontainers.image.revision="${COMMIT_SHA}" \
org.opencontainers.image.url="${BUILD_URL}"
这些标准化标签遵循开放容器倡议(OCI)规范,意味着您的镜像将与不同容器管理工具兼容。
文档往往被忽视,但对企业级落地至关重要。
创建清晰的 README 部分,记录所有可用的构建参数、用途、默认值与使用示例。注明哪些参数是必填、哪些是可选,并记录不同参数之间的相互影响。也可将这些信息以注释形式加入 CI/CD 流水线配置文件,帮助开发者理解需要提供哪些值:
# Example documented CI configuration
build_job:
script:
# BUILD_NUMBER: Unique identifier for this build (required)
# ENVIRONMENT: Target deployment environment [dev|staging|prod] (required)
# PYTHON_VERSION: Python version to use (optional, default: 3.9)
- docker build
--build-arg BUILD_NUMBER=${CI_PIPELINE_ID}
--build-arg ENVIRONMENT=${DEPLOY_ENV}
--build-arg PYTHON_VERSION=${PYTHON_VERSION:-3.9}
-t myapp:${CI_PIPELINE_ID} .
若要实现真正的企业级落地,建议实施可版本化并可校验的构建参数模式(schema)。这种方法可让您在保持向后兼容的同时,逐步演进构建配置。
对比分析:构建参数 vs. 环境变量
若要创建既安全又灵活、同时符合最佳实践的 Docker 镜像,您必须明白何时使用构建参数、何时使用环境变量。
下面是一张可随时参考的表格:
|
特性 |
构建参数 |
环境变量 |
|
可用性 |
仅在镜像构建期间可用 |
在构建与容器运行时均可用 |
|
持久性 |
不会保留在最终镜像中(除非显式转换为 |
会保存在镜像中,并对运行中的容器可用 |
|
安全性 |
可通过 docker history 在镜像历史中看到 |
不会出现在镜像历史中,但对容器内进程可见 |
|
用途 |
适用于构建时配置,如版本、构建路径、编译器标志 |
适用于运行时配置,如连接串、功能开关、日志级别 |
|
声明方式 |
在 Dockerfile 中使用 |
在 Dockerfile 中用 |
|
默认值 |
可提供默认值: |
可提供默认值: |
|
作用域 |
限定在各自的构建阶段,需在每个 |
在所有构建阶段可用,并被子镜像继承 |
|
覆盖方式 |
|
|
关键区别在于时机与目的。 构建参数用于配置构建过程本身,而环境变量用于配置正在运行的应用。例如,您会用构建参数来选择基础镜像(ARG PYTHON_VERSION=3.10),而用环境变量告诉应用监听哪个端口(ENV PORT=8080)。
从安全角度看,构建参数对敏感信息的风险更高,因为它们会保留在镜像历史中。
针对不同类型配置,可参考以下工作流:
# Build-time configuration (non-sensitive)
ARG PYTHON_VERSION=3.13
FROM python:${PYTHON_VERSION}-slim
# Build-time secrets (use BuildKit secrets)
RUN --mount=type=secret,id=build_key \
cat /run/secrets/build_key > /tmp/key && \
# Use the secret for build operations
rm /tmp/key
# Runtime configuration (non-sensitive)
ENV LOG_LEVEL=info
# Runtime secrets (should be injected at runtime, not here)
# This would be provided at runtime with:
# docker run -e API_KEY=secret123 myimage
在实践中,一个常见模式是:当某些构建参数需要在运行时可用时,将它们转换为环境变量:
ARG APP_VERSION=1.0.0
# Make the version available at runtime
ENV APP_VERSION=${APP_VERSION}
在企业级应用中,这种分离使不同团队可以分别管理应用生命周期的不同方面: DevOps 团队可调整构建参数以构建镜像,而运维人员可在部署时调整环境变量,而无需重新构建镜像。
总结 Docker 构建参数
Docker 构建参数不只是另一个技术特性——它们是让您的镜像在团队与各环境中保持一致性的利器。
我已经演示了如何在简单的 Python 项目中使用它们,同时确保敏感信息安全。您也看到了如何将构建参数与 Docker Compose 等工具集成。
将构建参数视为灵活容器化策略的基础。从小处着手,在下一个项目中参数化 Python 版本;熟悉后,再为不同环境添加条件逻辑。不久之后,您就能创建复杂的多阶段构建,使团队无需修改 Dockerfile 即可自定义。
准备更进一步了吗? 下面这些 DataCamp 课程值得一看:
FAQs
什么是 Docker 构建参数?
Docker 构建参数(build args)是您在镜像构建过程中传递给 Docker 的变量,仅在镜像构建期间可用。它们让您无需修改 Dockerfile 就能实现自定义,从而使容器构建更灵活、更可复用。您可以将它们视为每次构建镜像时都可调整的参数,非常适合处理不同环境或配置。
Docker 中的构建参数与环境变量有何不同?
构建参数仅在镜像构建期间存在,而环境变量在容器运行时仍然存在。构建参数通过 Dockerfile 中的 ARG 指令定义,并在构建时通过 --build-arg 传入,适合用于选择基础镜像或设置构建时配置。环境变量通过 ENV 定义,旨在为运行中的应用提供所需的运行时配置。
使用 Docker 构建参数时需要注意哪些安全问题?
构建参数并不像许多开发者想象的那样私密——其取值会出现在镜像历史与 CI/CD 日志中。切勿将构建参数用于 API 密钥或密码等敏感信息,因为任何能访问镜像的人都可能看到这些值。对于敏感数据,请改用 Docker BuildKit secrets,它们不会持久化到最终镜像或历史记录。
如何在 GitHub Actions 等 CI/CD 流水线中传递构建参数?
多数 CI/CD 平台均支持在配置文件中传递 Docker 构建参数。在 GitHub Actions 中,您可以在工作流 YAML 中通过 docker/build-push-action 的 build-args 参数传入构建参数。可根据安全需求引用环境变量、仓库机密或硬编码值。这样便可基于分支、环境或其他 CI 变量,自动化地以不同配置进行构建。
Dockerfile 中的构建参数数量是否有限制?
严格来说,Dockerfile 中构建参数的数量没有技术上限,但过多会使 Dockerfile 难以理解与维护。对于数据科学项目,建议重点参数化关键变量,如 Python 版本、框架选择或数据集配置。如果您发现使用了超过 8–10 个构建参数,考虑将 Dockerfile 拆分为更聚焦的小文件,或使用 Docker Compose 来管理复杂度。
