概述

如果曾经做过 VM 管理员,则可以把 Docker 镜像理解为 VM 模板,VM 模板就像停止运行的 VM,而 Docker 镜像就像停止运行的容器;而作为一名研发人员,则可以将镜像理解为类(Class)。
首先需要先从镜像仓库服务中拉取镜像。常见的镜像仓库是Docker Hub,但是也存在其他镜像仓库服务。
拉取操作会将镜像下载到本地 Docker 主机,可以使用该镜像启动一个或者多个容器。
镜像由多个层组成,每层叠加之后,从外部看来就如一个独立的对象。镜像内部是一个精简的操作系统(OS),同时还包含应用运行所必须的文件和依赖包。
因为容器的设计初衷就是快速和小巧,所以镜像通常都比较小。
前面多次提到镜像就像停止运行的容器(类)。实际上,可以停止某个容器的运行,并从中创建新的镜像。
在该前提下,镜像可以理解为一种构建时(build-time)结构,而容器可以理解为一种运行时(run-time)结构,如下图所示。

镜像和容器关系

上图从顶层设计层面展示了镜像和容器间的关系。通常使用docker container run和docker service create命令从某个镜像启动一个或多个容器。
一旦容器从镜像启动后,二者之间就变成了互相依赖的关系,并且在镜像上启动的容器全部停止之前,镜像是无法被删除的。尝试删除镜像而不停止或销毁使用它的容器,会导致出错。

容器通常比较小

容器目的就是运行应用或者服务,这意味着容器的镜像中必须包含应用/服务运行所必须的操作系统和应用文件。
但是,容器又追求快速和小巧,这意味着构建镜像的时候通常需要裁剪掉不必要的部分,保持较小的体积。
例如,Docker 镜像通常不会包含 6 个不同的 Shell 让读者选择——通常 Docker 镜像中只有一个精简的Shell,甚至没有 Shell。
镜像中还不包含内核一一容器都是共享所在Docker主机的内核。所以有时会说容器仅包含必要的操作系统(通常只有操作系统文件和文件系统对象)。

镜像仓库

Docker镜像存储在镜像仓库服务(Image Registry)当中。
Docker客户端的镜像仓库服务是可配置的,默认使用Docker Hub。
镜像仓库服务包含多个镜像仓库(Image Repositroy);镜像仓库中可以包含多个镜像。
下图展示了包含 3 个镜像仓库的镜像仓库服务,其中每个镜像仓库都包含一个或多个镜像。如图:

官方和非官方镜像仓库

Docker Hub 也分为官方仓库(Official Repository)和非官方仓库(Unofficial Repository)。
顾名思义,官方仓库中的镜像是由 Docker 公司审查的。这意味着其中的镜像会及时更新,由高质量的代码构成,这些代码是安全的,有完善的文档和最佳实践。
非官方仓库更像江湖侠客,其中的镜像不一定具备官方仓库的优点,但这并不意味着所有非官方仓库都是不好的!非官方仓库中也有一些很优秀的镜像。
大部分流行的操作系统和应用在 Docker Hub 的官方仓库中都有其对应镜像。这些镜像很容易找到,基本都在 Docker Hub 命名空间的顶层。

阿里的容器镜像服务

介绍这个的目的是,我们日常针对于我们开发的应用来说,如果要同时部署多台服务器,部署一台服务其实是很累的,每台服务器都要从本地打成镜像到服务器上,而别的服务器很多公共的应用都是一样的,这个时候就没有必要一个个的去打成镜像到每台服务器上,我们可以把这些公共的镜像抽取出来由单独的一个容器仓库去管理,只需要一份,其它服务器上的镜像都是第一台服务器上镜像的复制品,这样容错性更大,更方便。
可以购买阿里的容器镜像服务,让本地创建镜像并推送到阿里的仓库。

拉取镜像

Docker主机安装后,本地并没有镜像。

docker image pull xxx

是下载镜像的命令,镜像从远程镜像仓库服务的仓库中下载。
默认情况下,镜像会从Docker Hub的仓库中拉取。

docker image pull alpine:latest

该命令会从Docker Hub的alpine仓库中拉取标签为latest的镜像。

Linux Docker主机本地镜像仓库通常位于:
/var/lib/docker/

查看镜像

docker images 或者 docker image ls

镜像命名和标签

镜像的命名是:名称:tag
从官方仓库拉取镜像时,格式如下:

docker image pull <repository>:<tag>

查看tag的方式可以直接访问默认的docker镜像仓库地址去查找:
https://hub.docker.com/u/library
例如:

如果不指定tag,默认将拉取最新的,等同于:

docker image pull <repository>:latest

镜像结构解析

可以通过 docker image inspect 命令查看,
例如:
docker image inspect redis:latest

"RootFS": {"Type": "layers",
"Layers": [
"sha256:d000633a56813933cb0ac5ee3246cf7a4c0205db6290018a169d7cb096581046",
"sha256:bdad86443e47c5665683ac41c1f24f28479d830d7e3cc47d0a337ee5166c7714",
"sha256:6a7992ac480029d82b7dbb757d16fe5d023aa283ed32b52267cd1fe9e6b73c49",
"sha256:be43d2475cf809c0f2ec31950e849d0f888f3121970fd99196a11a903f8c3820",
"sha256:be5818ef2907adfe19be14bf66647b5fb5a2029143f9297f8ce1ff1fd1d35753"
]
}

输出显示该镜像包含 5 个镜像层。只不过输出内容中使用了镜像的 SHA256 散列值来标识镜像层。
其实docker镜像由一些松耦合的只读镜像层组成,如下所示。

镜像层如何产生

Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上再创建的镜像层。
举一个简单的例子,假如基于 Ubuntu Linux 16.04 创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加 Python 包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。

在天津额外的镜像层的同时,镜像始终保持是当前所有镜像层的组合,下图例举一个简单的例子,每个镜像层包含3个文件,二镜像包含了来自两个镜像层的6个文件。

下图中展示了一个稍微复杂的三层镜像,在外部看了镜像只有6个文件,这是因为最上层的文件7是文件5的一个更新版本。

这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。
Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。
Linux上可以的存储引擎有AUFS、Overlay2、Device Mapper、Btrfs以及ZFS。每种存储引擎都基于Linux中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。

Docker 在 Windows 上仅支持 windowsfilter 一种存储引擎,该引擎基于 NTFS 文件系统之上实现了分层和 CoW。
下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。

镜像散列值(摘要)

  • 从Docker1.10版本开始,镜像就是一系列松耦合的独立层的集合。
  • 镜像本身就是一个配置对象,其中包含了镜像层的列表以及一些元数据信息。
  • 镜像层才是实际数据存储的地方(比如文件等,镜像层之间是完全独立的,并没有从属某个镜像集合的概念)。
  • 镜像的唯一标识是一个加密ID,即配置对象本身的散列值。每个镜像层也由一个加密ID区分,其值为镜像层本身内容的散列值。
  • 这意味着修改镜像的内容或其中任意的镜像层,都会导致加密散列值的变化。所以,镜像和其镜像层都是不可变的,任何改动都能很轻松的被辨别。
  • 这就是所谓的内容散列(Content Hash)。
    到目前为止,事情都很简单。但是接下来的内容就有点儿复杂了。
  • 在推送和拉取镜像的时候,都会对镜像层进行压缩来节省网络带宽以及仓库二进制存储空间。
  • 但是压缩会改变镜像内容,这意味着镜像的内容散列值在推送或者拉取操作之后,会与镜像内容不相符!这显然是个问题。
    例如,在推送镜像层到 Docker Hub 的时候,Docker Hub 会尝试确认接收到的镜像没有在传输过程中被篡改。
    为了完成校验,Docker Hub 会根据镜像层重新计算散列值,并与原散列值进行比较。
    因为镜像在传输过程中被压缩(发生了改变),所以散列值的校验也会失败。
    为避免该问题,每个镜像层同时会包含一个分发散列值(Distribution Hash)。这是一个压缩版镜像的散列值,当从镜像仓库服务拉取或者推送镜像的时候,其中就包含了分发散列值,该散列值会用于校验拉取的镜像是否被篡改过。
    这个内容寻址存储模型极大地提升了镜像的安全性,因为在拉取和推送操作后提供了一种方式来确保镜像和镜像层数据是一致的。
    该模型也解决了随机生成镜像和镜像层 ID 这种方式可能导致的 ID 冲突问题。

多架构镜像

Docker 最值得称赞的一点就是使用方便。例如,运行一个应用就像拉取镜像并运行容器这么简单。无须担心安装、依赖或者配置的问题。开箱即用。

但是,随着 Docker 的发展,事情开始变得复杂——尤其是在添加了新平台和架构之后,例如 Windows、ARM 以及 s390x。

这是会突然发现,在拉取镜像并运行之前,需要考虑镜像是否与当前运行环境的架构匹配,这破坏了 Docker 的流畅体验。

多架构镜像(Multi-architecture Image)的出现解决了这个问题!

Docker(镜像和镜像仓库服务)规范目前支持多架构镜像。这意味着某个镜像仓库标签(repository:tag)下的镜像可以同时支持 64 位 Linux、PowerPC Linux、64 位 Windows 和 ARM 等多种架构。
简单地说,就是一个镜像标签之下可以支持多个平台和架构。下面通过实操演示该特性。

为了实现这个特性,镜像仓库服务 API 支持两种重要的结构:Manifest 列表(新)和 Manifest。
Manifest 列表是指某个镜像标签支持的架构列表。其支持的每种架构,都有自己的 Mainfest 定义,其中列举了该镜像的构成。
下图使用 Golang 官方镜像作为示例。图左侧是 Manifest 列表,其中包含了该镜像支持的每种架构。

Manifest 列表的每一项都有一个箭头,指向具体的 Manifest,其中包含了镜像配置和镜像层数据。

在具体操作之前,先来了解一下原理。

假设要在 Raspberry Pi(基于 ARM 架构的 Linux)上运行 Docker。

在拉取镜像的时候,Docker 客户端会调用 Docker Hub 镜像仓库服务相应的 API 完成拉取。

如果该镜像有 Mainfest 列表,并且存在 Linux on ARM 这一项,则 Docker Client 就会找到 ARM 架构对应的 Mainfest 并解析出组成该镜像的镜像层加密 ID。
然后从 Docker Hub 二进制存储中拉取每个镜像层。
下面的示例就展示了多架构镜像是如何在拉取官方 Golang 镜像(支持多架构)时工作的,并且通过一个简单的命令展示了 Go 的版本和所在主机的 CPU 架构。
需要注意的是,两个例子都使用相同的命令 docker container run。不需要告知 Docker 具体的镜像版本是 64 位 Linux 还是 64 位 Windows。

示例中只运行了普通的命令,选择当前平台和架构所需的正确镜像版本是有由 Docker 完成的。

64 位 Linux 示例如下。$ docker container run --rm golang go versionUnable to find image 'golang:latest' locally
latest: Pulling from library/golang
723254a2c089: Pull complete
<Snip>
39cd5f38ffb8: Pull complete
Digest: sha256:947826b5b6bc4...
Status: Downloaded newer image for golang:latest
go version go1.9.2 linux/amd6464 位 Windows 示例如下。PS> docker container run --rm golang go versionUsing default tag: latest
latest: Pulling from library/golang
3889bb8d808b: Pull complete
8df8e568af76: Pull complete
9604659e3e8d: Pull complete
9f4a4a55f0a7: Pull complete
6d6da81fc3fd: Pull complete
72f53bd57f2f: Pull complete
6464e79d41fe: Pull complete
dca61726a3b4: Pull complete
9150276e2b90: Pull complete
cd47365a14fb: Pull complete
1783777af4bb: Pull complete
3b8d1834f1d7: Pull complete
7258d77b22dd: Pull complete
Digest: sha256:e2be086d86eeb789...e1b2195d6f40edc4
Status: Downloaded newer image for golang:latest
go version go1.9.2 windows/amd64

前面的操作包括从 Docker Hub 拉取 Golang 镜像,以容器方式启动,执行 go version 命令,并且输出 Go 的版本和主机 OS / CPU 架构信息。

每个示例的最后一行都展示了 go version 命令的输出内容。可以看到两个示例使用了完全相同的命令,但是 Linux 示例中拉取的是 linux/amd64 镜像,而 Windows 示例中拉取的是 windows/amd64 镜像。

所有官方镜像都支持 Manifest 列表。但是,全面支持各种架构的工作仍在推进当中。

创建支持多架构的镜像需要镜像的发布者做更多的工作。同时,某些软件也并非跨平台的。在这个前提下,Manifest 列表是可选的——在没有 Manifest 列表的情况下,镜像仓库服务会返回普通的 Manifest。

删除镜像

当读者不再需要某个镜像的时候,可以通过:

docker image rm

命令从 Docker 主机删除该镜像。其中,rm 是 remove 的缩写。
删除操作会在当前主机上删除该镜像以及相关的镜像层。这意味着无法通过 docker image ls 命令看到删除后的镜像,并且对应的包含镜像层数据的目录会被删除。
但是,如果某个镜像层被多个镜像共享,那只有当全部依赖该镜像层的镜像都被删除后,该镜像层才会被删除。

Docker镜像常用命令总结

docker image pull是下载镜像的命令。镜像从远程镜像仓库服务的仓库中下载。

默认情况下,镜像会从 Docker Hub 的仓库中拉取。

docker image pull alpine:latest命令会从 Docker Hub 的 alpine 仓库中拉取标签为 latest 的镜像。

docker image ls列出了本地 Docker 主机上存储的镜像。可以通过 --digests 参数来查看镜像的 SHA256 签名。

docker image inspect命令非常有用!该命令完美展示了镜像的细节,包括镜像层数据和元数据。

docker image rm用于删除镜像。

docker image rm alpine:latest命令的含义是删除 alpine:latest 镜像。当镜像存在关联的容器,并且容器处于运行(Up)或者停止(Exited)状态时,不允许删除该镜像。

Docker镜像-Docker相关推荐

  1. 创建Python数据分析的Docker镜像+Docker自定义镜像commit,Dockerfile方式解析+pull,push,rmi操作...

    实例解析Docker如何通过commit,Dockerfile两种方式自定义Dcoker镜像,对自定义镜像的pull,push,rmi等常用操作,通过实例创建一个Python数据分析开发环境的Dock ...

  2. Docker学习(三)-----Docker镜像常用命令

    六.Docker镜像 镜像是Docker的三大组件之一 Docker运行容器前需要本地存在对应的镜像,如果本地不存,Docker会从镜像仓库下载 6.1Docker获取镜像 6.1.1查找镜像 我们可 ...

  3. Docker镜像基本使用

    使用 Docker 镜像 Docker 运行容器前需要本地存在对应的镜像,如果本地不存在该镜像,Docker 会从镜像仓库下载该镜像. 获取镜像 docker pull [选项] [Docker Re ...

  4. 简单谈谈Docker镜像的使用方法_docker

    在上篇文章(在Docker中搭建Nginx服务器)中,我们已经介绍了如何快速地搭建一个实用的Nginx服务器.这次我们将围绕Docker镜像(Docker Image),介绍其使用方法.包括三部分: ...

  5. 简述Docker镜像、容器、仓库概念

    Docker镜像 Docker镜像(Image)类似于虚拟机的镜像,可以将他理解为一个面向Docker引擎的只读模板,包含了文件系统. 例如:一个镜像可以完全包含了Ubuntu操作系统环境,可以把它称 ...

  6. docker 根据标签删除镜像_10 个 Docker 镜像安全最佳实践

    <Docker 镜像安全最佳实践速查表[1]>列举了 10 个诀窍和指南,确保更安全和更高质量的 Docker 镜像处理.此外,还可以检视有关 Docker 安全的新报告<Docke ...

  7. docker第二天:管理docker镜像与容器(上)

    docker镜像下载官网:https://hub.docker.com/explore/ 众所周知国内访问外国页面都是非常的卡顿的,导致使用docker pull拉取镜像时,下载速度很缓慢,甚至失败. ...

  8. docker镜像和容器区别

    docker镜像 docker容器,容器是用镜像创建的运行实例

  9. docker打包镜像上传_Jenkins | 一键打包部署Spring Boot 应用的Docker镜像

    一.前言 1.本文主要内容 将在项目中实际使用到的相关东西整理记录一波,同时可以方便其他同学在使用到的时候参考一下(自己也备忘),有不对的地方,欢迎指出~~ Docker部署SpringBoot 项目 ...

最新文章

  1. Leetcode(18)-四数之和
  2. openssl私有ca创建
  3. WAMPSERVER安装之笑话
  4. 语义分割 - 数据集准备
  5. 39 网络相关函数(七)——live555源码阅读(四)网络
  6. java 文件目录_Java——文件及目录File操作
  7. email邮件中 内嵌iframe_Python+Selenium执行结果,封装函数,用Python自动发送SMTP邮件...
  8. Linux系统服务之dhcp
  9. python 提取最小外接矩形_python给人脸带上口罩(简单版)
  10. 2016年5月26日晚上(妙味课堂js基础-2笔记二(DOM))
  11. Element UI el-table 表格多选的使用
  12. 类模板使用示例(二)类模板整体特化
  13. PhpSpreadsheet 生成圆饼图
  14. 2021-02-14金蝶KIS旗舰版从采购订单下推外购入库单使用说明,金蝶盘点机PDA仓库条码管理
  15. 2021年中国石油市场回顾及2022年行业发展趋势分析预测:2021年石油需求震荡修复,石油对外依存度首次下降,预计2022年石油需求7.35亿吨[图]
  16. Linux系统管理----centos7系统进程管理
  17. asterisk cdr mysql_在asterisk中添加CDR sqlite支持
  18. Bug 20186278 - crfclust.bdb Becomes Huge Size Due to Sudden Retention Change (文档 ID 20186278.8)
  19. 坑爹的No matching method
  20. Hexo-NexT主题添加评论功能(来必力、Hypercomments、畅言、友言)

热门文章

  1. 服务器怎么查服务端数据
  2. 【MySQL】函数提取字符串中的数字
  3. 安装Linux时grub2安装失败,尝试安装Ubuntu作为计算机唯一的操作系统时,我收到错误'grub-install/dev/sda failed'。 - Ubuntu问答...
  4. 【机房重构】-UNL图回顾
  5. HDU 1873 - 看病要排队 ← 优先队列
  6. 正则:\b 匹配出一个单词的小天使
  7. 根据前序和中序推出后序
  8. vba 邮件body html,Excel VBA中的Outlook电子邮件和签名 - .Body vs .HTMLbody
  9. PostgreSQL 一复合查询SQL优化例子 - (多个exists , 范围检索 , IN检索 , 模糊检索 组合)...
  10. 会员管理小程序实战开发教程(六)-会员查询功能