1. 概述

在需要将容器资源与宿主机进行绑定时,我们会使用 Docker 卷。我们可以使用命名卷(named volumes)或绑定挂载(bind mounts),也可以选择本地或远程资源,持久化与否均可。

但在实际挂载过程中,我们可能会希望排除一些不必要的文件或文件夹。比如日志文件、临时文件、node_modules 等。

本文将通过 Docker Compose 示例,演示如何在挂载卷时排除某些子目录或文件。


2. 构建一个 Node.js Docker 镜像

在介绍如何排除文件之前,我们先来简单构建一个 Node.js 的 Docker 镜像作为示例。

通常,构建镜像时我们会将本地代码复制到容器中。以下是一个基础的 Dockerfile 示例:

FROM node:12.18.1
ENV NODE_ENV=production

WORKDIR /app

COPY ["package.json", "package-lock.json*", "./"]

RUN npm install --production

COPY . .

CMD [ "node", "server.js" ]

使用如下命令构建镜像:

$ docker build -t node-docker .

该命令会将当前目录下的所有内容作为上下文发送给 Docker 服务,用于构建镜像。构建完成后,我们可以使用 docker history 查看镜像的构建层:

$ docker history --format "ID-> {{.ID}} | Created-> {{.CreatedSince}} | Created By-> {{.CreatedBy}} | Size: {{.Size}}" e870a50eed97

输出类似如下内容:

ID-> e870a50eed97 | Created-> 36 hours ago | Created By-> /bin/sh -c #(nop)  CMD ["node" "server.js"] | Size: 0B
ID-> 708a43cd0ef2 | Created-> 36 hours ago | Created By-> /bin/sh -c #(nop) COPY dir:7cc2842dd32649457… | Size: 11.3MB
ID-> d49b84f48e41 | Created-> 36 hours ago | Created By-> /bin/sh -c npm install --production | Size: 14.7MB
ID-> a351be0717a1 | Created-> 36 hours ago | Created By-> /bin/sh -c #(nop) COPY multi:9959dc16241ba60… | Size: 80.7kB
ID-> 56b22d35f315 | Created-> 36 hours ago | Created By-> /bin/sh -c #(nop) WORKDIR /app | Size: 0B
ID-> c28b64493ce8 | Created-> 36 hours ago | Created By-> /bin/sh -c #(nop)  ENV NODE_ENV=production | Size: 0B
ID-> f5be1883c8e0 | Created-> 2 years ago | Created By-> /bin/sh -c #(nop)  CMD ["node"] | Size: 0B

3. 构建镜像时排除文件和目录

假设我们项目中有一些敏感文件(如 secret.txt)或大文件(如日志、压缩包),不希望它们被包含在镜像中。此时,我们可以使用 .dockerignore 文件来排除这些资源。

它的工作方式与 .gitignore 类似。例如,创建一个 secret.txt 文件:

$ echo 'password' >secret.txt

然后在 .dockerignore 中添加:

# 排除密码文件
secret.txt

也可以排除整个目录:

# 排除日志目录
logs/

这样构建的镜像就不会包含这些文件。使用如下命令启动容器验证:

$ docker run -d --publish 8000:8000 node-docker

或者使用 Docker Compose:

services:
  node-app:
    image: node-docker:latest
    ports:
      - 8080:8080

进入容器后,使用 ls 检查,你会发现 secret.txt 并不存在。


4. 使用卷挂载时排除文件或目录

除了构建镜像时排除资源,我们还可以在容器运行时通过卷挂载的方式排除某些文件或目录。

4.1 排除单个文件

假设我们不希望容器中某个文件影响宿主机,可以使用 /dev/null 进行绑定:

services:
  node-app:
    build: .
    ports:
      - 8080:8080
    volumes:
      - .:/app/
      - /dev/null:/app/secret.txt

这样,容器中的 secret.txt 就是一个空文件,不会影响宿主机。

4.2 排除目录

更常见的是我们希望排除某个子目录,比如 node_modules。可以通过挂载匿名卷或命名卷来实现:

services:
  node-app:
    build: .
    ports:
      - 8080:8080
    volumes:
      - .:/app
      - /app/node_modules/

注意顺序:先挂载整个项目目录,再单独挂载要排除的子目录。

如果希望保留命名卷,可以这样写:

services:
  node-app:
    build: .
    ports:
      - 8080:8080
    volumes:
      - .:/app
      - my-vol:/app/node_modules/

volumes:
  my-vol:
    driver: local

这样,容器中 node_modules 目录的修改不会同步到宿主机。


5. 总结

本文介绍了在使用 Docker 构建镜像和运行容器时,如何排除不需要的文件或目录:

  • 使用 .dockerignore 排除构建上下文中的资源
  • 使用 /dev/null 排除特定文件
  • 使用匿名或命名卷排除子目录(如 node_modules

这些方法可以帮助我们优化镜像体积、保护敏感信息、避免误操作影响宿主机。

完整代码示例请参考 GitHub 仓库


原始标题:Exclude a Sub-Folder When Adding a Volume to Docker