【docker】Dockerfile中COPY和ADD的区别理解,多阶段构建中COPY的用法
在 Dockerfile 中,COPY
和 ADD
都是用来将文件从主机复制到 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 install
和npm 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