关于Docker镜像

  • 仓库(Repository)
  • 镜像仓库服务(Image Registry)
  • 镜像仓库(Image Repository)
  • 标签(Tag)
  • 拉取镜像(Pull)
  • 过滤docker image ls输出内容
  • 搜索Docker Hub(Search)
  • 分层
  • 共享镜像层
  • 分发散列值(Distribution Hash)
  • 多层架构镜像
  • 删除(Remove)


仓库(Repository)

镜像仓库服务(Image Registry)

Docker镜像存储在镜像仓库服务 当中。Docker客户端的镜像仓库服务是可配置的,默认使用Docker Hub

镜像仓库(Image Repository)

镜像仓库服务包含多个镜像仓库。同样,一个镜像仓库中可以包含多个镜像,它们通常对应不同的版本。

官方和非官方镜像仓库
Docker Hub也分为官方仓库(Official Repository)和非官方仓库(Unofficial Repository)。

下图帮助理解:

docker的镜像文件能做U盘启动盘吗_Docker

拉取镜像命令的格式:
docker image pull <repository>:<tag>


标签(Tag)

  • 一个镜像可以拥有多个标签
  • 不能仅根据latest标签判断镜像为最新版本
  • docker image ls将相同镜像的不同标签分别列出,这是因为一个镜像可以根据用户需要设置多个标签,而标签就是存放在镜像元数据中的任意数字或字符串。
  • 悬虚(dangling)镜像:没有标签的镜像。
    出现悬虚镜像通常是因为构建了一个新镜像,然后为该镜像打了一个已经存在的标签。当此情况出现,Docker会构建新的镜像,然后发现已经有镜像包含相同的标签,接着Docker会移除旧镜像上面的标签,将该标签标在新的镜像之上。

拉取镜像(Pull)

  1. 拉取Docker Hub官方仓库中的镜像(默认)
    docker image pull <repository>:<tag>
  2. 拉取Docker Hub 的非官方仓库中的镜像
    docker image pull AAA/BBB:v2 解释:从Docker HubDocker账号ID为AAABBB中下载标签v2镜像
  3. 第三方镜像仓库服务获取镜像(非Docker Hub),需要在镜像仓库名称前加上第三方镜像仓库服务的DNS名称
    假如从Google容器镜像仓库服务(GCR) 拉取AAA的BBB库中标签为v2的镜像
    docker pull gcr.io/AAA/BBB:v2 `
  4. 根据摘要(Digest) 拉取镜像。

因为摘要是镜像内容的一个散列值,所以镜像内容的变更一定会导致散列值的改变。这意味着相同镜像摘要的是不可变的。

  1. 已知镜像的摘要,那么下次就可以使用摘要再次拉取这个镜像。这种方式可以确保准确拉取想要的镜像 。下图实验帮助理解:

    解释:
    假设我对ubuntu:latest镜像做了修改并上传。由于标签没有变,仅凭标签无法区分修改前后的两个镜像。这时可以使用摘要来指定唯一的镜像。
  1. docker image ls --digests查看了实验镜像的摘要,即图中光标强调部分
  2. docker image rm e4c5删除了该镜像
  3. docker image pull ubuntu@sha256:2b74...f05f根据摘要拉取镜像
  4. docker image ls --digests查看镜像摘要,确定成功拉取了修改过的镜像。

过滤docker image ls输出内容

  • Docker提供--filter参数来过滤docker image ls命令返回的镜像列表内容
  • 例如,只返回悬虚(dangling)镜像:
    docker image ls --filter dangling=true
  • Docker目前支持的过滤器
  • dangling :可以指定true 或者false ,仅返回悬虚镜像(true),或者非悬虚镜像(false)。
  • before :需要镜像名称或者ID作为参数,返回在之前被创建的全部镜像。
  • since :与before 类似,不过返回的是指定镜像之后创建的全部镜像。
  • label :根据标注(label) 的名称或者值,对镜像进行过滤。docker image ls 命令输出中默认不显示标注内容。
  • 其他的过滤方式可以使用reference 例如使用reference 完成过滤并且仅显示标签为latest的镜像:
    docker image ls --filter=reference="*:latest"
  • 也可以使用--format 参数来通过Go模板对输出内容进行格式化
  • 如果需要更复杂的过滤,可以使用OS或者Shell自带的工具,比如Grep或者AWK
  • -q选项意为quiet(静默模式),使docker image ls只输出镜像ID

搜索Docker Hub(Search)

docker search 命令允许通过CLI的方式搜索Docker Hub。该命令会搜索所有“NAME”字段中包含特定字符串的仓库

  • CLI(Command Line Interface)即“命令行界面”
  • “NAME”字段是仓库名称,包含了Docker ID,或者非官方仓库的组织名称
  • 例如,执行docker search ubuntu命令的结果:
  • 上面返回的镜像中既有官方的也有非官方的。我们可以使用
    --filter "is-official=true"使返回内容只显示官方镜像。
  • 也可以使用--filter "is-automated=true"只显示自动创建的仓库。
  • 默认情况下,Docker只返回25行结果。但是可以指定选项--limit的参数来增加返回内容行数,最多为100行。

分层

  • Docker镜像由一些松耦合的只读镜像层组成
  • docker的镜像文件能做U盘启动盘吗_docker的镜像文件能做U盘启动盘吗_02

  • Docker负责堆叠这些镜像层,并且将它们表示为单个统一的对象
  • 下图展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层中的文件7是文件5的一个更新版本。这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。
  • docker的镜像文件能做U盘启动盘吗_docker的镜像文件能做U盘启动盘吗_03

  • 在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合
  • Docker通过存储引擎 (新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。
  • 下图展示了系统视角的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。

共享镜像层

  • 多个镜像之间会共享镜像层。这样可以有效节省空间并提升性能。
  • Docker在Linux上支持很多存储引擎。每个存储引擎都有自己的镜像分层镜像层共享以及写时复制(CoW)技术的具体实现。但是,其最终效果和用户体验是完全一致的。
    下图展示了拉取两个镜像的过程:

    注意那些以Already exists 结尾的行,这从侧面验证了共享镜像层机制。

分发散列值(Distribution Hash)

散列值(Hash)也被称为摘要(Digest)

  • 在推送和拉取镜像的时候,都会对镜像层进行压缩来节省网络带宽以及仓库二进制存储空间。但是压缩会改变镜像内容,这意味着镜像的内容散列值在推送或者拉取操作之后,会与镜像内容不相符。
  • 为避免该问题,每个镜像层同时会包含一个分发散列值(Distribution Hash)。这是一个压缩版镜像的散列值,当从镜像仓库服务拉取或者推送镜像的时候,其中就包含了分发散列值,该散列值会用于校验拉取的镜像是否被篡改过。
  • 该模型也解决了随机生成的镜像ID镜像层ID可能冲突的问题。

多层架构镜像

  • 为了避免每次拉取镜像都需要手动对应主机架构,多架构镜像(Multi-architecture Image)出现了。
  • 实现方式:
  • Docker会维护一个称为 Manifest 列表的结构来管理多个镜像的不同平台和架构的版本。
  • Manifest列表是指某个镜像标签支持的架构列表。其支持的每种架构,都有自己的Manifest定义,其中列举了该镜像的构成。
  • 以Golang 官方镜像为例。 图左侧是Manifest列表,其中包含了该镜像支持的每种架构。Manifest列表的每一项都有一个箭头,指向具体的Manifest,其中包含了镜像配置和镜像层数据。
  • 实践验证:

    解释:
    docker container run --rm golang go version命令:启动容器
  • --rm选项:在容器退出后自动删除容器(可选)
  • golang参数:镜像库
  • go version参数:启动后执行的命令
  • 当在其它架构主机的docker上执行该命令时,结果将不再是go version go1.21.3 linux/amd64
    假如使用64位Windows,结果将会是go version go1.21.3 windows/amd64这体现了多层架构镜像的功能。

删除(Remove)

Remove 的缩写是 rm

  • 可以通过docker image rm命令从Docker主机删除镜像。
  • 该操作会试图删除镜像以及相关的镜像层。对于被多个镜像共享的镜像层,只有当全部依赖该镜像层的镜像都被删除后,该镜像层才会被删除。
  • 当镜像存在关联的容器时,不允许删除,除非使用-f选项。
  • 删除全部镜像:
    docker image rm $(docker image ls -q) -f
  • $是 shell中的特殊字符,表示命令替换(command substitution)
    命令替换允许将命令的输出作为命令行中的一个值进行替换。
    -q意为quiet(静默模式),使docker image ls命令只输出镜像ID
  • $(docker image ls -q) 参数:所有镜像的ID
  • -f选项:强制