1. 理解 Docker Build 上下文
Docker build 上下文(Build Context)是指执行 docker build
命令时,Docker CLI 会将当前目录(或指定路径)下的所有文件和子目录打包发送给 Docker Daemon 的过程。
这个上下文的作用是:Dockerfile 中所有 COPY
、ADD
等操作都只能访问上下文范围内的文件。也就是说,Dockerfile 所在目录之外的文件是无法被访问的,除非你显式地将其包含在构建上下文中。
✅ 构建上下文的常见来源:
- 本地文件系统路径(如
.
表示当前目录) - Git 仓库地址(如
https://github.com/xxx.git
)
⚠️ 踩坑点:
如果你的构建目录中存在不必要的大文件(如日志、备份、压缩包等),它们都会被包含进构建上下文,导致构建过程变慢,甚至失败。
2. 构建上下文带来的问题
我们来看一个简单的 Dockerfile 示例:
FROM centos:7
MAINTAINER [email protected]
COPY jdk-8u202-linux-x64.rpm /
执行构建命令:
docker build -t javaapplication .
输出如下:
Sending build context to Docker daemon 178.4MB
...
Successfully built 9c58f775bb80
现在,我们在当前目录下新增一个 186MB 的 jdk-8u202-linux-x64.tar.gz
文件,不修改 Dockerfile,再次构建:
Sending build context to Docker daemon 372.5MB
...
Successfully built 9c58f775bb80
✅ 问题总结:
- 构建上下文自动包含了当前目录下的所有内容,包括未被使用的文件。
- 这会导致构建上下文体积膨胀,浪费带宽、内存和时间。
3. 使用 .dockerignore 文件优化上下文
.dockerignore
文件的作用类似于 .gitignore
,用于指定哪些文件或目录不应被包含在构建上下文中。
✅ 示例:
创建 .dockerignore
文件,排除 tar.gz
文件:
echo "jdk-8u202-linux-x64.tar.gz" > .dockerignore
再次执行构建:
Sending build context to Docker daemon 178.4MB
✅ 效果:
- 构建上下文大小恢复到原来的 178.4MB。
- 有效避免了不必要的文件传输。
4. 使用 EOF 构建无上下文镜像
如果你的 Dockerfile 不涉及 COPY
或 ADD
操作,可以使用以下方式构建镜像,完全避免构建上下文:
docker build -t test -<<EOF
FROM centos:7
MAINTAINER admin@example.com
RUN echo "Welcome to Bealdung"
EOF
输出如下:
Sending build context to Docker daemon 2.048kB
✅ 适用场景:
- Dockerfile 中没有使用本地文件(如 COPY、ADD)。
- 快速测试或构建简单镜像。
⚠️ 注意:
- 一旦使用了
COPY
或ADD
,这种方式就不再适用。
5. Docker 镜像优化技巧
5.1 使用多阶段构建(Multi-Stage Builds)
多阶段构建允许你在同一个 Dockerfile 中使用多个 FROM
指令,每个阶段可以使用不同的基础镜像。最终镜像中只保留你需要的文件。
✅ 示例:
FROM centos:7 as builder
RUN yum -y install maven
COPY spring-boot-application /spring-boot-application
WORKDIR /spring-boot-application/
RUN mvn clean package -Dmaven.test.skip=true
FROM centos:7
RUN yum install -y epel-release \
&& yum install -y maven wget \
&& yum -y install java-1.8.0-openjdk \
&& yum clean all
COPY --from=builder /spring-boot-application/target/spring-boot-application-0.0.1-SNAPSHOT.jar /
CMD ["java -jar ","-c","/spring-boot-application-0.0.1-SNAPSHOT.jar && tail -f /dev/null"]
✅ 优势:
- 构建环境与运行环境分离。
- 镜像体积大幅减小。
5.2 合并 RUN 指令减少图层
每条 RUN
指令都会创建一个新的图层(Layer),图层数量越多,镜像体积越大。
❌ 不推荐写法:
RUN apt-get update
RUN apt-get install -y python
✅ 推荐写法:
RUN apt-get update && apt-get install -y python
✅ 效果:
- 图层数量减少。
- 镜像体积更小。
- 更易于维护。
5.3 自定义基础镜像
如果你有多个服务使用了相同的依赖项,建议:
- 创建一个自定义的基础镜像,预装通用依赖。
- 利用 Docker 的缓存机制,提升构建效率。
✅ 优势:
- 减少重复构建。
- 提高构建速度。
- 统一依赖版本。
6. 总结
优化方式 | 说明 | 适用场景 |
---|---|---|
.dockerignore |
排除不必要的文件 | 所有项目 |
EOF 构建 | 无需上下文,构建最小镜像 | 简单镜像 |
多阶段构建 | 分离构建和运行阶段 | Java、Go 等编译型项目 |
合并 RUN 指令 | 减少图层数量 | 所有 Dockerfile |
自定义基础镜像 | 提前安装通用依赖 | 多服务共享依赖 |
✅ 建议:
- 从构建上下文开始优化,再结合 Dockerfile 优化技巧。
- 对于大型项目,推荐使用多阶段构建 + 自定义基础镜像组合方案。
⚠️ 避免踩坑:
- 不要忽视
.dockerignore
文件。 - 不要频繁使用
RUN
指令。 - 不要将大文件随意放在构建目录中。