1. 概述

Docker 的 build 命令在构建镜像时,默认限制了我们只能使用构建上下文(build context)中的文件。也就是说,Dockerfile 及其依赖的所有文件都必须位于指定的上下文中。

但在实际开发中,有时我们希望使用一个目录下的 Dockerfile,同时引用另一个目录中的文件。例如:

  • 根据不同环境使用不同的 Docker 或 docker-compose 文件
  • 将容器相关配置与项目源码分离

本文将介绍几种绕过该限制的方法,并分析它们的优缺点。


2. Docker 构建及其上下文

2.1. 常规构建方式

假设我们有一个简单的 Nginx 项目,结构如下:

projects
├── sample-site
│   ├── html
│   │   └── index.html
│   └── Dockerfile

Dockerfile 内容如下:

FROM nginx:latest
COPY html/* /etc/nginx/html/

执行构建命令:

$ docker build -t sample-site:latest .

这里 . 表示当前目录为构建上下文,Docker 会从该目录下查找所有文件。

2.2. 复杂构建场景

当项目结构变得更复杂时,比如:

  • Dockerfile 放在 docker/ 目录中
  • 配置文件 nginx.conf 存放在 config/ 目录中,不在项目根目录下

结构如下:

projects
├── sample-site
│   ├── html
│   │   └── index.html
│   └── docker
│       └── Dockerfile
└── config
    └── nginx.conf

此时,如果我们仍然使用默认方式构建,Docker 将无法找到 config/nginx.conf 文件。


3. 扩展构建上下文

3.1. 修改 Dockerfile

我们可以将构建上下文设为 projects 目录,这样就能访问到 sample-siteconfig 中的文件。相应的 Dockerfile 应该调整路径:

FROM nginx:latest
COPY sample-site/html/* /etc/nginx/html/
COPY config/nginx.conf /etc/nginx/nginx.conf

3.2. 执行构建命令

进入 projects 目录执行:

$ cd projects
$ docker build -f sample-site/docker/Dockerfile -t sample-site:latest .

优点:实现简单,无需额外脚本
缺点:上下文过大,构建效率低,Docker 会复制整个目录,可能包含大量无关文件


4. 使用基础镜像包含外部文件

4.1. 构建基础镜像

我们先创建一个基础镜像,包含 config/nginx.conf

FROM nginx:latest
COPY nginx.conf /etc/nginx/nginx.conf

projects/config 下执行:

$ docker build -t sample-site-base:latest .

4.2. 构建子镜像

接着,编写 sample-site/docker/Dockerfile

FROM sample-site-base:latest
COPY html/* /etc/nginx/html/

然后在 projects/sample-site 下执行:

$ docker build -f docker/Dockerfile -t sample-site:latest .

优点:结构清晰,适合多环境复用
缺点:增加了镜像层数,构建过程变复杂,需注意基础镜像更新后子镜像需要重新构建


5. 构建临时上下文

5.1. 创建临时目录

创建一个临时目录,将所需文件复制进去:

$ mkdir tmp-context
$ cp -R ../sample-site/html tmp-context/
$ cp -R ../../config tmp-context/

5.2. 编写 Dockerfile

tmp-context 下创建 Dockerfile

FROM nginx:latest
COPY html/* /etc/nginx/html/
COPY config/nginx.conf /etc/nginx/nginx.conf

5.3. 执行构建

$ cd tmp-context
$ docker build -t sample-site:latest .

5.4. 清理临时目录

$ rm -rf tmp-context

优点:灵活可控,上下文最小
缺点:每次构建都要复制文件,效率可能较低,适合脚本自动化处理


6. 总结

本文介绍了三种绕过 Docker 构建上下文限制的方法:

方法 优点 缺点
扩展构建上下文 实现简单 上下文大,效率低
使用基础镜像 结构清晰,可复用 增加镜像层数,维护复杂
创建临时上下文 灵活可控,上下文小 需要手动复制,适合脚本处理

选择哪种方式,取决于你的项目结构和构建需求。如果只是偶尔构建,使用临时上下文可能是最干净的方式;如果需要多环境复用,基础镜像是更好的选择。

完整示例代码可在 GitHub 仓库 中找到。


原始标题:How to Include Files Outside of Docker’s Build Context