标签 容器 下的文章

Dockerfile 编写经验:优化大小与效率

创建高效的 Docker 镜像对于加速构建、减少存储需求和提升部署性能至关重要。在实践中,通过不断改进 Dockerfile,可以总结出编写优化 Dockerfile 的一些关键技巧。

Dockerfile 通用的技巧总结

1. 使用多阶段构建

  • 利用多阶段构建分离构建和运行时环境,仅将必要的产物(二进制文件、库、配置)复制到最终阶段,这通过排除构建工具和中间文件保持运行时镜像精简

  • 示例:仅从构建阶段复制编译后的二进制文件和特定资源

    WORKDIR /device-openvino
    # Copy binaries and resources from the builder stage
    COPY --from=builder /device-openvino/device-openvino-object-classification-c /device-openvino/device-openvino-object-classification-c
    # Copy the CSDK library (custom dependency built by build_deps.sh)
    COPY --from=builder /opt/iotech/iot/1.5/lib /opt/iotech/iot/1.5/lib
    COPY --from=builder /device-openvino/deps/device-sdk-c/build/release/_CPack_Packages/Linux/TGZ/csdk-0.0.0 /device-openvino/csdk
    # copy device service configuration file
    COPY res/configuration.yaml /device-openvino/res/configuration.yaml
    COPY res/profiles /device-openvino/res/profiles
    COPY res/devices /device-openvino/res/devices

2. 最小化层数

  • 将相关命令(例如,apt-get update && apt-get install )合并到单个 RUN 指令中,以减少层数。每个 RUN 都会创建一个新层,增加镜像大小。

  • 使用&&\保持可读性,同时串联命令。

    # Configure the image source and install runtime dependencies
    RUN sed -i 's/archive.ubuntu.com/mirror.nju.edu.cn/g' /etc/apt/sources.list && \
        sed -i 's/security.ubuntu.com/mirror.nju.edu.cn/g' /etc/apt/sources.list && \
        apt-get update && apt-get install -y curl gnupg && \
        # Configure OpenVINO repository
        curl -fsSL https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB | apt-key add - && \
        echo "deb https://apt.repos.intel.com/openvino/2025 ubuntu22 main" | tee /etc/apt/sources.list.d/intel-openvino-2025.list && \
        # Configure Intel GPU repository
        curl -fsSL https://repositories.intel.com/gpu/intel-graphics.key | \
        gpg --yes --dearmor --output /usr/share/keyrings/intel-graphics.gpg && \
        echo "deb [arch=amd64,i386 signed-by=/usr/share/keyrings/intel-graphics.gpg] https://repositories.intel.com/gpu/ubuntu jammy unified" | \
        tee /etc/apt/sources.list.d/intel-gpu-jammy.list && \
        # Install runtime dependencies
        apt-get update && apt-get install -y \
        # base dependencies
        dumb-init \
        libyaml-dev \
        uuid-dev \
        libpaho-mqtt-dev \
        libcbor-dev \
    ...

3. 彻底清理

  • 在包安装后始终移除临时文件,例如APT缓存(/var/lib/apt/lists/*)。使用apt-get clean--no-install-recommends避免不必要的依赖。

  • 示例:

        # cleanup
        --no-install-recommends && \
        apt-get clean && \
        rm -rf /var/lib/apt/lists/*

4. 选择合适的基镜像

  • 选择满足需求的最小基镜像(例如,ubuntu:22.04 或更小的 debian:slim )。除非必要,避免使用臃肿的镜像。

  • 明确指定平台(例如,--platform=linux/amd64 )以确保兼容性

    # including its dependencies
    ARG BASE=ubuntu:22.04
    FROM --platform=linux/amd64 ${BASE} as builder
    LABEL license='SPDX-License-Identifier: Apache-2.0' \
    ...

5. 仅安装必要的依赖

  • 精确指定运行时依赖。避免在最终镜像中安装开发包(例如,libopencv-dev),除非必要。新版Dockerfile选择性安装OpenCV模块是一个很好的示例。
  • 使用apt-cache search或包文档确定确切的依赖。

6. 利用构建缓存

  • 按从最不可能更改到最可能更改的顺序排列指令(例如,先安装包,再复制源代码)。这最大化构建缓存的复用。

  • 新版Dockerfile在 make 之前复制源代码,确保早期层(例如依赖安装)被缓存,能大大节省构建时间!

    # build device service 
    COPY src /device-openvino/src
    COPY Makefile /device-openvino/Makefile
    RUN make clean build
    
    # Stage 2: Create the final runtime image
    FROM --platform=linux/amd64 ${BASE}

常见陷阱

  • 过度安装依赖:在运行时镜像中安装广泛的包(例如,libopencv-dev)会增加体积。始终验证运行时需求。
  • 忘记清理:不移除APT缓存或临时文件会在镜像中留下不必要的数据。
  • 冗余指令:重复环境变量设置或存储库配置会增加层数和复杂性。
  • 未固定版本:不指定包版本可能导致构建不一致。
  • 广泛的COPY命令:不加筛选地复制整个目录会包含未使用的文件,增加大小。

总结

本文展示了如何通过合并命令、清理缓存和选择最小依赖等小而精心的更改,显著减少 Dockerfile 构建镜像的大小、开发过程的效率以及发布后的稳定性。通过遵循上述技巧,可以创建精简、安全且高效的Docker镜像,使应用更易于部署和维护。