在 Dockerfile 中,COPYADD 都是用来将文件从主机复制到 Docker 镜像中的指令。它们有些相似,但在功能上有一些关键的区别。

单阶段构建

1. 基本区别

  • COPY:简单地将文件或目录从主机系统复制到容器的指定路径,不做任何额外的处理。

  • ADD:除了执行与 COPY 相同的操作外,还能处理一些额外的功能:

    • 支持从 URL 下载文件并复制到容器中。
    • 支持自动解压 .tar 格式的压缩包(如 .tar.gz.tar.bz2 等)。

2. 理解与逻辑

  • COPY 用于最基础的文件拷贝操作,语法简单,行为明确,通常在我们不需要额外处理(如解压文件或从远程服务器下载文件)的情况下使用。

  • ADD 提供了更多的功能(如下载和解压),但由于其具有自动处理压缩文件的功能,有时会增加不必要的复杂性。比如,如果我们不需要解压 .tar 文件,使用 ADD 可能会带来一些不期望的行为。因此,推荐使用 COPY,只有在需要解压文件或从网络下载时,才使用 ADD

3. 使用场景对比

特性 COPY ADD
基本功能 将文件从主机复制到镜像中 将文件从主机复制到镜像中
支持解压 不支持解压文件 支持自动解压 .tar 文件
支持 URL 只支持本地路径 支持从 URL 下载文件并复制
推荐使用场景 仅复制文件或目录,没有额外需求 需要解压 .tar 文件或从 URL 下载文件
语法 COPY <src> <dest> ADD <src> <dest>

4. 举例说明

示例 1:使用 COPY 复制文件
COPY ./myfile.txt /app/myfile.txt

这将把主机上的 myfile.txt 文件复制到容器中的 /app/ 目录。

示例 2:使用 ADD 复制文件并解压
ADD ./myarchive.tar.gz /app/

这将把 myarchive.tar.gz 文件复制到 /app/ 目录,并自动解压它。假如 myarchive.tar.gz 中包含多个文件,ADD 会自动将这些文件解压到 /app/ 目录中。

示例 3:使用 ADD 从 URL 下载文件
ADD http://example.com/file.tar.gz /app/

这将从 http://example.com/file.tar.gz 下载文件,并将其复制到 /app/ 目录中,同时也会解压文件。

总结:

  • COPY 是最基础的文件复制操作,语义明确,推荐用于文件复制。
  • ADD 除了复制文件外,支持自动解压和从 URL 下载,但增加了不必要的复杂性,除非有解压或下载需求,否则优先使用 COPY

多阶段构建

多阶段构建(multi-stage builds) 中,COPY 可以从一个阶段复制文件到另一个阶段。

如何使用 COPY 在不同阶段之间传递文件

在多阶段构建中,COPY 可以通过指定源镜像的名称来从一个构建阶段复制文件到另一个阶段。

语法

COPY --from=<stage_name_or_index> <src_path> <dest_path>
  • --from=<stage_name_or_index>:指定从哪个构建阶段复制文件。如果是第一个阶段,可以使用 0,如果是多个阶段中的其他阶段,可以使用阶段的名称或索引。
  • <src_path>:源路径,表示要复制的文件或目录。
  • <dest_path>:目标路径,表示复制到容器中的位置。

示例:多阶段构建中的 COPY 使用

假设你有一个 Node.js 项目,首先需要编译和构建文件,然后在最终的镜像中仅包含构建后的产物(比如构建出来的静态文件或编译后的代码)。

# 第一阶段:构建阶段
FROM node:16 AS builder
WORKDIR /app
COPY . .
RUN npm install && npm run build

# 第二阶段:最终镜像
FROM nginx:alpine 
# 从构建阶段复制编译好的静态文件到 Nginx 服务器的默认目录

COPY --from=builder /app/build /usr/share/nginx/html 

# 暴露端口

EXPOSE 80 

解释

  • 在第一阶段,我们使用 node:16 镜像构建项目,执行 npm installnpm run build

  • 在第二阶段,我们使用 nginx:alpine 镜像来部署构建后的静态文件。通过 COPY --from=builder /app/build /usr/share/nginx/html,我们从名为 builder 的第一阶段中复制 /app/build 目录到 Nginx 的默认静态文件目录 /usr/share/nginx/html

为什么使用多阶段构建?

  • 减小镜像大小:你可以只将构建过程中需要的文件复制到最终镜像中,避免将临时的构建工具和中间文件包含在内,从而减小最终镜像的体积。

  • 清晰的分层管理:将不同的构建步骤分开,可以更清晰地管理每个构建步骤的依赖。

dockerfile演示

FROM quay.io/0voice/node:18.16.0 as stage0
RUN npm config set registry https://mirrors.huaweicloud.com/repository/npm/
COPY ./user-web /src/user-web
WORKDIR /src/user-web
RUN npm install
RUN npm run build

FROM quay.io/0voice/golang:1.20 as stage1
RUN go env -w GOPROXY=https://goproxy.cn,https://proxy.golang.com.cn,direct
ADD ./user /src/user
WORKDIR /src/user
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o user .

FROM quay.io/0voice/alpine:3.18 as stage2
ADD ./curl-amd64 /usr/bin/curl
RUN chmod +x /usr/bin/curl
WORKDIR /app
ADD ./user/dev.config.yaml /app/config.yaml
COPY --from=stage0 /src/user-web/dist /app/www
COPY --from=stage1 /src/user/user /app
ENTRYPOINT ["./user"]
CMD ["--config=config.yaml"]


https://github.com/0voice

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐