当前位置: 首页 > article >正文

Docker 多阶段构建:优化镜像大小

在 Docker 中,构建镜像时,我们通常会将应用及其所有依赖打包到镜像中。然而,随着时间的推移,镜像的大小会随着依赖项和构建工具的增加而变得越来越大,这不仅增加了存储成本,还会降低容器启动速度。多阶段构建(Multi-stage Builds) 是一种优化 Docker 镜像大小的技术,它通过分阶段的方式来创建镜像,避免了不必要的构建工具和依赖项进入最终镜像。

本文将深入探讨 Docker 多阶段构建 的概念、用法以及如何优化镜像大小。


1. 什么是 Docker 多阶段构建?

1.1 多阶段构建的基本概念

Docker 多阶段构建 是一种在 Dockerfile 中使用多个 FROM 指令的构建方式。每个 FROM 指令都定义了一个新的构建阶段,前一个阶段的输出可以传递给下一个阶段。这样,我们可以在不同的阶段中使用不同的基础镜像和依赖,最终将构建和运行环境分开,确保最终镜像中只包含必要的文件和依赖。

多阶段构建的流程
  1. 阶段 1:使用包含所有构建工具和依赖的镜像(例如:node:alpinemaven)进行应用的构建。
  2. 阶段 2:从前一个阶段复制构建结果,只包含应用程序和运行时依赖,使用更小的基础镜像(例如:nginx:alpineopenjdk:alpine)构建最终镜像。

通过这种方式,最终镜像只包含运行应用所需的文件,而不会包含构建过程中不必要的依赖和工具,显著减少镜像的大小。


2. 为什么使用多阶段构建?

2.1 优化镜像大小

多阶段构建的最大优点就是 减小镜像大小。在传统的单阶段构建中,构建工具(如编译器、测试工具等)通常会被打包到最终的镜像中。而多阶段构建则将构建过程与运行时环境隔离开,避免将不必要的构建工具包含在最终镜像中。

2.2 提高构建效率

通过将构建和运行环境分离,构建过程可以更为高效,并且可以根据需求选择合适的基础镜像。

2.3 更好的安全性

在多阶段构建中,最终的镜像仅包含应用和运行时所需的最小环境,从而减少了攻击面,提升了镜像的安全性。


3. 多阶段构建示例

3.1 构建一个 Java 应用的多阶段构建

假设我们有一个简单的 Java 项目,使用 Maven 进行构建,并最终生成一个 JAR 文件。我们可以通过多阶段构建,先在一个包含 Maven 的镜像中构建应用,然后在一个轻量级的镜像中运行应用。

示例 Dockerfile(多阶段构建)
# 阶段 1:构建阶段
FROM maven:3.8.1-openjdk-11-slim AS build

# 设置工作目录
WORKDIR /app

# 将本地代码复制到容器中
COPY . .

# 使用 Maven 构建应用
RUN mvn clean package -DskipTests

# 阶段 2:运行阶段
FROM openjdk:11-jre-slim

# 设置工作目录
WORKDIR /app

# 从构建阶段复制构建好的 JAR 文件
COPY --from=build /app/target/my-app.jar /app/my-app.jar

# 运行应用
CMD ["java", "-jar", "/app/my-app.jar"]
解析
  1. 构建阶段

    • 使用 maven:3.8.1-openjdk-11-slim 镜像,它包含了 Maven 和 JDK,用于构建应用。
    • 将项目的源代码复制到 /app 目录,并通过 mvn clean package 命令构建应用。
  2. 运行阶段

    • 使用更小的 openjdk:11-jre-slim 镜像,它只包含 Java 运行时环境(JRE),适合生产环境运行应用。
    • 从构建阶段复制生成的 JAR 文件到运行阶段的 /app 目录。
    • 使用 java -jar 启动应用。

3.2 构建一个 Node.js 应用的多阶段构建

假设你有一个 Node.js 应用,并希望通过 Docker 构建和运行它。在多阶段构建中,我们可以先在一个包含 Node.js 的镜像中进行应用的构建和依赖安装,然后将构建的产物传递到一个轻量级的镜像中运行。

示例 Dockerfile(Node.js 应用)
# 阶段 1:构建阶段
FROM node:16 AS build

# 设置工作目录
WORKDIR /app

# 复制 package.json 和 package-lock.json
COPY package*.json ./

# 安装应用依赖
RUN npm install

# 复制其他源代码
COPY . .

# 构建生产版本
RUN npm run build

# 阶段 2:运行阶段
FROM nginx:alpine

# 从构建阶段复制静态文件到 Nginx 的文件夹
COPY --from=build /app/dist /usr/share/nginx/html

# 暴露 80 端口
EXPOSE 80

# 启动 Nginx
CMD ["nginx", "-g", "daemon off;"]
解析
  1. 构建阶段

    • 使用包含 Node.js 的镜像 node:16 来构建应用。
    • 复制 package.jsonpackage-lock.json 文件,执行 npm install 安装依赖。
    • 复制项目的源代码并执行 npm run build 来构建生产版本。
  2. 运行阶段

    • 使用更小的 nginx:alpine 镜像,只包含 Nginx 服务器。
    • 从构建阶段复制生成的静态文件到 Nginx 的文件夹中。
    • 使用 Nginx 提供服务,暴露 80 端口。

4. Docker 多阶段构建优化技巧

4.1 减少构建镜像的层数

每个 RUNCOPY 等指令都会生成一个新的镜像层。为了减少镜像的大小,可以将多个命令合并为一个 RUN 指令,减少镜像的层数。

RUN apt-get update && \
    apt-get install -y python3 python3-pip && \
    rm -rf /var/lib/apt/lists/*

4.2 使用小型基础镜像

选择合适的基础镜像可以减少构建后的镜像体积。例如,使用 alpine 镜像,它比传统的 Ubuntu 镜像要小得多:

FROM node:16-alpine

4.3 清理临时文件

在构建过程中,许多临时文件(如安装包缓存)可能会增加镜像的体积。在构建镜像时,应清理这些不必要的文件。

RUN apt-get update && \
    apt-get install -y python3 python3-pip && \
    rm -rf /var/lib/apt/lists/*  # 清理 APT 缓存

4.4 只复制需要的文件

避免将不必要的文件(如测试文件、日志文件、编译工具等)复制到镜像中。可以使用 .dockerignore 文件来排除不需要的文件。

.dockerignore 示例

node_modules
*.log
.git

5. 总结

5.1 多阶段构建的优点

  • 减少镜像体积:多阶段构建只将运行时必需的文件复制到最终镜像,避免了不必要的构建工具和依赖。
  • 提高安全性:最终镜像只包含必要的运行环境,减少了潜在的安全漏洞。
  • 优化构建效率:分阶段构建可以选择合适的基础镜像,使得每个阶段只包含必要的内容,提升构建效率。

5.2 多阶段构建的最佳实践

  • 合并多个 RUN 指令,减少镜像层数。
  • 使用轻量级的基础镜像(如 alpine)。
  • 清理构建过程中的临时文件和缓存。
  • 使用 .dockerignore 排除不必要的文件。
  • 只将生产环境必需的文件复制到最终镜像中。

通过掌握 多阶段构建 技术,你可以创建更加精简、安全和高效的 Docker 镜像,提升容器

化应用的部署和运行效率! 🚀


http://www.kler.cn/a/552816.html

相关文章:

  • C#_子窗体嵌入父窗体
  • YOLOv11-ultralytics-8.3.67部分代码阅读笔记-annotator.py
  • 【第3章:卷积神经网络(CNN)——3.7 数据增强与正则化技术】
  • go 树形结构转为数组
  • win11 labelme 汉化菜单
  • matlab质子磁力仪传感器线圈参数绘图
  • 确保设备始终处于最佳运行状态,延长设备的使用寿命,保障系统的稳定运行的智慧地产开源了
  • Effective C++读书笔记——item52(如果编写了 placement new,就要编写 placement delete)
  • Spring Security,servlet filter,和白名单之间的关系
  • 【前端ES】ECMAScript 2023 (ES14) 引入了多个新特性,简单介绍几个不为人知但却好用的方法
  • 【Python爬虫(14)】解锁Selenium:Python爬虫的得力助手
  • npm、yarn、pnpm 的异同及为何推荐 pnpm
  • DeepSeek AI 完全使用指南:从入门到精通
  • Node.js 版本与 npm 的关系及版本特性解析:从开源项目看演进
  • 腿足机器人之九- SLAM基础
  • 跳板机和堡垒机的区别
  • HDFS应用-后端存储cephfs-java-API
  • 论文阅读 DOES END-TO-END AUTONOMOUS DRIVING REALLY NEED PERCEPTION TASKS?
  • 上位机知识篇---与、或、移位操作(、|、>><<)
  • 工具包组件和内置Agent组件