侧边栏壁纸
博主头像
汪洋

即使慢,驰而不息,纵会落后,纵会失败,但一定可以达到他所向的目标。 - 鲁迅

  • 累计撰写 212 篇文章
  • 累计创建 81 个标签
  • 累计收到 160 条评论

Docker - 镜像小技巧

汪洋
2022-04-24 / 0 评论 / 5 点赞 / 495 阅读 / 2,961 字

今天,有同学发现了 Docker 面试文章中,关于镜像删除的一条错误命令(无需担心,已改正,也感谢这位同学)。有感而发,就谈谈操作镜像中的一些小技巧

Docker 镜像简介

如果你熟悉 VM,可以把 Docker 镜像理解为 VM 模板,VM 模板就像停止运行的VM,而 Docker 镜像就像停止运行的容器。常见的镜像仓库服务是 Docker Hub,但也存在其他镜像仓库服务。镜像由多隔层组成,每层叠加之后,从外部看来就像一个独立的对象。镜像内部是一个精简的操作系统(OS),同时还包含了应用运行所必需的文件和依赖

Docker 镜像详解

前面提到镜像就像停止运行的容器,实际上,可以停止某个容器的运行,并从中创建新的镜像。在该前提下,镜像可以理解为一种构建时结构,而容器可以理解为运行时结构

镜像和容器

一旦容器从镜像启动后,二者就变成了互相依赖的关系,并且在镜像上启动的容器全部停止之前,镜像是无法被删除的。当然,如果您铁了心,那么是可以通过 -f 强制删除的,当然容器可能这辈子也无法再次启动了,慎用!!!

镜像通常比较小

容器的目的就是运行应用或者服务,这意味着容器的镜像中必须包含应用/服务运行所必须的操作系统和应用文件。但是,容器又追求快速和小巧,这意味着构建镜像的时候通常需要剪裁掉不必要的部分,保持较小的体积。当然,也不是说所有的容器都必须小。比如,企业中会部署多套环境(业务环境、测试环境)。业务环境中应用的镜像在满足性能和安全稳定的前提小要尽可能小,以此带来更低的下载带宽要求以及更安全的环境。测试环境中的镜像应该足够大,以此满足调试代码找寻 Bug 的目的。所以,不要以偏概全,具体问题具体分析

镜像仓库服务

Docker 镜像存储在镜像仓库服务中,Docker 客户端的镜像仓库服务是可以配置的,默认使用 Docker Hub。其分为官方仓库(Official Repository)和非官方仓库(Unofficial Repository)

镜像命名和标签

只需要给出镜像的名字和标签,就能在官方仓库中定位一个镜像(采用“:”分隔),从官方仓库拉取镜像时,命令格式如下:

$ docker image pull <repository>:<tag>

如果没有在仓库名称后指定具体的镜像标签,则 Docker 会假设用户希望拉取标签为 latest 的镜像。注意:标有 latest 标签的镜像不保证这是仓库中最新的镜像,所以使用 latest 标签时要谨慎!(k8s 环境中,如果镜像版本为 latest 默认情况下还会重复性下载)

从非官方仓库拉取镜像时,需要在仓库名称前加上 Docker Hub 的用户名或者组织名称。如下:

$ docker image pull "用户名"/<repository>:<tag>
$ docker image pull wangyanglinux/myapp:v1

ps: docker image pull == docker pull

从第三方镜像仓库服务获取镜像( 非 Docker Hub ),则需要在镜像仓库名称前加上第三方镜像仓库服务的 DNS 名称(需要注意的是可能需要有第三方镜像仓库服务的账户,在拉取镜像前完成登录),如下:

$ docker image pull "DNS"/<repository>:<tag>
$ docker image pull harbor.xinxianghf.com/myapp:v1

为镜像打多个标签

一个镜像可以根据用户需要设置多个标签,这是因为标签是存放在镜像元数据中的任意数字或者字符串。在 docker image pull 命令中指定 -a 参数可以拉取仓库中的全部镜像(就不能指定 tag 了),语法如下:

$ docker image pull -a <repository>
$ docker image pull -a wangyanglinux/myapp

过滤 docker image ls 的输出内容

docker 通过--filter 参数来果过滤 docker image ls 命令返回的镜像列表的内容,语法如下:

$ docker image ls --filter="过滤器名称"="对应过滤器可以使用的参数"

这里介绍一下“悬虚镜像”,就是那些没有标签的镜像被称为悬虚镜像,出现这种情况是因为构建了一个新的镜像,然后为该镜像打了一个已经存在标签,此时, docker 发现已经有镜像包含相同的标签,接着 Docker 会移除旧镜像上的标签,将该标签标在新的镜像之上,那么旧镜像就变成了悬虚镜像。可以通过以下命令删除全部的悬虚镜像

$ docker image prune

docker 目前支持的过滤器如下

  • dangling:可以指定 true 或者 false,仅返回悬虚镜像(true),或者返回非悬虚镜像(false)
  • before:需要使用镜像名称或者 ID 作为参数,返回在之前被创建的全部镜像列表
  • since:与 before 类似,不过返回的是指定镜像之后创建的全部镜像
  • lable:根据标注(lable)的的名称或值,对镜像进行过滤,docker image ls 命令输出中不显示标注内容
  • 其他的过滤方式可以使用 reference,下面是使用 reference 完成过滤并且仅显示标签为 latest 的实例
$ docker image ls --filter=reference="*:latest"

镜像和分层

Docker 镜像由一些松耦合的只读镜像层组成,Docker 负责堆叠这些镜像层,并且将它们表示为单个同一的对象。有多种方式可以查看和检查构成某个镜像的分层,第一种:就是我们在 pull 镜像时,命名输出内容中,以 pull complete 结尾的每一行都代表了镜像中某个被拉取的镜像层。第二种:docker image inspect,在输出内容中的 “Layers” 对应的列表中就是该镜像的镜像层

共享镜像层

多个镜像之间可以并且确实会共享镜像层,这样可以有效节省空间并提升性能。那么我们怎么知道是否镜像之间共享了镜像层呢,这个可以在 pull 镜像时指定 -a 参数,拉取某个镜像的所有镜像,注意那些 Already exists 结尾的行,可以说明镜像层是可以共享的

根据摘要拉取镜像

我们之前都是通过标签(tag)来拉取镜像的,但是 tag 是可变的,这意味着如果给镜像打错标签,或者给镜像打一个已经存在标签,都可能导致问题。那么什么是摘要,每一个镜像都存在一个基于内容的密码散列值,摘要就是指这个散列值。每次我们在拉取镜像后,摘要都会作为返回代码的一部分,可以使用 docker image ls 命令之后添加 --digests 参数查看镜像摘要

通过摘要拉取镜像的方式和通过tag拉取镜像的方式稍微有点区别,如下:
语法:

$ docker image pull <repository>@"摘要值"
$ docker image pull centos@sha256:76d24f3ba3317fa945743bb3746fbaf3a0b752f10b10376960de01da70685fbd

删除 docker 主机上全部镜像的快捷方式

docker image rm $(docker image ls -q) -f
0

评论区