Docker学习:Docker制作镜像的实用技巧,构建安全轻巧的容器镜像
在日常镜像构建中,我们频繁接触到的文件就是Dockerfile,一种用于定义docker镜像的文本文件,包含一系列指令和参数,用于指导Docker引擎在构建镜像时的执行顺序。Dockerfile 基础语法和构建镜像流程 - 皇帽讲绿帽带法技巧 - 博客园 今天,分享一些压缩容器镜像的小技巧给大家。
镜像制作的基本指令
镜像的本质是镜像层和运行配置文件组成的压缩包,构建镜像是通过运行 Dockerfile 中的 RUN 、COPY 和 ADD 等指令生成镜像层和配置文件的过程。
- FROM <镜像名称>:<标签>,设置构建镜像所需的基础镜像
- LABEL maintainer <作者姓名或邮箱>,标注镜像维护信息
- RUN <命令>,执行命令并将结果写入镜像,每个 RUN 指令会生成一层新的镜像层
- COPY <源路径> <镜像路径>,拷贝主机文件或文件夹到镜像里
- EXPOSE <端口>,告知 Docker 运行时该容器监听的端口
- CMD ["可执行文件", "参数1", "参数2"],容器启动执行的默认参数
镜像层体积的特点
RUN、COPY 和 ADD 指令会在已有镜像层的基础上创建一个新的镜像层,执行指令产生的所有文件系统变更会在指令结束后作为一个镜像层整体提交。 镜像层具有 copy-on-write 的特性,如果去更新其他镜像层中已存在的文件,会先将其复制到新的镜像层中再修改,造成双倍的文件空间占用。 如果去删除其他镜像层的一个文件,只会在当前镜像层生成一个该文件的删除标记,并不会减少整个镜像的实际体积。
查询不同镜像层的体积
如何优化 docker 镜像体积 | Shall We Code? docker 自带的 docker history 命令,该命令可以展示所有镜像层的创建时间、指令以及体积等较为基础的信息。 第三方的 dive 工具,该工具可以分析镜像层组成,并列出每个镜像层所包含的文件列表,可以很方便地定位到影响镜像体积的构建指令以及具体文件。 在Ubuntu使用snap安装dive即可: wagoodman/dive: A tool for exploring each layer in a docker image
FastAPI镜像构建
以下面的fastapi为例
# 使用 Python 3.12.0 作为基础镜像
FROM docker.1ms.run/library/python:3.12.0
# 设置工作目录为 /service
WORKDIR /service
# 修复时区设置,将容器时区设置为亚洲/上海
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo "Asia/Shanghai" > /etc/timezone
# 安装 uv 包管理器
# uv 是一个快速的 Python 包安装器和解析器,替代 pip
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#installing-uv
# 备选方案:从预构建镜像复制 uv 二进制文件
# COPY --from=ghcr.io/astral-sh/uv:0.5.29 /uv /uvx /bin/
RUN pip install --index-url https://pypi.tuna.tsinghua.edu.cn/simple/ uv==0.5.29
# 启用字节码编译,提高 Python 代码启动速度
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#compiling-bytecode
ENV UV_COMPILE_BYTECODE=1
# 设置 uv 缓存模式为 copy,确保依赖项被复制到镜像中而不是链接
# 这样可以避免在运行时依赖宿主机的缓存
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#caching
ENV UV_LINK_MODE=copy
# 安装项目依赖
# 先复制依赖配置文件,利用 Docker 层缓存优化构建速度
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#intermediate-layers
COPY ./pyproject.toml ./uv.lock ./alembic.ini /service/
RUN uv pip install -r pyproject.toml --system --index-url https://pypi.tuna.tsinghua.edu.cn/simple/
# 设置 Python 路径环境变量,确保可以正确导入项目模块
ENV PYTHONPATH=/service
# 复制脚本文件到容器中
COPY ./script /service/script
# 复制应用程序代码到容器中
# 这一步放在最后,因为代码变更最频繁,这样可以最大化利用 Docker 层缓存
COPY ./app /service/app
安装dive
sudo snap install docker
sudo snap install dive
sudo snap connect dive:docker-executables docker:docker-executables
sudo snap connect dive:docker-daemon docker:docker-daemon
dive fastapi-service:latest,📊 层次结构分析

基础层
- FROM blobs (116 MB) - 基础镜像层,包含操作系统核心文件
系统更新层
- 48 MB - 系统包管理器更新层,执行 apt-get update 和基础软件安装
- 177 MB - 包含 git 的安装层
软件安装层
- 587 MB - 主要应用软件安装层,包含Python等关键组件
- 18 MB - Python相关依赖安装
- 60 MB - Python 3.12.0 安装层
- 10 MB - pip 包管理器安装层
优化镜像体积的技巧
选择合适的基础镜像
在From使用官方镜像更安全,考虑使用Alpine Linux等轻量级发行版,据需求选择带特定标签的镜像(如python:3.11-slim而非python:latest)。
分段构建和从零构建
将镜像构建过程区分为构建和运行环境,在构建环境安装编译器等依赖并编译所需的二进制包,然后将其复制到仅包含必要运行依赖的运行环境中。
# 构建阶段
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp
# 运行阶段
FROM alpine:latest
COPY --from=builder /app/myapp /usr/local/bin/
CMD ["myapp"]
合并Run等指令减少层数
# 不推荐 - 创建3层
RUN apt-get update
RUN apt-get install -y package1
RUN apt-get install -y package2
# 推荐 - 只创建1层
RUN apt-get update && \
apt-get install -y package1 package2 && \
rm -rf /var/lib/apt/lists/*
删除无用缓存和无用文件
**使用.dockerignore文件**
排除不需要的文件,加速构建并减小镜像体积:
.git
node_modules
*.log
.env
构建过程删除多余文件
RUN apt-get update && \
apt-get install -y package && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
合并多个镜像层
避免在不同镜像层中更新文件而造成额外的体积占用。当构建的层数很多且执行指令较复杂时,很难避免在不同的镜像层中更新文件。
在docker build 命令中使用 —squash即可实现
谢谢关注收藏
⏰ 刚刷到的朋友注意啦!点击【关注】锁定宝藏库,从此升职加薪不迷路 ✨
轻量云主机限时优惠
RackNerd
☁ 主机显示特惠:只要80元(3TB流量,1vcpu,50GB硬盘),且多区域IDC机房。
购买地址:https://my.racknerd.com/aff.php?aff=14942

CloudCone
CloudCone 特惠轻量云主机:购买地址:https://app.cloudcone.com/?ref=12332

📢 腾讯云资源限时福利
有云服务器、CDN、对象存储、网络防护等需求的朋友,欢迎联系下方腾讯云官方销售 👇 ✔️ 内部专属折扣,价格更优:

评论区