Docker 镜像的缓存特性

本文介绍了Docker镜像缓存的相关知识。Docker镜像结构分层,其缓存可在构建和拉取镜像时发挥作用。构建缓存通过重用未更改的层提高效率,缓存生效依赖指令顺序不变;拉取缓存可避免重复拉取基础镜像。使用缓存能提升构建速度、减少带宽等。

dockerimages

Author:rab



前言

首先我们要清楚,Docker 的镜像结构是分层的,镜像本身是只读的(不管任何一层),当我们基于某镜像运行一个容器时,会有一个新的可写层被加载到镜像的顶部,我们通常将这一层称之为容器层容器层之下的都称之为镜像层。我们所有对容器的增删操作都只会发生在容器层中,因此,容器层保存的是从容器运行时开始到当前的数据变化部分,不会对镜像层本身进行任何修改。镜像的其他特性就不在一一举例了,我们现在的目标是镜像的缓存特性,镜像的缓存有什么优势?它在哪方面实现缓存?接下来我们来细看一下。

一、构建缓存

1、什么是构建?

Docker 镜像构建使用分层文件系统的概念,每个 Dockerfile 指令都会生成一个新的文件系统层,这些层通过联合文件系统(UnionFS)技术叠加在一起,形成最终的镜像。

2、什么是缓存?

Docker 使用缓存来提高构建效率,当构建镜像时,如果之前的层已经存在并且没有发生更改(顺序上的更改),那 Docker 将重用这些层,而不是重新生成它们,这可以显著减少构建时间和服务器带宽使用。

3、案例演示缓存特性

  • 创建 Dockerfile 文件并构建镜像

    mkdir -p /root/dist && cd /root/dist     # 创建构建上下文目录
    vim Dockerfile                           # 添加下面内容
    
    FROM centos:centos7.9.2009
    RUN yum install -y wget
    
    docker build -t centos:v1 .
    
    Sending build context to Docker daemon  2.048kB ①
    Step 1/2 : FROM centos:centos7.9.2009  ②
     ---> eeb6ee3f44bd  
    Step 2/2 : RUN yum install -y wget  ③
     ---> Running in a51051b0f4a5
    Loaded plugins: fastestmirror, ovl
    Determining fastest mirrors
     * base: mirrors.ustc.edu.cn
     * extras: mirrors.ustc.edu.cn
     * updates: mirrors.huaweicloud.com
    Resolving Dependencies
    --> Running transaction check
    ---> Package wget.x86_64 0:1.14-18.el7_6.1 will be installed
    --> Finished Dependency Resolution
    ...
    ...
    Installed:
      wget.x86_64 0:1.14-18.el7_6.1                                                 
    
    Complete!
    Removing intermediate container a51051b0f4a5  ④
     ---> 9a4b27a6d88d  
    Successfully built 9a4b27a6d88d  ⑤
    Successfully tagged centos:v1  ⑥
    

    镜像构建流程分析:

    ①:向 Docker 守护进程发送构建上下文,即将 /root/dist 目录下的所有文件发送给 Docker daemon,因此不要将 //usr/etc 等目录作为构建上下文发送给 Docker daemon,否则构建出的镜像将会很臃肿,且构建会很缓慢甚至有可能会构建失败,所以为什么一开始我就创建了一个空目录(/root/dist)作为我上下文的存储目录。

    ②:步骤1(Step 1/2),将 centos:centos7.9.2009 作为构建的基础(base)镜像,该 base 镜像 ID 为 eeb6ee3f44bd

    ③:步骤1(Step 2/2),开始执行 Dockerfile 中的指令 RUN yum install -y wget,而且是在一个中间(临时)容器上执行的指令,该临时容器的 ID 为 a51051b0f4a5,为什么要使用临时容器?因为 base 镜像是只读的,想要进行增删只能在容器层实现。

    ④:RUN yum install -y wget 指令在临时容器 a51051b0f4a5 完成安装后,就会将临时容器删除(即构建信息中的 Removing intermediate container a51051b0f4a5 部分)并最终将该临时容器保存为镜像,且镜像 ID 为 9a4b27a6d88d

    ⑤:镜像 9a4b27a6d88d 构建成功。

    ⑥:将镜像 9a4b27a6d88d 打上 Tag 为 centos:v1

    查看本地镜像详情:

    image-20231006093145229

    可见,图中的 TAG、IMAGE ID 与我们 ⑤、⑥ 是一一对应的,而且你会发现构建后的镜像的容量比基础镜像更大了。

  • Docker 镜像缓存应用

    在构建上下文目录中创建一个测试文件(test.txt)进行缓存测试验证。

    touch test.txt   # 创建测试文件
    vim Dockerfile   # 添加下面内容
    
    FROM centos:centos7.9.2009
    RUN yum install -y wget
    COPY test.txt /usr/local
    
    docker build -t centos:v2 .
    
    Sending build context to Docker daemon   2.56kB
    Step 1/3 : FROM centos:centos7.9.2009
     ---> eeb6ee3f44bd
    Step 2/3 : RUN yum install -y wget  ①
     ---> Using cache
     ---> 9a4b27a6d88d
    Step 3/3 : COPY test.txt /usr/local  ②
     ---> 8f421058bfd8
    Successfully built 8f421058bfd8
    Successfully tagged centos:v2
    

    镜像构建流程分析:

    ①:当执行 RUN yum install -y wget 指令时,就使用了缓存 Using cache,且是镜像 9a4b27a6d88d 层的缓存,不难看出,这镜像就是上面我们刚构建而成的。

    ②:同样 COPY test.txt /usr/local 指令在临时容器中构建完成并最终生成镜像 8f421058bfd8

    查看本地镜像详情:

    image-20231006094542859

    如果你不想使用镜像缓存可添加 --no-cache 选项:docker build -t centos:v2 --no-cache .

    此时构建镜像就不会使用本地镜像缓存了。

4、注意

这里要注意的是,缓存生效的前提是 Dockerfile 的指令未发生位置顺序上的变动,否则缓存失效(会重新生成新的镜像层,而不会使用缓存),具体案例如下。

  • 修改 Dockerfile 文件中的指令顺序并构建镜像

    FROM centos:centos7.9.2009
    COPY test.txt /usr/local
    RUN yum install -y wget
    
    docker build -t centos:v3 .
    

    镜像构建流程分析:

    此时就没使用缓存了,构建流程与上面是一致的。

    查看本地镜像详情:

    image-20231006095006205

  • 构建说明

    尽管从逻辑上来说改动指令顺序对镜像的内容没有改变,但由于镜像的分层结构特性,改动 Dockerfile 指令顺序后 Docker 必须重建受影响的镜像层。

    看看分层:图中更清晰地像我们展示了镜像的分层结构(可见这些镜像都是在基础镜像层上继续叠加新的镜像层成为新的镜像),每一层由上至下排列,且上层依赖于下层。

    image-20231006095626841

二、Pull 缓存

Docker 除了在镜像构建时可使用缓存,在拉取(pull)镜像时也会使用缓存,具体案例如下。

1、先 pull 一个基础镜像(如:debian)

docker pull debian

2、再 pull 一个应用镜像(如:httpd)

docker pull httpd

Pull 分析:怎么证明本次的 pull 使用了缓存?

下图中,Already exists,说明该 httpd 镜像使用的 base 镜像是 debian 镜像,而 debian 镜像我们已经提前 pull 了,因此就不需额外地再次 pull,提升了镜像的构建效率。

image-20231006100356941

总结

综上案例我们要知道,镜像的缓存可以是在构建时发生,也会在 pull 镜像时发生。

而且我们不难归纳出 Docker 镜像缓存在实际应用中的优势:

  • 构建速度提升:使用缓存可以显著提高镜像构建的速度,减少了不必要的工作,节省时间;

  • 减少带宽使用:因为构建可以从本地缓存中获取,所以减少了从其他远程仓库下载的数据量,从而减少了带宽的使用;

  • 提高可重复性:镜像缓存确保了构建的可重复性,这点毋庸置疑,这也是 Docker 镜像的精髓所在;

  • 降低资源消耗:因为缓存特性,Docker Daemon 不必重新执行 Dockerfile 中已经缓存的指令,从而降低了系统资源的消耗;

  • 减少互联网依赖:如果缓存中已经存在所需的镜像层,那么构建过程则不依赖于互联网上的外部资源,尤其是在网络不稳定或有限的环境中,更体现出来其可靠性。

—END

<think> 我们已知用户希望了解删除Docker镜像缓存的方法。根据提供的引用,我们有三种相关引用信息: 引用[1]介绍了两种清理方式:`docker rmi`用于删除指定镜像,`docker system prune -a`用于清理整个Docker系统中未使用的资源(包括镜像容器、网络等)。 引用[2]给出了一个脚本示例,其中包括删除悬空镜像(dangling images)的命令:`docker rmi $(docker images -f "dangling=true" -q)`,以及清理卷、网络的命令。 引用[3]描述了Docker镜像缓存特性,解释了镜像分层和容器层的概念,但并未直接给出删除缓存的方法。 结合引用信息,我们可以总结删除Docker镜像缓存的方法如下: 1. **删除指定镜像**:使用`docker rmi`命令,可以删除指定的镜像(通过镜像ID或名称)。注意,如果镜像正在被使用,需要先停止并删除相关容器。 2. **清理未使用的资源(包括镜像缓存)**:使用`docker system prune -a`命令,该命令会删除所有未使用的资源(包括未使用的镜像、停止的容器、网络等)。注意:这个命令会删除所有未被使用的镜像(不仅仅是悬空镜像),所以请谨慎使用。 3. **删除悬空镜像(dangling images)**:悬空镜像是那些没有标签并且没有被任何容器引用的镜像。可以使用`docker images -f "dangling=true" -q`来列出这些镜像,然后通过`docker rmi`删除。引用[2]中给出了一个脚本示例。 4. **清理构建缓存**:引用[3]提到镜像的构建缓存,但未给出直接删除方法。实际上,Docker在构建镜像时使用缓存,这些缓存通常存储为中间镜像层。我们可以通过删除悬空镜像(包括中间层)来清理构建缓存。此外,使用`docker builder prune`命令可以清理构建缓存(这个在引用中未提到,但根据Docker知识补充)。 另外,根据Docker的使用经验,我们还可以补充: 5. **删除所有未被使用的镜像**(包括未被标记和未被容器引用的):使用`docker image prune -a`。这个命令会删除所有未被任何容器使用的镜像(不仅仅是悬空镜像,还包括那些有标签但未被使用的镜像)。 因此,我们可以向用户介绍以下几种方法: - 方法1:删除指定镜像(适用于明确知道要删除的镜像) ```bash docker rmi [IMAGE_ID_OR_NAME] [IMAGE_ID_OR_NAME] ... ``` - 方法2:删除所有悬空镜像(dangling images) ```bash docker rmi $(docker images -f "dangling=true" -q) ``` 或者(新版本Docker) ```bash docker image prune ``` - 方法3:删除所有未被使用的镜像(包括悬空镜像和有名字但未被使用的镜像) ```bash docker image prune -a ``` - 方法4:清理整个Docker系统未使用的资源(包括镜像容器、网络、卷等) ```bash docker system prune -a ``` 注意事项:这些命令中的`-a`或`--all`参数表示包括未被使用的镜像(不仅仅是悬空镜像),而`-f`或`--force`可以跳过确认提示。在使用`docker system prune -a`时,它会删除所有未使用的资源,所以请确保不再需要这些资源。 另外,引用[2]中的脚本还展示了清理卷和网络的方法,但用户问题聚焦在镜像缓存,所以我们可以主要介绍镜像缓存的删除。 因此,回答用户: 您可以使用以下几种方法来删除Docker镜像缓存: 1. **删除指定镜像**:使用`docker rmi`命令后接镜像ID或名称,可以删除指定的镜像。例如: ```bash docker rmi ubuntu:18.04 ``` 2. **删除悬空镜像(dangling images)**:悬空镜像是未被任何容器引用的中间层镜像,可以使用以下命令删除: ```bash docker image prune ``` 或者使用旧版本命令: ```bash docker rmi $(docker images -f "dangling=true" -q) ``` 3. **删除所有未被使用的镜像**:包括悬空镜像以及那些有名字但未被任何容器使用的镜像: ```bash docker image prune -a ``` 4. **清理整个Docker系统的未使用资源**(包括镜像容器、网络、卷等): ```bash docker system prune -a ``` 注意:在执行这些命令时,请确保要删除的镜像或资源确实不再需要,因为删除操作不可逆。使用`-a`参数会删除更多资源,请谨慎使用。 另外,如果您想要删除的是构建缓存(Build Cache),可以使用: ```bash docker builder prune ``` 该命令会删除构建缓存,释放磁盘空间[^3]。 请根据您的具体需求选择合适的方法。 §§相关问题§§ 1. 如何查看Docker镜像的磁盘占用情况? 2. Docker镜像的悬空镜像(dangling images)是如何产生的? 3. 如何避免Docker镜像缓存占用过多磁盘空间? </think> ### 删除 Docker 镜像缓存的方法 根据引用内容,删除 Docker 镜像缓存主要有以下方法: #### 1. **删除指定镜像(手动清理)** ```bash docker rmi <镜像ID_1> <镜像ID_2> ... ``` - **功能**:删除指定镜像(支持多个镜像ID或名称)[^1]。 - **适用场景**:明确知道需要删除的缓存镜像ID时。 - **注意**:需先停止相关容器,否则会报错。 #### 2. **清理悬空镜像(dangling images)** ```bash docker rmi $(docker images -f "dangling=true" -q) ``` - **功能**:删除所有未被容器引用的中间层镜像(构建缓存)[^2]。 - **验证**:可先用 `docker images -f "dangling=true"` 查看悬空镜像列表。 #### 3. **系统级清理未使用资源** ```bash docker system prune -a ``` - **功能**:清理所有未使用的资源,包括: - 停止的容器 - 未被任何容器引用的镜像 - 悬空镜像(构建缓存) - 无效的网络和卷[^1]。 - **注意**:操作不可逆!会删除所有未被使用的资源,谨慎执行。 #### 4. **精细化分层清理** ```bash # 仅清理悬空镜像 docker image prune # 清理所有未被使用的镜像(含悬空和有标签但未使用的) docker image prune -a # 清理构建缓存Docker 18.09+) docker builder prune ``` ### 操作建议 1. **常规维护**:定期运行 `docker image prune` 清理悬空镜像(最安全的缓存清理方式)。 2. **彻底清理**:确认无重要数据后,使用 `docker system prune -a` 释放最大磁盘空间。 3. **避免误删**:先执行 `docker system df` 查看磁盘占用,再用 `--dry-run` 参数预览清理效果: ```bash docker system prune -a --dry-run ``` ### 缓存机制说明 Docker 镜像采用分层存储结构,构建时每层都会生成缓存。当修改 Dockerfile 的某一层后,后续所有层的缓存都将失效,旧缓存层变为“悬空镜像”占用磁盘空间[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云计算-Security

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值