多阶段构建

Docker多阶段构建的好处

使用Docker多阶段构建有以下几个好处:

  • 减小镜像大小:每个构建阶段只包含必要的依赖项和文件,从而减小了生成的镜像大小。这可以减少镜像的存储空间和传输时间。
  • 提高构建速度:每个构建阶段可以并行执行,因此可以提高构建速度。而且,每个构建阶段只构建所需的内容,从而减少了构建时间。
  • 简化Dockerfile:使用多个构建阶段可以将Dockerfile分解为更小的部分,从而使Dockerfile更加易于管理和维护。每个构建阶段都可以专注于特定的任务,而不必关注整个构建过程。
  • 提高安全性:使用多个构建阶段可以限制敏感信息的泄露。例如,在第一个构建阶段中,可以包含敏感信息,例如私有密钥或密码。而在第二个构建阶段中,可以只包含必要的文件和依赖项。

单独执行rm并不会精简镜像体积

尽管在 Dockerfile 中使用 RUN rm -rf /tmp/* 删除了大量文件,但你可能会发现最终生成的 Docker 镜像的大小并没有显著变化。这是因为每个 Dockerfile 指令都会创建一个新的镜像层,而删除文件的操作并不会减少已有层的大小。 删除的文件其实仍然存在于之前的层中,导致镜像整体大小没有减少。

要优化镜像大小,你可以考虑以下几个方法:

合并命令以减少镜像层数。将相关的运行命令合并到一个 RUN 指令中,以减少镜像层数。例如,你可以将安装软件包和删除缓存文件的操作合并到一个 RUN 指令中:

1
2
3
4
5
6
FROM ubuntu:latest

# 更新包列表、安装软件包并删除缓存文件
RUN apt-get update && apt-get install -y \
curl vim \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

通过这种方式,删除操作和安装操作在同一个层完成,避免了无用文件占用空间。

多阶段构建精简镜像体积

多阶段构建是一种优化 Docker 镜像大小的方法,可以在构建过程中使用临时构建环境,并在最终镜像中只保留必要的部分。COPY –from复制之前镜像中执行的必要的结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 第一阶段:构建环境
FROM node:14 AS builder

# 在构建环境中执行构建操作
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
RUN npm run build

# 第二阶段:最终镜像
FROM nginx:alpine

# 仅复制构建产物,并删除临时文件夹
COPY --from=builder /app/dist /usr/share/nginx/html

# 删除不必要的目录
RUN rm -rf /usr/share/nginx/html/temp

# 定义容器启动时运行的命令
CMD ["nginx", "-g", "daemon off;"]

目录挂载精简镜像体积

在 Docker 构建过程中,通常是基于本地文件的路径进行操作的,但有时候可能需要从另一个镜像中获取文件。在 Docker 18.09 版本引入了 BuildKit 功能,其中一个特性是支持在 docker build 中使用挂载点(mounts)来访问其他镜像的文件。

以下是具体的方法和示例:

使用 BuildKit 进行挂载

  • –mount=type=bind 和 –mount=type=cache 是 BuildKit 支持的特性,其中 type=bind 可以用来挂载本地文件系统中的文件,而 type=cache 则常用于缓存构建依赖。但是要访问另一个镜像的文件,通常使用 –mount=type=bind 结合 COPY –from 的多阶段构建来实现。

启用 BuildKit
首先确保 Docker Daemon 启用了 BuildKit。可以在环境变量中设置 DOCKER_BUILDKIT=1:

1
export DOCKER_BUILDKIT=1

或者在 Docker 运行时添加 –build-arg BUILDKIT_INLINE_CACHE=1 选项:

1
DOCKER_BUILDKIT=1 docker build .

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Dockerfile 示例:使用 npm 缓存

# 基础镜像
FROM node:14-alpine AS builder

WORKDIR /app

# 挂载缓存目录并安装依赖
RUN --mount=type=cache,target=/root/.npm \
npm install

# 添加应用程序源代码
COPY . .

# 构建应用程序
RUN npm run build

# 使用最小化的基础镜像
FROM nginx:alpine

# 复制构建产物到最终镜像
COPY --from=builder /app/build /usr/share/nginx/html