一.Dockerfile概述
1. 什么是 Dockerfile
Dockerfile 是一个用于构建 Docker 镜像的文本文件,其中包含一系列 指令(Instruction) 。
Docker 引擎会根据这些指令,自上而下、逐条执行 ,最终生成一个不可变的镜像(Image)。
2. 镜像、Layer 与容器的关系
- Docker 镜像(Image) 由多个 只读 Layer 组成
- 每一条 Dockerfile 指令都会生成一个 Layer
- Layer 是不可变的增量快照
- 构建缓存、镜像复用、镜像瘦身,全部基于 Layer 机制
镜像 = 多个只读 Layer 的叠加
容器 = 镜像 + 一层可写层(Container Layer)
3. Dockerfile 到 Layer 的真实映射
示例 Dockerfile:
dockerfile
FROM ubuntu:20.04
RUN apt-get update
RUN apt-get install -y curl
COPY app.sh /app/app.sh
生成的镜像层如下:
| 层号 | Dockerfile 指令 | Layer 内容 |
|---|---|---|
| 1 | FROM ubuntu | Ubuntu 文件系统 |
| 2 | RUN apt-get update | apt 缓存 |
| 3 | RUN apt-get install | curl 二进制 |
| 4 | COPY app.sh | app.sh 文件 |
注意:Dockerfile 不是合并执行 ,而是逐层叠加。
二.Dockerfile 核心指令详解
1.FROM
1.1 指令说明
FROM 用于指定当前镜像所基于的基础镜像 ,是 Dockerfile 中的第一条有效指令 。
一个 Dockerfile 中可以存在多个 FROM(用于多阶段构建)。
基础镜像来源:
- Docker 会优先在本地查找基础镜像
- 本地不存在则从 Docker Hub 或私有仓库拉取
- 镜像不存在则构建失败
1.2 语法格式
Dockerfile
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
Dockerfile
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
1.3 参数说明
| 参数 | 是否必需 | 含义 | 示例 | 工程建议 |
|---|---|---|---|---|
| FROM | 必需 | 声明新的构建阶段并指定基础镜像 | FROM ubuntu |
每个 Dockerfile 至少一个 |
| --platform | 可选 | 指定 OS / CPU 架构 | linux/amd64、linux/arm64 |
跨平台 / CI 推荐 |
<image> |
必需 | 基础镜像名称 | openjdk、ubuntu |
使用可信镜像源 |
:<tag> |
推荐 | 镜像版本标签 | :11-jre |
不指定则默认最新版本,生产必须指定版本 |
@<digest> |
可选 | 镜像内容哈希(不可变) | @sha256:... |
强一致性与安全 |
AS <name> |
可选 | 构建阶段命名 | AS builder |
多阶段构建必用 |
1.4 示例
Dockerfile
FROM williamyeh/java8:latest
Dockerfile
FROM williamyeh/java8@sha256:174d528516a0eae5c4df69966eeb5e51d7c0dc1a532249af61013953eab1d9f3
Dockerfile
FROM --platform=linux/amd64 ubuntu:20.04 AS builder
1.5 多阶段构建(Multi-stage Build)
多阶段构建通过 多个 FROM 将构建环境 与运行环境 分离,仅保留最终运行所需的产物,从而:大幅减小镜像体积、降低安全风险、提高可维护性。
❌ 错误示例(单阶段)
dockerfile
FROM openjdk:11
RUN apt-get update && apt-get install -y maven
COPY . /app
WORKDIR /app
RUN mvn package
ENTRYPOINT ["java", "-jar", "target/app.jar"]
问题:
- Maven 与源码永久存在镜像中
- 镜像臃肿,攻击面扩大
✅ 正确示例(多阶段构建)
dockerfile
# 构建阶段
FROM maven:3.9-eclipse-temurin-11 AS builder
WORKDIR /build
COPY pom.xml .
COPY src ./src
RUN mvn clean package -DskipTests
# 运行阶段
FROM openjdk:11-jre
WORKDIR /app
COPY --from=builder /build/target/app.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
最终镜像仅包含 JRE 与 app.jar
2.WORKDIR
2.1 指令说明
WORKDIR指令用于在 Docker 镜像内部设置工作目录 。一旦设置了 WORKDIR,后续的 RUN、CMD、ENTRYPOINT、COPY 和 ADD 这几个指令的执行环境,都会以这个目录为当前起点。
如果一个 Dockerfile 中从未使用过 WORKDIR,那么所有指令的**默认当前目录是根目录 /。
2.2 语法格式
Dockerfile
WORKDIR /path/to/workdir
2.3 示例
绝对路径:
Dockerfile
FROM ubuntu:22.04
WORKDIR /usr/why/app
RUN pwd
COPY . .
RUN 和之后的所有命令,都是在 /usr/why/app 下执行 COPY 方法则是将宿主机当前目录下所有文件,复制到 /usr/src/app 文件夹下
相对路径:
Dockerfile
FROM ubuntu:22.04
WORKDIR /app
RUN pwd # 输出:/app
WORKDIR why
RUN pwd # 输出:/app/why
WORKDIR test
RUN pwd # 输出:/app/why/test
设置相对路径后,依次增加追加前置的工作目录
3.COPY
3.1 指令说明
COPY 用于将构建上下文中的文件或目录 复制到镜像中,这些文件或目录会被添加到镜像的文件系统 里,成为镜像的一部分。是最推荐使用的文件复制指令。
3.2 语法格式
Dockerfile
COPY [--from=<name>] [--chown=<user>:<group>] [--chmod=<perms>] [--link] [--parents] [--exclude=<pattern>] <src>... <dest>
Dockerfile
COPY [--from=<name>] [--chown=<user>:<group>] [--chmod=<perms>] [--link] [--parents] [--exclude=<pattern>] ["<src>",... "<dest>"]
3.3 参数说明
| 参数 | 作用 | 典型使用场景 | 备注 |
|---|---|---|---|
--from=<stage> |
从指定构建阶段复制文件 | 多阶段构建中复制编译产物 | 多阶段构建核心参数 |
--chown=<user>:<group> |
设置文件属主和属组 | 非 root 用户运行容器 | 优于 RUN chown |
--chmod=<perms> |
设置文件权限 | shell 脚本 / 可执行文件 | 如 755、644 |
--exclude=<pattern> |
排除匹配的文件 | 精细控制 COPY 内容 | 类似 .dockerignore,但更局部 |
--parents |
保留源文件目录结构 | 批量复制并保持路径 | 适合复制深层文件 |
--link |
使用硬链接代替复制 | 大文件/不可变文件/构建性能优化 | 多个 Layer 共享同一文件数据减少 IO、加快构建 |
3.4 示例
从指定构建阶段复制文件:
Dockerfile
COPY --from=builder /build/target/app.jar /app/app.jar
设置文件属主和属组:
Dockerfile
COPY --chown=appuser:appgroup app.jar /app/app.jar
设置文件权限:
Dockerfile
COPY --chmod=755 start.sh /app/start.sh
排除匹配的文件:
Dockerfile
COPY --exclude=*.md --exclude=test/ . /app/
保留源文件目录结构:
Dockerfile
COPY --parents src/main/resources/application.yml /app/
使用硬链接代替复制:
注:需开启 DOCKER_BUILDKIT=1
Dockerfile
COPY --link app.jar /app/app.jar
4.ADD
4.1 指令说明
ADD指令时一个比COPY 指令功能更宽泛的资源引入指令 ,主要功能为向镜像文件系统中引入新的数据,数据内容可以来自上下文文件 或远程URL ,并对于某些类型的压缩文件可自动解压。
4.2 语法格式
Dockerfile
ADD [--keep-git-dir] [--checksum=<checksum>] [--chown=<user>:<group>] [--chmod=<perms>] [--link] [--exclude=<pattern>] <src>... <dest>
Dockerfile
ADD [--keep-git-dir] [--checksum=<checksum>] [--chown=<user>:<group>] [--chmod=<perms>] [--link] [--exclude=<pattern>] ["<src>", ... "<dest>"]
4.3 参数说明
| 参数 | 作用 | 典型使用场景 | 备注 |
|---|---|---|---|
--keep-git-dir |
保留 .git 目录 |
构建时需要 Git 元信息 | 当 ADD 的源是 Git 仓库 时,保留 .git 目录 |
--checksum=<checksum> |
校验下载内容的完整性 | ADD URL 资源 | 校验通过 URL 下载的文件是否被篡改 |
--chown=<user>:<group> |
设置文件属主/属组 | 非 root 容器 | 设置 ADD 后文件的属主和属组 |
--chmod=<perms> |
设置文件权限 | 脚本 / 可执行文件 | 如 755、644 |
--link |
使用硬链接而非复制 | 构建性能优化 | 多个 Layer 共享同一文件数据减少 IO、加快构建 |
--exclude=<pattern> |
排除匹配文件 | 精细控制 ADD 内容 | 在 ADD 时排除指定文件 |
4.4 示例
下载远程 git 链接并保留 .git 目录:
使用 git 需启用 BuildKit
Dockerfile
ADD --keep-git-dir https://github.com/example/repo.git /src
校验下载内容的完整性:
注:url下载的文件不会解压
Dockerfile
ADD --checksum=sha256:abc123 https://example.com/app.tar.gz /app/
设置文件属主/属组:
Dockerfile
ADD --chown=app:app app.tar.gz /app/
设置文件权限:
Dockerfile
ADD --chmod=755 start.sh /app/start.sh
使用硬链接:
Dockerfile
ADD --link app.tar.gz /app/
排除匹配文件:
Dockerfile
ADD --exclude=*.md --exclude=test/ . /app/
4.5 与 COPY 的对比
| 对比维度 | COPY | ADD | 备注 |
|---|---|---|---|
| 基本功能 | 复制本地文件/目录 | 复制文件 + 扩展功能 | 能用 COPY 就用 COPY |
| 是否支持 URL | ❌ 不支持 | ✅ 支持 | url下载的文件不会解压 |
| 是否自动解压 | ❌ 否 | ✅ 是 | 支持的格式:.tar .tar.gz .tgz .tar.bz2 .tbz2 .tar.xz .txz |
| 是否支持 Git 仓库 | ❌ | ⚠️(BuildKit 支持) | 需开启 BuildKit,docker高版本自动开启 |
| 行为可预测性 | ⭐⭐⭐⭐⭐ | ⭐⭐ | COPY 更安全 |
| 构建可控性 | 高 | 低 | COPY 更易维护 |
| 构建缓存稳定性 | 稳定 | 不稳定 | ADD 易失效 |
| 是否推荐用于生产 | ✅ 强烈推荐 | ⚠️ 谨慎 | 官方态度 |
| 可读性 | 高(即复制) | 低(可能有隐式行为) | 团队友好性 |
| 安全风险 | 低 | 较高 | ADD 可能引入供应链风险 |
5. MAINTAINER(已废弃)
5.1 指令说明
MAINTAINER 指令设置 Docker 镜像的制作者的个人信息。
5.2 语法格式
Dockerfile
MAINTAINER <作者信息>
5.3 示例
Dockerfile
MAINTAINER xiaoyangzi
MAINTAINER xiaoyangzi <xiaoyangzi@email.com>
6.LABEL
6.1 指令说明
LABEL指令为镜像添加元数据 (metadata)的指令。这些元数据以键值对(key-value) 的形式存在,用于描述镜像的作者、版本、用途、来源 等信息。
LABEL 不会影响镜像的构建流程和运行行为,其主要作用是信息标注与管理。
6.2 语法格式
Dockerfile
LABEL <key>=<value> <key>=<value> <key>=<value> ...
6.3 示例
设置制作人信息:
Dockerfile
LABEL maintainer="xiaoyangzi <xiaoyangzi@email.com>"
设置多个标签:
Dockerfile
LABEL maintainer="xiaoyangzi <xiaoyangzi@email.com>" \
version="1.0" \
description="测试镜像"
7.ENV
7.1 指令说明
ENV 指令用于在 Docker 镜像构建过程中设置环境变量 。这些变量会被设置在由该 Dockerfile 构建出的镜像环境里。环境变量可以在Dockerfile的许多指令中使用,包括但不限于:WORKDIR、ENV、LABEL、RUN、CMD、ENTRYPOINT、COPY、ADD等。
当以某个镜像运行容器时,使用ENV设置的环境变量将持续存在。可以使用docker inspect 查看这些值,并使用 docker run --env <key>=<value> 来更改它们。
7.2 语法格式
常用形式:
Dockerfile
ENV <key>=<value> [<key>=<value>...]
一对一形式(不推荐):
Dockerfile
ENV <key> <value>
在 Dockerfile 中,环境变量的引用有两种方式:$variable_name 和 ${variable_name}。
- 基本引用 :
使用 \$variable_name 时,变量名后面不能紧跟字母、数字、下划线,需以空格、换行、特殊字符等来表示变量名的结束。如果变量名后面需要紧接着其他字母数字下划线,就必须使用${variable_name}形式来明确变量名的范围。 - 括号形式 :
使用 \${variable_name} 可以明确指定变量名的边界,这样可以在字符串中直接嵌入变量而不会引起歧义。 - 转义 :如果需要使用$字符本身,而不是作为变量引用,可以用
\$来转义。
7.3 示例
一对一形式:
Dockerfile
ENV NAME "XYZ"
常用形式:
Dockerfile
ENV NAME="XYZ" \
AGE=18 \
gender=male
使用示例:
Dockerfile
ENV NAME XYZ
CMD echo "Hello, $NAME"
CMD echo "Hello, ${NAME}"
8.ARG
8.1 指令说明
ARG(Argument)是 Dockerfile 中用于定义构建阶段变量的指令。该变量仅在镜像构建过程中 可用,用于向构建过程传递参数,而不会在容器运行时自动保留 。
ARG 的主要作用是提高 Dockerfile 的可配置性与复用性。
8.2 语法格式
Dockerfile
ARG <name>[=<default value>] [<name>[=<default value>]...]
一个 ARG 变量从它被定义的那一行开始才生效,在这行之前使用它是无效的。
在使用 docker build 命令构建镜像时,使用 --build-arg 标志来为 ARG 变量赋值。
bash
docker build --build-arg <变量名>=<值> --build-arg <变量名>=<值> .
8.3 示例
定义变量
Dockerfile
ARG APP_ENV=dev
ARG APP_VERSION
ARG BUILD_TIME
使用变量:
与ENV使用方法相似:
Dockerfile
RUN echo "Environment: $APP_ENV"
RUN echo "Version: ${APP_VERSION}"
同样可以使用shell方式 ${APP_VERSION:-v0.0.1},如果 APP_VERSION 未被定义则默认 v0.0.1
Dockerfile
RUN echo "Environment: $APP_ENV"
RUN echo "Version: ${APP_VERSION:-v0.0.1}"
构建时传参:
bash
docker build \
--build-arg APP_ENV=prod \
--build-arg APP_VERSION=1.2.3 \
--build-arg BUILD_TIME=2025-01-01 \
.
8.4 ENV和ARG的区别
| 维度 | ARG | ENV |
|---|---|---|
| 生命周期 | 构建阶段(ARG在构建阶段可传参改变) | 构建 + 容器运行阶段(容器期可用) |
| 可否在容器运行时访问 | ❌ | ✅ |
| 默认值 | Dockerfile 内可定义 | Dockerfile 内可定义 |
| 多阶段构建作用域 | 每个阶段需重新声明,或者在 FROM 前全局声明 | 继承上阶段,可重新定义进行覆盖 |
| 安全性 | 不安全,可能出现在镜像历史 | 同样不安全,存在于镜像元数据 |
| 使用场景 | 动态构建参数、版本号、条件编译 | 容器运行期配置、路径、端口、标识等 |
联合使用 ARG 和 ENV
Dockerfile
ARG APP_ENV=dev
ENV APP_ENV=${APP_ENV}
RUN echo "Build environment: $APP_ENV"
注:ARG的只会被 ENV定义的值覆盖:
Dockerfile
FROM ubuntu
ARG NAME=xyz
ENV NAME=why
RUN echo $NAME
Dockerfile
FROM ubuntu
ENV NAME=why
ARG NAME=xyz
RUN echo $NAME
两个的NAME的输出均为 why
8.5 内置 ARG 变量
在 Dockerfile 里,有一些内置(预定义)ARG 变量,主要是为了支持构建阶段的一些特定场景。它们不是所有变量都自动存在,而是 Docker 官方定义的、可以直接使用或覆盖的构建参数。
| 变量名 | 说明 | 可用阶段 |
|---|---|---|
BUILD_DATE |
构建时间(通常用来标记镜像构建时间) | 构建阶段 |
VCS_REF |
Git 提交 hash(可选,用于标记源代码版本) | 构建阶段 |
TARGETPLATFORM |
当前构建的平台(例如 linux/amd64) |
构建阶段 |
BUILDPLATFORM |
执行构建的宿主平台(例如 linux/amd64) |
构建阶段 |
TARGETOS |
构建目标操作系统(例如 linux、windows) |
构建阶段 |
TARGETARCH |
构建目标 CPU 架构(例如 amd64、arm64) |
构建阶段 |
TARGETVARIANT |
构建目标架构的变体(例如 v7) |
构建阶段 |
9. RUN
9.1 指令说明
RUN指令用于在镜像构建阶段 执行命令,并将执行结果提交为一个新的镜像层(image layer)。
RUN = 构建时执行命令 + 固化结果到镜像中
9.2 语法格式
Shell 格式:
会启动 shell 来执行命令,通常是 /bin/sh, 实际执行时会包装为 /bin/sh -c ""
注:支持变量替换,通配符,管道,逻辑运算符等操作,可使用 $HOME、*.txt、|、&&等功能。
Dockerfile
RUN [OPTIONS] <command> ...
Exec 格式:
使用一个数组来明确指定要运行的可执行文件路径以及它的参数。
Docker 会直接调用这个可执行文件,而不通过任何默认的 Shell。
Dockerfile
RUN [OPTIONS] [ "<command>", ... ]
注:环境变量不会自动展开,通配符、管道和逻辑运算符无效,如不能使用 $HOME、*.txt、|、&&等功能。
如果既想使用 Exec 格式,又需要 Shell 的特性(比如变量替换),你必须显式地调用一个 Shell:
Dockerfile
RUN ["/bin/bash", "-c", "echo $HOME && rm -rf *.log"]
两种形式对比
| 格式类型 | Dockerfile 写法 | 是否启动 shell | 变量展开 | 逻辑运算符 | 是否支持管道 | 是否支持重定向 | 是否支持 glob | 适合复杂逻辑 |
|---|---|---|---|---|---|---|---|---|
| Shell 格式 | RUN echo hello | ✅ 是(/bin/sh -c) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ 非常适合 |
| Exec 格式 | RUN ["echo","hello"] | ❌ 否 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ 不适合 |
OPTIONS 参数:
以下参数仅在 BuildKit 启用时可用:
| 参数 | 作用对象 | 解决什么问题 | 常见取值 / 类型 | 是否进入最终镜像 | 典型使用场景 | 关键注意点 |
|---|---|---|---|---|---|---|
--mount |
文件系统 | 在构建阶段临时挂载资源 | type=cache 构建缓存 type=bind 绑定主机或上下文文件 type=secret 构建期密钥 type=ssh 构建期 SSH 访问 |
❌ 不会 | 依赖缓存 私有仓库凭证 SSH 拉代码 | 仅当前 RUN 有效 构建结束即销毁 |
--network |
网络 | 控制构建期联网行为 | default 默认网络 none 完全断网 host 使用宿主机网络 |
❌ 不会 | 禁止隐式下载 可复现构建 | none 可显著提升安全性 |
--security |
安全策略 | 放宽构建沙箱限制 | sandbox(默认) insecure 放宽安全限制 |
❌ 不会 | 私有仓库 token、npm / pip 私服凭证、SSH key | CI 中慎用 |
--device |
硬件设备 | 构建期访问宿主设备 | /dev/kvm /dev/nvidia0 |
❌ 不会 | QEMU / GPU 构建 | 极少数场景需要 |
9.3 示例
shell 形式:
Dockerfile
RUN echo "Hello Docker"
Exec 形式:
Dockerfile
RUN ["echo", "Hello Docker"]
合并 RUN:
Dockerfile
RUN apt-get update \
&& apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*
使用变量:
Dockerfile
ARG APP_VERSION
RUN echo "version=$APP_VERSION"
构建缓存:
Dockerfile
RUN --mount=type=cache,target=/root/.cache \
pip install -r requirements.txt
绑定主机或上下文文件:
Dockerfile
RUN --mount=type=bind,source=requirements.txt,target=/tmp/req.txt \
pip install -r /tmp/req.txt
构建期密钥:
Dockerfile
RUN --mount=type=secret,id=mytoken \
cat /run/secrets/mytoken
构建命令:
bash
docker build --secret id=mytoken,src=token.txt .
构建期 SSH 访问:
Dockerfile
RUN --mount=type=ssh git clone git@github.com:private/repo.git
构建命令:
bash
docker build --ssh default .
在构建阶段禁止联网
Dockerfile
RUN --network=none go build
控制构建阶段的安全策略:
Dockerfile
RUN --security=insecure some-command
临时暴露设备给 RUN:
Dockerfile
RUN --device=/dev/kvm make test
组合使用:
Dockerfile
RUN --mount=type=cache,target=/root/.cache \
--mount=type=secret,id=npm_token \
--network=default \
npm install
10.ENTRYPOINT
10.1 指令说明
ENTRYPOINT 用于定义容器启动时的固定入口程序 。无论用户在 docker run 后面传什么,ENTRYPOINT 都会被执行 。
当使用 docker run 命令启动一个基于该镜像的容器时,Docker 守护进程会执行 ENTRYPOINT 所指定的命令。这个命令会成为容器的"主进程"(PID 1)。
10.2 语法格式
Exec 格式:
使用字符串数组组成命令,且必须是双引号。
Dockerfile
ENTRYPOINT ["executable", "param1", "param2"]
Shell 格式:
会启动 shell 来执行命令,通常是 /bin/sh, 实际执行时会包装为 /bin/sh -c "<command>"
Dockerfile
ENTRYPOINT command param1 param2
两者区别:
| 对比维度 | Exec 格式 | Shell 格式 |
|---|---|---|
| Dockerfile 写法 | ENTRYPOINT ["nginx"] |
ENTRYPOINT nginx |
| 是否启动 shell | ❌ 否 | ✅ 是(/bin/sh -c) |
| 实际执行模型 | 直接 execve 程序 |
/bin/sh -c "cmd" |
| PID 1 是谁 | 应用程序本身 | /bin/sh |
| 是否直接接收 SIGTERM | ✅ 是 | ❌ 否(可能被吞) |
| 是否支持优雅停止 | ✅ 是 | ❌(不可靠) |
| 信号传递可靠性 | ⭐⭐⭐⭐⭐ | ⭐ |
| 容器停止行为 | 可预测、可控 | 不稳定 |
是否支持 $VAR |
❌ | ✅ |
| 是否支持 `&& / | ` | ❌ |
是否支持重定向 > |
❌ | ✅ |
| 是否支持管道 | ❌ | ✅ |
| 是否支持通配符 | ❌ | ✅ |
| 是否支持 shell 内建 | ❌ | ✅ |
| CMD 是否作为参数 | ✅(强) | ❌(语义混乱) |
| docker run 参数追加 | ✅ | ⚠️ 不直观 |
| 工程可维护性 | ⭐⭐⭐⭐⭐ | ⭐⭐ |
| 生产环境推荐度 | ⭐⭐⭐⭐⭐ | ⭐ |
替换 ENTRYPOINT:
ENTRYPOINT 一般是不可变的,但是可以在启动容器时使用 --entrypoint 参数覆盖
bash
docker run --entrypoint bash image
如果我们采用 --entrypoint 覆盖了 ENTRYPOINT,则 Dockerfile 中作为 ENTRYPOINT 参数的原始 CMD 命令会被忽略
10.3 示例
Exec 格式:
Dockerfile
ENTRYPOINT ["python"]
| docker run 命令 | 实际执行 |
|---|---|
docker run image app.py |
python app.py |
Shell 格式:
Dockerfile
ENTRYPOINT nginx -g "daemon off;"
与CMD组合执行:
Dockerfile
ENTRYPOINT ["python"]
CMD ["app.py"]
| docker run 命令 | 实际执行 |
|---|---|
docker run image |
python app.py |
docker run image other.py |
python other.py |
11.CMD
11.1 指令说明
CMD 用于为容器提供默认启动命令或默认参数 。它只在容器启动时执行(docker run),不会在构建 docker build 阶段执行。
Dockerfile 中只能有一个 CMD,如果有多个 CMD 指令,也只有最后一个会生效,并且可以被运行时参数覆盖:
Dockerfile
CMD ["echo", "hello"]
bash
docker run image echo world
echo hello 会被 echo world 覆盖,只会输出 world。
11.2 语法格式
Shell 格式:
会启动 shell 来执行命令,通常是 /bin/sh, 实际执行时会包装为 /bin/sh -c "<command>"
Dockerfile
CMD command param1 param2
Exec 格式:
使用字符串数组组成命令,且必须是双引号。
Dockerfile
CMD ["executable","param1","param2"]
为 ENTRYPOINT 提供默认参数:
和 ENTRYPOINT 指令配合使用,CMD 的作用不再是直接运行一个命令,而是为 ENTRYPOINT 指定的命令提供一组默认的参数。
Dockerfile
CMD ["param1","param2"]
两者区别:
| 对比维度 | Exec 格式 | Shell 格式 | 参数格式(配合 ENTRYPOINT) |
|---|---|---|---|
| Dockerfile 写法 | CMD ["executable","arg1","arg2"] |
CMD command arg1 arg2 |
ENTRYPOINT ["exe"] CMD ["arg1","arg2"] |
| 是否启动 shell | ❌ 否 | ✅ 是(/bin/sh -c) |
❌ 否 |
| 实际执行模型 | 直接 execve |
/bin/sh -c "cmd" |
execve(ENTRYPOINT + CMD) |
| PID 1 是谁 | 可执行程序 | /bin/sh |
ENTRYPOINT 程序 |
| 是否接收 SIGTERM | ✅ | ❌(不可靠) | ✅ |
| 是否支持优雅停止 | ✅ | ❌ | ✅ |
是否支持 $VAR |
❌ | ✅ | 有在 ENTRYPOINT 本身是 shell 时才可以。 |
| 是否支持 `&& / | ` | ❌ | ✅ |
是否支持重定向 > |
❌ | ✅ | 有在 ENTRYPOINT 本身是 shell 时才可以。 |
是否支持 管道 |
❌ | ✅ | 有在 ENTRYPOINT 本身是 shell 时才可以。 |
| 是否支持通配符 | ❌ | ✅ | 有在 ENTRYPOINT 本身是 shell 时才可以。 |
| CMD 是否可被覆盖 | ✅(整体替换) | ✅(整体替换) | ✅(仅替换参数 |
| docker run 参数行为 | 覆盖整个 CMD | 覆盖整个 CMD | 追加 / 替换参数 |
| 与 ENTRYPOINT 协作能力 | 一般 | 差 | ⭐⭐⭐⭐⭐ |
| 行为可预测性 | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ |
| 生产环境推荐度 | ⭐⭐⭐⭐ | ⭐ | ⭐⭐⭐⭐⭐ |
| 典型使用场景 | 固定启动命令 | 临时调试 | 官方镜像、服务型容器 |
11.3 示例
Exec 形式:
Dockerfile
CMD ["nginx", "-g", "daemon off;"]
Shell 形式:
Dockerfile
CMD nginx -g "daemon off;"
配合 ENTRYPOINT:
Dockerfile
ENTRYPOINT ["nginx"]
CMD ["-g", "daemon off;"]
| docker run | 实际执行 |
|---|---|
docker run image |
nginx -g daemon off; |
docker run image -t |
nginx -t |
RUN、ENTRYPOINT、CMD 区别
| 对比维度 | RUN | ENTRYPOINT | CMD | |
|---|---|---|---|---|
| 所属阶段 | 构建阶段(build time) | 运行阶段(run time) | 运行阶段(run time) | |
| 核心作用 | 构建镜像内容 | 定义容器的固定入口程序 | 定义默认启动命令或参数 | |
| 是否生成镜像层 | ✅ 每条 RUN 生成一层 | ❌ | ❌ | |
| 是否在构建时执行 | ✅ | ❌ | ❌ | |
| 是否在容器启动时执行 | ❌ | ✅ | ✅ | |
| 是否必须存在 | ❌ | ❌ | ❌ | |
| 是否只能有一条 | ❌ | ✅(最后一条生效) | ✅(最后一条生效) | |
| 是否支持 Shell 格式 | ✅ | ✅(不推荐) | ✅(不推荐) | |
| 是否支持 Exec 格式 | ✅ | ✅(强烈推荐) | ✅(推荐) | |
| 是否启动 shell | Shell 格式会 | Shell 格式会 | Shell 格式会 | |
是否支持 $VAR && ` |
> *` |
✅(Shell) | ❌(Exec) / ✅(Shell) | ❌(Exec) / ✅(Shell) |
| 是否成为 PID 1 | ❌ | ✅ | 取决于是否有 ENTRYPOINT | |
| 是否直接接收 SIGTERM | ❌ | ✅(Exec) | ❌ / ✅(取决于 ENTRYPOINT) | |
| 是否支持优雅停止 | ❌ | ✅(Exec) | 依赖 ENTRYPOINT | |
| 是否可被 docker run 覆盖 | ❌ | ⚠️(需 --entrypoint) |
✅ | |
| docker run 参数行为 | 无意义 | 参数会追加 | 覆盖或作为参数 | |
| 与 ENTRYPOINT 的关系 | 无 | 定义"是什么程序" | 定义"默认参数" | |
| 典型使用次数 | 多次 | 1 次 | 1 次 | |
| 生产环境重要性 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
12.EXPOSE
12.1 指令说明
EXPOSE 用于声明容器在运行时"预期会监听"的端口 。可以理解为一种文档化的端口声明 + 元数据提示,而不是网络规则。
EXPOSE 指令本身只是声明端口,不会真的打开端口,也不会创建防火墙规则、让宿主机能访问、自动映射端口。
12.2 语法格式
默认协议是 tcp
Dockerfile
EXPOSE <port> [<port>/<protocol>...]
12.3 示例
声明端口:
Dockerfile
EXPOSE 80
EXPOSE 80/tcp
EXPOSE 53/udp
EXPOSE 80 443
声明多个端口:
Dockerfile
EXPOSE 80 443 9000
12.4 启动示例
-p 映射启动:
bash
docker run -d -p 80:7000 -p 8080:8080/udp image
-P 启动:
bash
docker run -P image
会自动映射所有 EXPOSE 的端口到宿主机的一个高端口(通常从 32768 开始)
13.VOLUME
13.1 指令说明
VOLUME 用于声明容器中的某个路径是持久化数据目录 。这个目录的数据不应该随着容器销毁而消失。
工作原理:
- Docker 会自动在宿主机上生成一个
随机名字的目录,这个目录被称为"匿名卷"。(默认在 /var/lib/docker/volumes/ 下,可以通过 docker inspect 查看容器元数据找到)。 将这个主机上的随机目录,与容器内部的 VOLUME 目录绑定起来。- 任何写入容器内 VOLUME 目录的文件,实际上都被
保存在了主机上的那个随机目录里。 - 容器被删除后,宿主机上的随机目录及其里面的
数据默认不会被删除。
13.2 语法格式
单路径模式:
Dockerfile
VOLUME ["/data"]
数组模式:
Dockerfile
VOLUME ["/var/lib/mysql", "/var/log/mysql"]
13.3 示例
1. VOLUME 示例
该形式会在宿主机 Docker volume 内部目录 /var/lib/docker/volumes/ 下创建一个随机名称的目录与镜像目录挂载
Dockerfile
VOLUME ["/data"]
2.-v 示例
宿主机指定 volume 目录名称:
该形式会在宿主机 Docker volume 内部目录 /var/lib/docker/volumes/ 下创建一个 mydata 名称的目录与镜像目录挂载
bash
docker run -v mydata:/data image
宿主机指定绝对路径:
该形式会在宿主机指定的绝对路径目录与镜像目录挂载
bash
docker run -v /host/data:/data image
3.--mount type=volume 示例
该形式会在宿主机 Docker volume 内部目录 /var/lib/docker/volumes/ 下创建一个 mydata 名称的目录与镜像目录挂载
bash
docker run --mount type=volume,source=mydata,target=/data image
4.--mount type=bind 示例:
该形式会在宿主机指定的绝对路径目录与镜像目录挂载
bash
docker run --mount type=bind,source=/host/data,target=/data image
13.4 VOLUME、-v、--mount 区别
以下出现的 volume 目录为宿主机Docker目录下,默认:/var/lib/docker/volumes/
| 对比维度 | VOLUME (Dockerfile) | -v | --mount type=volume | --mount type=bind |
|---|---|---|---|---|
| 定义位置 | Dockerfile | docker run / Compose |
docker run / Compose |
docker run / Compose |
| 生效时机 | 容器启动时 | 容器启动时 | 容器启动时 | 容器启动时 |
| 目的 | 声明容器内持久化目录 | 挂载 volume 或宿主机目录 | 明确挂载 volume | 挂载宿主机目录 |
| 是否创建 volume | ✅ 自动匿名 volume | ✅ 可创建 | ✅ 可创建 | ❌(只能挂已有宿主机目录) |
| 容器路径 | ✅ 必须 | ✅ 必须 | ✅ 必须 | ✅ 必须 |
| 宿主机路径 / source | ❌ 无法指定 | ✅ 可指定 | ✅ volume 名称 | ✅ 宿主机目录 |
| 数据实际存储位置 | 宿主机 Docker volume 内部目录 /var/lib/docker/volumes/... |
宿主机 Docker volume 内部目录 /var/lib/docker/volumes/...或宿主机指定目录 |
宿主机 Docker volume 内部目录 /var/lib/docker/volumes/... |
宿主机指定目录 |
| 是否可控 | 低 | 中 | 高 | 高 |
| 是否影响镜像层 | ✅ 切断容器目录与镜像层 | ❌ | ❌ | ❌ |
| 工程实践推荐度 | ⚠️ 官方镜像兜底 | ⚠️ 快捷方案 | ✅ 工程首选 | ✅ 生产挂宿主机首选 |
14.SHELL
14.1 指令说明
SHELL 的作用只有一个:修改后续 Shell Form 指令所使用的"默认 shell"
它影响的是这些以 shell 方式执行的指令格式:
Dockerfile
RUN <string>
CMD <string>
ENTRYPOINT <string>
默认情况下:
- 在 Linux 容器中,默认是
["/bin/sh", "-c"]。 - 在 Windows 容器中,默认是
["cmd", "/S", "/C"]。
例如当执行 RUN echo "Hello World" 时:
- Docker 在 Linux 底层实际上执行的是:
/bin/sh -c "echo \"Hello World\" - Docker 在 Windows 底层实际上执行的是:
cmd /S /C "echo \"Hello World\"
每个 SHELL 指令都会覆盖所有先前的 SHELL 指令,并影响所有后续指令
注意:SHELL 不影响 Exec 形式的指令
14.2 语法格式
Dockerfile
SHELL ["executable", "parameters"]
参数说明:
- executable :要使用的 Shell 程序的完整路径。如
/bin/bash、powershell等。 - parameters :传递给该 Shell 程序的参数。如
-c、 -Command等。
14.3 示例
Bash 常用模式:
Dockerfile
SHELL ["/bin/bash", "-c"]
Bash 严格模式:
Dockerfile
SHELL ["/bin/bash", "-euxo", "pipefail", "-c"]
参数说明:
- -e:出错即失败。
- -u:未定义变量报错。
- -x:打印执行命令。
- pipefail:管道中任意失败即失败。
- -c:后面接需要执行的命令。
Windows 默认(cmd):
Dockerfile
SHELL ["cmd", "/S", "/C"]
参数说明:
- /S :
改变 /C 后面命令字符串的解析规则,防止复杂命令容易被错误拆分或转义失败。 - /C:执行完后面的命令字符串后立即退出。
Windows PowerShell:
Dockerfile
SHELL ["powershell", "-Command"]
PowerShell 严格模式:
Dockerfile
SHELL ["powershell", "-NoProfile", "-Command", "$ErrorActionPreference = 'Stop';"]
参数说明:
- -NoProfile :
启动 PowerShell 时不加载任何用户或系统 Profile 脚本。使Docker 构建要 可重复、可预测。 - -Command:后面的字符串就是要执行的命令。
- $ErrorActionPreference = 'Stop'; :
任何非终止性错误,都会升级为终止性错误,报错立即停止执行。
15.USER
15.1 指令说明
USER 指令用于指定后续 Dockerfile 指令以及容器运行时所使用的用户和用户组 。默认情况下,容器的运行身份为 root 用户。USER指令可以修改后续的 RUN、CMD、 ENTRYPOINT 等指令以哪个用户的权限来执行。
注:可以在一个 Dockerfile 中使用多个 USER 来切换身份
15.2 语法格式
必须在系统 /etc/passwd 文件中定义的用户名/组
用户名/用户组名:
Dockerfile
USER <user>[:<group>]
用户ID/组ID:
Dockerfile
USER UID[:GID]
15.3 示例
创建用户并使用:
Dockerfile
# 创建一个用户组,指定组id为 1001,组名为 appgroup
# 并创建一个系统用户 appuser,指定用户id为 1001,并加入 appgroup 组
RUN groupadd -g 1001 appgroup && useradd -r -u 1001 -g appgroup appuser
WORKDIR /app
# 将宿主机构建上下文中的 app 文件复制到容器内(COPY 后文件一定是 root 拥有的,这是后面要 chown 的原因。)
COPY app.sh /app/app.sh
# 修改 /app 目录的所有权,并赋予 app.sh 可执行权限
RUN chown -R appuser:appgroup /app && chmod +x /app/app.sh
# 切换用户
USER appuser
# 执行 app.sh 文件
CMD ["/app/app.sh"]
切换用户:
Dockerfile
FROM ubuntu:22.04
RUN whoami
RUN useradd -r -u 1001 newuser
USER newuser
RUN whoami
USER root
RUN whoami
16.HEALTHCHECK
16.1 指令说明
HEALTHCHECK指令后定义一个命令,Docker 会周期性执行它,判断容器是否健康。
容器健康状态有三种:
- healthy:健康
- unhealthy:不健康
- starting:刚启动,命令还未判断
16.2 语法格式
检查容器的健康状况:
Dockerfile
HEALTHCHECK [OPTIONS] CMD command
参数说明:
- --interval=DURATION :
两次健康检查命令之间的时间间隔。 (默认: 30s) - --timeout=DURATION :
单次健康检查命令的执行超时时间,如果超时则视为失败。(默认: 30s) - --start-period=DURATION :
容器启动后的宽限期,在这段时间内,即使健康检查失败,也不会标记容器为 unhealthy。 (默认: 0s) - --start-interval=DURATION :这是 Docker 20.10+ 新增参数(
比 --interval 更精细)
用于在启动期覆盖 --interval 的间隔时间(默认: 5s`) - --retries=N :
连续失败多少次,才把容器标记为 unhealthy(默认: 3 次)
禁用从基础镜像继承而来的任何健康检查功能:
用于清理基础镜像继承的 HEALTHCHECK
Dockerfile
HEALTHCHECK NONE
16.3 示例
- 检查成功 → 返回 0 → healthy
- 检查失败 → 执行 exit 1 → 返回非 0 → unhealthy
16.3.1 curl 方式
两次健康检查命令之间的时间间隔:
Dockerfile
HEALTHCHECK --interval=10s CMD curl -f http://localhost:8080/health || exit 1
设置单次检查超时时间:
Dockerfile
HEALTHCHECK --timeout=5s CMD curl -f http://localhost:8080/health || exit 1
容器启动后的宽限期:
Dockerfile
HEALTHCHECK --start-period=20s CMD curl -f http://localhost:8080/health || exit 1
设置启动器时间间隔:
容器启动前 30 秒,每 5 秒执行一次检查;容器启动后每 30 秒执行一次检查
Dockerfile
HEALTHCHECK --start-period=30s --start-interval=5s --interval=30s CMD curl -f http://localhost:8080/health || exit 1
设置连续失败多少次,把容器标记为 unhealthy:
Dockerfile
HEALTHCHECK --retries=5 CMD curl -f http://localhost:8080/health || exit 1
综合示例:
Dockerfile
HEALTHCHECK \
--interval=30s \
--timeout=5s \
--start-period=20s \
--start-interval=5s \
--retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
16.3.2 TCP 端口检查
使用 Netcat 命令尝试是否能够连接,可以的话则为成功
- 优点 :快速、无数据发送,适合
数据库/Redis/MQ等服务的端口探测 - 缺点 :
只能判断端口是否监听,不能判断协议/服务是否真正可用
Dockerfile
HEALTHCHECK CMD nc -z localhost 3306 || exit 1
参数说明:
- nc: Netcat 工具,万能网络工具
- -z: 端口扫描/探测模式,不发送数据,只尝试建立 TCP 连接
16.3.3 命令/进程检查
扫描 /proc 目录,如 Linux 内核维护的 /proc/[pid]/cmdline,pgrep 遍历进程列表,查找匹配 myservice 的进程
Dockerfile
HEALTHCHECK CMD pgrep myservice || exit 1
参数说明:
- pgrep:Process GREP 的缩写,用于在 Linux 系统中 查找正在运行的进程。
- myservice:进程名或部分匹配字符串。
pgrep 常用参数:
| 参数 | 含义 | 示例 |
|---|---|---|
-x |
精确匹配命令名 | pgrep -x nginx |
-u <user> |
只匹配特定用户 | pgrep -u appuser myservice |
-q |
静默模式,只返回状态码 | pgrep -q myservice |
-f |
匹配完整命令行 | pgrep -f "python /app/app.py" |
16.3.4 文件/目录检查
Dockerfile
HEALTHCHECK CMD test -f /app/config.yaml || exit 1
参数说明:
- test:内置 shell 命令,用于检查文件/字符串/数字等条件。
- -f:判断目标是否存在且是普通文件(不是目录、链接、设备等)。
test 扩展用法:
| 参数 | 含义 | 示例 |
|---|---|---|
-f |
判断是否普通文件 | test -f /app/config.yaml |
-d |
判断是否目录 | test -d /app/logs |
-e |
判断文件或目录是否存在 | test -e /app/config.yaml |
-r |
文件是否可读 | test -r /app/config.yaml |
-w |
文件是否可写 | test -w /app/config.yaml |
-x |
文件是否可执行 | test -x /app/app |
16.3.5 自定义脚本(复杂逻辑)
Dockerfile
HEALTHCHECK CMD /app/healthcheck.sh
17.ONBUILD
17.1 指令说明
ONBUILD = 构建触发器 ,它不会在当前镜像构建时执行,而是在基于当前镜像的子镜像构建时触发执行。
- 当前 Dockerfile:定义基础镜像
- ONBUILD:给"使用这个镜像作为父镜像的 Dockerfile"留的指令
- 构建此镜像时(父镜像)不执行。
- 基于父镜像构建子镜像时才执行。
ONBUILD 指令会在子镜像构建时首先执行,但严格来说是"在父镜像的 ONBUILD 队列中按顺序执行,紧接着子镜像自己的第一条指令之前。
17.2 语法格式
Dockerfile
ONBUILD <INSTRUCTION>
<instruction> 可以是 Dockerfile 中的常用指令,例如:COPY、ADD、RUN、ENV 等。(不支持某些特殊指令,如 FROM、ONBUILD 自己)
17.3 示例
17.3.1 构建示例
构建父镜像:
Dockerfile
# 基础镜像
FROM ubuntu:22.04
ONBUILD COPY . /app
ONBUILD RUN echo "Build triggered in child"
构建这个镜像时:
ONBUILD COPY 和 ONBUILD RUN 不会执行镜像构建完成 → 生成一个带有"触发器"的镜像
构建子镜像:
Dockerfile
FROM mybaseimage:latest
构建子镜像时:
- Docker 会自动执行父镜像的 ONBUILD 指令
- COPY . /app → 将子镜像上下文复制到 /app
- RUN echo ... → 执行命令
- 然后执行子镜像自己的 Dockerfile 指令
17.3.2 典型使用场景:
父镜像:
Dockerfile
# python:3.9-slim 的 Dockerfile
ONBUILD COPY requirements.txt /app/
ONBUILD RUN pip install -r /app/requirements.txt
子镜像:
Dockerfile
FROM python:3.9-slim
COPY . /app
18.STOPSIGNAL
18.1 指令说明
当执行 docker stop 时,Docker 发送给容器主进程(PID 1)的 Unix 信号。
注:由于 STOPSIGNAL 是对 PID 1 的主进程有效,所以在 SHELL 格式的命令时 PID 1 是 /bin/sh,如下 myapp 是子进程,STOPSIGNAL 发给 sh,sh 不一定转发信号。从而导致 STOPSIGNAL 失效
Dockerfile
CMD myapp
ENTRYPOINT myapp
| 写法 | PID 1 是谁 | STOPSIGNAL 是否生效 |
|---|---|---|
| ENTRYPOINT Exec | 应用进程 | ✅ |
| CMD Exec | 应用进程 | ✅ |
| ENTRYPOINT Shell | /bin/sh | ❌(通常) |
| CMD Shell | /bin/sh | ❌(通常) |
18.2 语法格式
Dockerfile
STOPSIGNAL signal
支持两种写法:
Dockerfile
# 信号名形式
STOPSIGNAL SIGTERM
# 编号形式
STOPSIGNAL 15
等同于在 docker run 或 docker create 时指定--stop-signal=:
bash
docker run --stop-signal=SIGINT my-image
docker create --stop-signal SIGTERM my-image
常用 Unix 信号表
| 信号名 | 编号 | 含义 | 默认行为 | 常见用途 |
|---|---|---|---|---|
| SIGTERM | 15 | 请求终止 | 终止进程 | Docker 默认 stop 信号 |
| SIGINT | 2 | 中断 | 终止进程 | Ctrl+C、CLI 程序 |
| SIGQUIT | 3 | 退出并生成 core | 终止 + core | Nginx 优雅退出 |
| SIGKILL | 9 | 强制杀死 | 立即终止 | 无法捕获,兜底 |
| SIGHUP | 1 | 挂起/重载 | 终止或重载 | 重新加载配置 |
| SIGUSR1 | 10 | 用户自定义 | 忽略 | 应用自定义控制 |
| SIGUSR2 | 12 | 用户自定义 | 忽略 | 应用自定义控制 |
| SIGPIPE | 13 | 管道破裂 | 终止 | 写入已关闭管道 |
| SIGCHLD | 17 | 子进程退出 | 忽略 | 进程回收 |
| SIGALRM | 14 | 定时器超时 | 终止 | 超时控制 |
18.3 示例
18.3.1 SIGTERM:
请求进程正常退出(可捕获、可处理),docker stop 默认发送
Dockerfile
STOPSIGNAL SIGTERM
ENTRYPOINT ["myapp"]
18.3.2 SIGINT:
CLI 工具、通过命令行直接运行、执行完就退出的程序、运行时占着终端、用户能实时看到输出的程序
Dockerfile
STOPSIGNAL SIGINT
CMD ["ffmpeg", "-i", "a.mp4", "b.mp4"]
Dockerfile
STOPSIGNAL SIGINT
CMD ["node", "server.js"]
Dockerfile
STOPSIGNAL SIGINT
CMD ["python", "server.py"]
18.3.3 SIGQUIT
Nginx 优雅退出:
Dockerfile
STOPSIGNAL SIGQUIT
18.3.4 SIGKILL
立即杀死进程,不要在 Dockerfile 里用 STOPSIGNAL SIGKILL
bash
docker kill mycontainer
18.3.5 SIGHUP
重新加载配置 / 重启逻辑
bash
docker kill -s HUP nginx-container
等价于:
bash
nginx -s reload
用 Bash 模拟配置重载:
bash
#!/bin/sh
reload() {
echo "Reload config at $(date)"
}
trap reload HUP
echo "App started, PID $$"
while true; do
sleep 5
done
Dockerfile
FROM alpine
COPY app.sh /app.sh
RUN chmod +x /app.sh
CMD ["/app.sh"]
bash
docker run -d --name hup-demo hup-image
docker kill -s HUP hup-demo
输出:
Reload config at 2026-01-08 ...
三.docker build 构建命令
1. docker build 介绍
docker build 是 Docker 客户端用于根据 Dockerfile 构建镜像(Image)的命令。
镜像是不可变的只读模板,容器是镜像的运行实例。docker build 只负责生成镜像,不运行任何容器。
2.docker build 的基本语法
2.1 语法格式
bash
docker build [OPTIONS] PATH | URL | -
关键组成部分
| 部分 | 含义 |
|---|---|
| OPTIONS | 构建参数 |
| PATH | PATH 指的是构建上下文路径, 可以是相对路径或绝对路径 |
| URL | Git 仓库或者 HTTP(s) 资源 |
| - | 从 stdin 读取 Dockerfile |
2.2 OPTIONS 可用参数列表
| 参数 | 简述 | 用法 / 示例 | 备注 |
|---|---|---|---|
-t, --tag |
给生成的镜像打标签 | docker build -t myapp:1.0 . |
可指定多个标签,多标签镜像共享同一镜像 ID,如果不指定标签,则会生成一个随机镜像id,而不会有名字 |
-f, --file |
指定 Dockerfile 路径 | docker build -f Dockerfile.prod . |
可以是相对路径或绝对路径(如果不指定,则会在构建上下文的根目录寻找Dockerfile) |
--build-arg |
构建时传入参数 | docker build --build-arg VERSION=1.2.3 . |
仅在 build 阶段有效,不进入最终镜像环境变量 |
--cache-from |
指定缓存来源镜像 | docker build --cache-from myapp:cache . |
用于加速构建,常与 CI/CD 配合 |
--no-cache |
禁用缓存 | docker build --no-cache . |
强制重新执行每一条 Dockerfile 指令 |
--pull |
强制拉取最新基础镜像 | docker build --pull . |
避免使用本地旧镜像 |
--quiet, -q |
静默构建,仅输出镜像 ID | docker build -q . |
CI/CD 常用,减少日志输出 |
--rm |
构建完成后删除中间容器 | 默认 true |
一般不用手动设置,除非调试 |
--force-rm |
即使构建失败也删除中间容器 | docker build --force-rm . |
调试时避免残留垃圾容器 |
--compress |
压缩发送给 daemon 的上下文 | 默认开启 | 对大文件夹有明显效果 |
--isolation |
设置构建隔离方式 | docker build --isolation=process . |
Windows 平台可用,Linux 通常忽略 |
--network |
构建网络模式 | docker build --network=host . |
默认 bridge,复杂网络需求可指定 |
--output, -o |
构建输出到本地目录或其他后端 | docker build -o type=local,dest=./out . |
用于 BuildKit,支持多种输出类型 |
--progress |
控制日志显示方式 | docker build --progress=plain . |
可选 auto/plain/tty |
--secret |
构建时使用 secret | docker build --secret id=mysecret,src=./secret.txt . |
需 BuildKit 支持,用于安全传递密码等 |
--ssh |
构建时使用 SSH agent | docker build --ssh default . |
常用于私有 Git 拉取依赖 |
--platform |
指定目标平台 | docker build --platform linux/amd64 . |
用于跨架构构建,多架构镜像 |
--iidfile |
将构建完成镜像 ID 写入文件 | docker build --iidfile image_id.txt . |
CI/CD 常用 |
--label |
给构建的镜像打标签信息 | docker build --label version=1.0 . |
metadata,不影响镜像 ID |
--build-context |
指定额外构建上下文 | docker build --build-context docs=./docs . |
BuildKit 支持,可引入多个上下文 |
--ulimit |
设置构建时的 ulimit | docker build --ulimit nofile=1024:2048 . |
BuildKit 支持,控制资源限制 |
2.3 URL 参数说明
如执行:
bash
docker build -t myapp:latest https://github.com/user/repo.git
- Docker daemon 下载远程仓库到临时目录:
如果 URL 指定了 branch/tag/commit,则下载指定版本,默认是 HEAD - 仓库下载完成后,这个下载的内容就是
构建上下文。 - Docker daemon 读取 Dockerfile 内容,按
顺序解析每条构建指令(FROM, RUN, COPY, ADD, ENV 等)。
注意:Dockerfile 默认在仓库根目录下找 Dockerfile,如果文件名不是 Dockerfile,必须加 -f 指定。
- 参数说明:
| 用法 | 描述 | 构建上下文 | Dockerfile 来源 | 示例(单元格安全) | 优势 | 限制 / 注意事项 |
|---|---|---|---|---|---|---|
| Here Document | Shell 使用 HereDoc 把 Dockerfile 内容送入 stdin | 默认空 | stdin | docker build -t tempimage - <<EOF FROM alpine RUN echo hello EOF |
无需 Dockerfile 文件,适合临时测试、教学 | 无上下文,不能 COPY 本地文件 |
| 管道 echo | 用 echo 输出 Dockerfile,通过管道传给 docker build | 默认空 | stdin | `echo "FROM alpine\nRUN echo hello" | docker build - -t tempimage` | 最简单、脚本友好 |
| tar 方式传上下文 | 将目录打包为 tar,通过 stdin 传给 Docker | stdin 中的 tar 包 | stdin Dockerfile + 上下文 | `tar -czf - . | docker build - -t myimage` | 可在无 Dockerfile 文件情况下构建完整项目 |
| 动态生成 Dockerfile | 脚本动态生成 Dockerfile 内容 | 视脚本而定 | stdin | `generate.sh | docker build - -t ci-image` | CI/CD 自动化利器 |
| stdin + BuildKit 上下文 | 使用 BuildKit 引入额外构建上下文 | 多上下文 | stdin | docker build --build-context src=./src - < Dockerfile |
解决 stdin 无上下文问题 | 依赖 BuildKit,复杂度高 |
2.4 dockerignore 文件
.dockerignore 是位于构建上下文根目录的配置文件 ,用于在构建开始之前过滤构建上下文中不需要发送给 Docker daemon 的文件和目录。防止一些大文件或者没有的文件创建到镜像中。
如:
conf
.git
.gitignore
node_modules
target
dist
*.log
3.示例
3.1 镜像标签
bash
docker build -t repo/name:tag .
多标签:
bash
docker build -t app:1.0 -t app:latest .
3.2 指定 DOckerfile
不指定标签
bash
docker build -f Dockerfile.prod .
3.3 传入构建参数
给 Dockerfile 中的 ARG 传参
bash
docker build --build-arg VERSION=1.2.3 .
3.4 禁用缓存
bash
docker build --no-cache .
3.5 平台指定
bash
docker build --platform linux/amd64 .
3.6 本地文件路径
bash
docker build -t myapp:1.0 .
docker build -t myapp:1.0 ./docker
docker build -t myapp:1.0 /home/user/project
- Dockerfile:默认在 PATH 根目录下找 Dockerfile。
- COPY / ADD :
只能访问上下文里的文件,不能访问 PATH 以外的文件。 - 性能注意 :
不要把不必要的大文件夹放入上下文,否则每次 build 都要上传,耗时很长。 - 解决方案 :
使用 .dockerignore 忽略不需要的文件。
3.7 Git 仓库或者 HTTP(s) 资源
bash
docker build -t myapp:latest https://github.com/user/repo.git
docker build -t myapp:latest https://github.com/user/repo.git#branch-name
docker build -t myapp:latest https://github.com/user/repo.git#commit-hash
3.8 从标准输入读取 Dockerfile
动态生成 Dockerfile:
CI/CD 脚本生成 Dockerfile 内容,然后直接构建,不用在磁盘上写文件
bash
echo -e "FROM alpine\nRUN echo hello" | docker build - -t myimage
临时构建:
bash
# <<EOF 表示 把后续直到 EOF 的内容当作标准输入
docker build -t tempimage - <<EOF
FROM busybox
RUN echo hello
EOF

四.docker 部署 springboot 示例
1.docker 下拉 java 镜像
bash
docker pull williamyeh/java8
该镜像不必启动
2.编写 Dockerfile 文件
Dockerfile
#指定基础镜像,本地没有会从dockerHub pul1下来
FROM williamyeh/java8
#把可执行jar包复制到基础镜像的根目录下
ADD api-test.jar /api-test.jar
#镜像要暴露的端口,如要使用端口,在执行docker run命令时使用-p生效
EXPOSE 8087
#在镜像运行为容器后执行的命令
ENTRYPOINT ["java","-jar","/api-test.jar"]
3.打包 jar 为镜像
上传 jar 包到服务器 Dockerfile 文件同目录下
bash
docker build -f Dokcerfile -t why/api-test:v1.0 .
参数说明:
- -f: 指定Dockerfile文件的路径
- -t: 指定镜像名字和TAG
- .: 指当前目录,这里实际上需要一个上下文路径
4.启动 api-test 镜像
bash
docker run -d --name api-test -p 8087:8087 why/api-test:v1.0
我们可以在一台机器上, 部署多个该微服务, 内部同一个端口, 宿主机多个端口, 以此用来负载均衡
bash
docker run -d --name api-test2 -p 8088:8087 why/api-test:v1.0
docker run -d --name api-test3 -p 8089:8087 why/api-test:v1.0