Dockerfile 编写经验:优化大小与效率
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镜像,使应用更易于部署和维护。