手记

我如何将Docker镜像大小缩减90%:精简容器的最佳实践

缩减 Docker 镜像的体积对于简化开发流程、加速构建速度和缩短部署时间至关重要,同时还能节省宝贵的存储空间。基于我的实际经验,我发现了一些既优化 Docker 镜像,又能提升性能和效率的有效策略。以下是我推荐并经常使用的最佳实践,以保持精简高效的 Docker 镜像。

1. 使用最小的镜像

选择最小的基础镜像是最有效的方法之一。最小的基础镜像,如alpinescratchdebian-slim,要小得多,因为它们只包含必要的内容。

Python 示例代码

看看基于 ubuntu 的 Python 镜像和基于 alpine 的那个之间的大小差异

使用 Ubuntu 作为基础镜像:

FROM python:3.11-slim
# 从Python 3.11-slim镜像开始
  • 图像大小:大约 60 MB,基于 Python 3.11 和 Ubuntu 的基础镜像

使用 Alpine 作为基础镜像,就像...

FROM python:3.11-alpine # 使用Python 3.11-alpine基础镜像
  • 图像大小:大约 23 MB,基于 Alpine 基础镜像的 Python 3.11

基于 Alpine 的镜像大约是基于 Ubuntu 的镜像的三分之一大小。这种显著的大小减少是因为 Alpine Linux 是一个特别设计用于 Docker 环境的最小化发行版。使用最小基础镜像不仅能减少镜像的大小,还能减小攻击面,还能增强安全性。

2. 多阶段构建流程

多阶段构建允许你将构建环境与运行时环境隔离开,确保最终镜像仅包含必要文件。这有助于排除运行时不需要的构建工具和依赖等,从而减小最终 Docker 镜像的体积。

使用 Python 的例子

考虑一个使用 Python 开发的应用程序,你希望采用多阶段构建技术来让最终镜像保持精简:

用于多阶段构建的Dockerfile:

     # 构建阶段:  
    FROM python:3.11-slim AS builder  
    WORKDIR /app  

    # 安装构建所需的依赖项  
    COPY requirements.txt .  
    RUN pip install --user -r requirements.txt  

    # 复制应用代码:  
    COPY . .  

    # 最终阶段:  
    FROM python:3.11-slim  
    WORKDIR /app  

    # 安装运行时所需的依赖项  
    COPY --from=builder /root/.local /root/.local  
    COPY . .  

    # 设置环境变量以包含用户安装的包路径  
    ENV PATH=/root/.local/bin:$PATH  

    CMD ["python", "app.py"]
大小对比
  • 如果没有使用多阶段构建:如果你使用单阶段Dockerfile,最终生成的镜像将同时包含构建依赖和应用代码:
## 使用 Python 3.11 版本的 slim 镜像  
FROM python:3.11-slim  
## 设置工作目录为 /app  
WORKDIR /app  
## 复制 requirements.txt 文件到当前目录  
COPY requirements.txt .  
## 安装 requirements.txt 文件中列出的依赖包  
RUN pip install -r requirements.txt  
## 复制当前目录下的所有文件到容器中  
COPY . .  
## 设置容器启动时运行的命令  
CMD ["python", "app.py"]
  • 图像大小:约 150 MB(包含构建和运行所需依赖项)。

使用多阶段构建法:通过使用提供的多阶段构建示例来,最终镜像更小。

  • 图片大小:大约 60 MB,(仅包含运行时所需的依赖和应用程序代码)。
3. 删掉不必要的文件

清理无用的文件,比如缓存、临时文件和构建依赖项,是减小Docker镜像大小的重要一步。这一做法确保你的镜像只包含运行应用所需的必要组件,同时最小化镜像的体积并减少潜在的攻击面。

Python 示例代码

这里是一个如何在Python应用的Dockerfile中移除不必要的文件的例子。

清理前的状况。

     FROM python:3.11-slim  

    WORKDIR /app  

    # 安装构建所需的依赖  
    COPY requirements.txt .  
    RUN pip install -r requirements.txt  

    # 复制应用的代码  
    COPY . .  

    CMD ["python", "app.py"]

清理模式:

FROM python:3.11-slim  

WORKDIR /app  

# 安装构建依赖项  
COPY requirements.txt .  
RUN pip install -r requirements.txt \  
  # 清理临时文件和缓存数据  
  && rm -rf /root/.cache/pip  

# 复制应用程序代码  
COPY . .  

CMD ["python", "app.py"]

未进行清理:在一个没有清理的Dockerfile中,因为未清理的缓存和临时文件,镜像可能会变得更大。

  • 图片大小约为150MB(包括构建缓存和其他不需要的文件)。

使用清理命令,比如:使用清理命令,如 rm -rf /root/.cache/pip 来清除缓存和临时文件可以减小最终镜像的大小:

  • 图片大小: 在清理了缓存和临时文件之后,大约 120 MB 左右。
4. 使用 .dockerignore 文件配置

.dockerignore 文件类似于 .gitignore 文件,但用于 Docker 构建。它指定了哪些文件和目录不应该被包含在 Docker 构建上下文内容中。这有助于缩小构建上下文内容的大小,从而加快构建速度,生成更小的 Docker 镜像文件。

了解使用 .dockerignore 的优点
  1. 减少构建上下文大小:通过排除不必要的文件,你可以减少发送给Docker守护程序的数据量,从而加快构建速度。
  2. 更小的Docker镜像:在最终镜像中排除不需要的文件可以防止它们被包含,从而有助于减小镜像的大小。
  3. 提高构建效率:较小的构建上下文意味着Docker可以更有效地缓存层,从而加快重新构建的过程。
下面是一个 .dockerignore 文件的例子

这里有一个简单的 .dockerignore 文件例子:

    .git  
    node_modules  
    *.log  
    .DS_Store

请注意,以上文件路径和模式不需要翻译,它们保持原样。

如果没有.dockerignore文件:

  • 当不必要的文件被包含在 Docker 构建上下文中时,这些文件会被发送给 Docker 守护进程,并最终成为 Docker 镜像的一部分,即使它们在最终镜像中并没有被使用。
  • 例如,包含 .git 目录或 node_modules 文件夹可能会显著增加构建上下文的大小。.git 目录可能包含几百兆字节的版本历史,而 node_modules 可能会增加另外几百兆字节的依赖文件,这些依赖文件在生产镜像中不需要。
  • 对构建上下文大小的影响:排除最终镜像不需要的文件和目录,有助于减小构建上下文的大小,否则,构建上下文的大小可能会增加到几个 GB,具体取决于被排除的文件的数量和大小。如果构建上下文包含一个大型的 .git 目录、node_modules 文件夹以及其他不需要的文件,其大小可能达到 1 GB 左右。

使用**.dockerignore**:

  • 通过使用 .dockerignore 文件排除不必要的文件,你可以将构建范围限制为仅包含应用程序所需的文件。
  • 排除 .gitnode_modules 和其他大型目录后,构建范围的大小可以从几个吉字节缩小到仅几兆字节。
  • 对镜像大小的影响是:虽然 .dockerignore 文件本身并不会直接减小最终 Docker 镜像的大小,但它可以防止不必要的文件被添加到构建范围内。这使得构建过程更加高效,并有助于通过确保仅包含相关文件来创建更精简的最终镜像。在排除这些不必要的文件后,构建上下文可能减少到 50 MB 左右,这可以显著减少构建时间,使最终 Docker 镜像更加高效。
5. 减少层次

在 Docker 中,每个 RUNCOPYADD 指令都会在生成的镜像中创建一个新的层。这些层会增大 Docker 镜像的大小并影响构建的速度。将多个命令合并成一个 RUN 指令有助于减少层数,从而生成更高效和更紧凑的 Docker 镜像。

无层次简化:

  • 每个单独的指令(如 RUNCOPY 等)都会在 Docker 镜像中创建一个新的层。这些层层层叠加会导致镜像大小变大,因为中间文件、临时数据和额外的元数据都会被包含在内。
  • 例如,使用单独的 RUN 指令会产生多个层,每个层都会有自己的元数据和开销,这可能会导致最终镜像大小变大。
  • 这将影响镜像的大小:如果你使用多个 RUN 指令,比如:
RUN 更新软件包列表  
RUN 安装 curl -y  
RUN 清理软件包缓存

使用多个 RUN 指令会导致镜像大小大约为 150 MB,每一层都会增加一些额外的大小。因此尽量减少使用多个 RUN 指令。

最小化层次:

  • 将多个命令合并到一个 RUN 指令中可以减少层数,并有助于将更改合并到较少的、更精简的层中。
  • 例如,将命令合并到一个 RUN 指令中,比如这样:

  • RUN command1 && command2 && command3
    RUN apt-get update && apt-get install -y curl && apt-get clean
# 更新包列表并安装curl,然后清理缓存

将命令组合成一个 RUN 指令可以将镜像的大小减少到大约 130 MB。这样做的方法是将更改合并到更少的层中,并尽量减少多余的中间数据。

6. 使用特定的复制命令

而不是复制整个目录到你的Docker镜像,使用具体的COPY命令,只包含你需要的文件。这种方法避免了传输不必要的文件,减少了镜像的大小。

例子:比如说

复制 package.json 到当前目录  
复制 src/ 目录到当前目录
  • 大小影响:通过仅复制特定的文件和目录,您可以避免包含不必要的文件,这些文件可能会使镜像文件变大。比如说,排除开发文件或构建工件,从而减少镜像文件的大小数兆字节。
7. 使用多种架构的镜像

创建多架构的Docker镜像确保了与各种环境(如ARM和x86)的兼容性。这种方法可以更好地适应各种硬件平台。

例子

  • 大小影响:多架构镜像针对特定架构进行了优化,这会减少在不同平台上使用的镜像的大小。这有助于避免那些臃肿的镜像,这些镜像包含了不必要的多架构支持,实际上只需要支持一个架构。
结论部分

这些最佳实践可以让Docker镜像更加高效、安全和快速,从而帮助您更高效地管理和部署容器。

0人推荐
随时随地看视频
慕课网APP