第3章 Docker 镜像
3.1镜像基础
3.1.1 镜像简介
镜像是一种轻量级、可执行的独立软件包,也可以说是一个精简的操作系统。镜像中包含应用软件及应用软件的运行环境。具体来说镜像包含运行某个软件所需的所有内容,包括代码、库、环境变量和配置文件等。几乎所有应用,直接打包为 Docker 镜像后就可以运行。
由于镜像的运行时是容器,容器的设计初衷就是快速和小巧,所以镜像通常都比较小,镜像中不包含内核,其共享宿主机的内核;镜像中只包含简单的 Shell,或没有 Shell
3.1.2 镜像仓库分类
镜像中心中存储着大量的镜像仓库 Image Repository,每个镜像仓库中包含着大量相关镜像。根据这些镜像发布者的不同,形成了四类不同的镜像仓库。
-
Docker Official Image
Docker 官方镜像仓库。该类仓库中的镜像由 Docker 官方构建发布,代码质量较高且安全,有较完善的文档。该类仓库中的镜像会及时更新。一般常用的系统、工具软件、中间件都有相应的官方镜像仓库。例如,Zookeeper、Redis、Nginx 等。官方镜像仓库的名称**<repository>一般直接为该类软件的名称<software-name>**。
-
Verified Publisher
已验证发布者仓库。该类仓库中的镜像由非 Docker 官方的第三方发布。但该第三方是由 Docker 公司审核认证过的,一般为大型企业、团体或组织。审核通过后,Docker 公司会向其颁发“VERIFIED PUBLISHER”标识。这种仓库中镜像的质量还有有保证的。除了官方镜像仓库,其它都是非官方镜像仓库。非官方镜像仓库名称**<repository>一般由发布者用户名与软件名称两部分构成,形式为:<username>/<software-name>**。
-
Sponsored OSS
由 Docker 公司赞助开发的镜像仓库。该类仓库中的镜像也由非 Docker 官方的第三方发布,但该镜像的开发是由 Docker 公司赞助的。该类型的第三方一般为个人、团队或组织。这种仓库中镜像的质量也是有保证的
-
无认证仓库
没有以上任何标识的仓库。这种仓库中镜像的质量良莠不齐,质量上无法保证,在使用时需谨慎。
3.1.3 第三方镜像中心
镜像中心默认使用的都是 Docker 官方的 Docker Hub。不过,镜像中心是可配置的,可以使用指定的第三方镜像中心。对于第三方镜像中心中的仓库名称**<repository>由三部分构成:<domain-name>/<username>/<software-name>。其中的< domain-name >**指的是第三方镜像中心的域名或 IP。
3.1.4 镜像定位
对于任何镜像,都可通过**<repository>:<tag>进行唯一定位。其中<tag>一般称为镜像的版本号。<tag>中有一个比较特殊的版本——latest。如果不指定,默认<tag>**即为 latest。不过,虽然其字面意思是最新版,一般其也的确存放的是最新版,但并不能保证其真的就是最新版。
3.2 镜像相关命令
如果不确定命令作用,可以使用help命令进行查看
docker --help
docker version --help
3.2.1 docker pull
-
基本用法
通过 docker pull 命令可以将指定的镜像从 docker hub 拉取到本地。如果没有指定镜像则会抛出一个 Error。例如,下面的命令是拉取 zookeeper 的 3.7 版
docker pull zookeeper:3.7
下载完成,通过images查看下载成功文件镜像,
注意:如果不带版本号则默认下载lastest版本
-
DIGEST进行获取
digest,是镜像内容的一个 Hash 值,即所谓的 Content Hash(内容散列)。只要镜像内容发生了变更,其内容散列值就一定会发生改变。注意,digest 是包含前面的 sha256 的,表示该 digest 的产生所采用的 Hash 算法是 SHA256。使用该拉取方式的具体场景或用途,后面会详解。
docker pull zookeeper:@sha256:c7a6a6ea6a1413ca3c13e987a4f9a1d6d2ba62b1837c3b356875842c64458b73
注意:使用DIGEST拉取镜像,他的TAG列不会有内容
-
加上选项-q 后就可简化拉取过程中的日志输出。
docker pull -q redis
3.2.2 docker images
-
基础用法
通过 docker images 命令可查看本地所有镜像资源信息。这些镜像会按照镜像被创建的时间由近及远排序。
REPOSITORY:镜像仓库名称TAG:镜像版本号
IMAGE ID:镜像的唯一标识
CREATE:镜像的创建时间
SIZE:镜像大小
-
查看指定镜像
docker images 可以查看指定镜像的信息
docker images zookeeper
-
查看完整镜像 ID
默认的 docker images 显示的镜像 id 是经过截取后的显示结果,仅显示了前 12 位。使用 --no-trunc 参数后显示的是完成的镜像 id。
docker images --no-trunc
-
查看镜像 digest
–digests选项可以查看所有镜像或指定镜像的digest信息。关于digest后面会详细学习。
docker images --digests
-
仅显示镜像 ID
-q 选项可仅显示本地所有镜像的 ImageID。该主要是将来与其它命令联合使用。
docker images -q
-
过滤镜像
-f 选项用于过滤指定条件的镜像。下面例举一些常用的过滤条件。例如
docker images -f dangling=true
dangling=true 用于过滤出悬虚镜像,即没有 Repository 与 Tag 的镜像。对于悬虚镜像的REPOSITORY 与 TAG,显示的是**<none>**。
-f before 用于列举出本地镜像中指定镜像创建时间之前创建(CREATED)的所有镜像。
-f since 用于列举出本地镜像中指定镜像创建时间之后的创建(CREATED)的所有镜像。
-f reference 用于列举出<repository>:<tag>与指定表达式相匹配的所有镜像,只查询官方的镜像
docker images -f before=hello-world docker images -f since=hello-world docker images -f reference=centos:* docker images -f reference=*:lastest
-
格式化显示
该选项用于格式化输出 docker images 的内容,格式需要使用 GO 模板指定。例如
docker images --format {{.Repository}}:{{.Tag}}:{{.Size}}
3.2.3 docker search
-
基础用法
通过 docker search 命令可以从 docker hub 上查看指定名称的镜像。
docker search tomcat
之前版本还有另一个属性,AUTOMATED
AUTOMATED 表示当前镜像是否是“自动化镜像”。什么是自动化镜像?就是使用 Docker Hub 连接一个包含 Dockerfile 文件(专门构建镜像用的文件)的 GitHub 仓库或 Bitbucket 仓库的源码托管平台,然后 Docker Hub 就会自动根据 Dockerfile 内容构建镜像。这种构建出的镜像会被标记为 AUTOMATED,这种构建镜像的方式称为 Trusted Build(受信构建)。只要 Dockerfile文件内容发生变化,那么 Docker Hub 就会构建出新的镜像。
-
过滤检索结果
用于过滤查询结果。例如,下面的是仅查询出官方提供的镜像。
docker search tomcat --filter-official=true
-
限制检索数量
默认 docker search 显示 25 条检索结果,可通过–limit 选项来指定显示的结果数量。
docker search tomcat --limit=5
-
到 hub 官网查看
以上检索方式与从 docker hub 官网 https://hub.docker.com 查看是一样的,但没有官网查看的直观
3.2.4 docker rmi
-
基本用法
rmi,remove images。该命令用于删除指定的本地镜像。镜像通过**<repository>:<tag>**指定。如果省略要删除镜像的 tag,默认删除的是 lastest 版本
docker rmi hello-world
-
删除多个镜像
docker rmi 命令可一次性删除多个镜像,多个要删除的镜像间使用空格分隔。
docker rmi hello-world zookeeper:3.7 ......
-
通过 ImageID 删除镜像
docker rmi 也可通过 ImageID 指定要删除的镜像
docker rmi feb5d9fea6a5
-
强制删除镜像
默认情况下,对于已经运行了容器的镜像是不能删除的,必须要先停止并删除了相关容器然后才能删除其对应的镜像。不过,也可以通过添加-f 选项进行强制删除。
docker rmi -f hello-world
-
删除所有镜像
使用组合命令删除所有镜像。当然,如果不携带-f 选项,则不会删除已打开容器的镜像
docker rmi -f $(docker images -q)
3.2.5 导出/导入镜像
我们在本地生成一个镜像,想将其导出后在另一电脑上使用,则可通过导出/导入镜像来完成。
-
导出镜像 save
docker save 命令用于将一个或多个镜像导出为 tar 文件。例如,下面的命令是将 busybox与 hello-world 镜像导出到当前/root 目录的 my.tar 文件中。
# 使用root用户进入到根目录 cd ~ docker save -o export.tar busybox:latest hello-world:latest # 这种方式导出也可以 docker save busybox:latest hello-world:latest > export.tar
-
导入镜像 load
docker load -i export.tar
运行完毕后,可以看到 buxybox 与 hello-world 两个镜像都恢复了。
3.3 镜像分层
3.3.1 什么是分层
Docker 镜像由一些松耦合的只读镜像层组成,Docker Daemon 负责堆叠这些镜像层,并将它们关联为一个统一的整体,即对外表现出的是一个独立的对象。
通过 docker pull 命令拉取指定的镜像时,每个 Pull complete 结尾的行就代表下载完毕了一个镜像层。例如,下面的 redis:latest 镜像就包含 6个镜像层,其中第一个镜像层已经存在,其余5个正常下载。
3.3.2 为什么分层
采用这种分层结构的优势很多,例如,每个分层都是只读的,所有对分层的修改都是以新分层的形式出现,并不会破坏原分层内容;再如,每个分层只记录变更内容,所以有利于节省存储空间等。
不过,分层结构的最大的好处是,在不同镜像间实现资源共享,即不同镜像对相同下层镜像的复用。对于 docker pull 命令,其在拉取之前会先获取到其要拉取镜像的所有 ImageID,然后在本地查找是否存在这些分层。如果存在,则不再进行拉取,而是共享本地的该分层。大大节点的存储空间与网络带宽,提升了拉取效率。
3.3.3 镜像层构成
每个镜像层由两部分构成:镜像文件系统与镜像 json 文件。这两部分具有相同的 ImageID。镜像文件系统就是对镜像占有的磁盘空间进行管理的文件系统,拥有该镜像所有镜像层的数据内容。而镜像 json 文件则是用于描述镜像的相关属性的集合,通过 docker inspect [镜像]就可以直观看到。
3.3.4 镜像 FS 构成
一个 docker 镜像的文件系统 FS 由多层只读的镜像层组成,每层都完成了特定的功能。而这些只读镜像层根据其位置与功能的不同可分为两类:基础镜像层与扩展镜像层。
-
基础镜像层
所有镜像的最下层都具有一个可以看得到的基础镜像层 Base Image,基础镜像层的文件系统称为根文件系统 rootfs。
而 rootfs 则是建立在 Linux 系统中看不到的引导文件系统bootfs 之上。
-
扩展镜像层
在基础镜像层之上的镜像层称为扩展镜像层。顾名思义,其是对基础镜像层功能的扩展。在 Dockerfile 中,每条指令都是用于完成某项特定功能的,而每条指令都会生成一个扩展镜像层。
-
容器层
一旦镜像运行了起来就形成了容器,而容器就是一个运行中的 Linux 系统,其也是具有文件系统的。容器的这个文件系统是在 docker 镜像最外层之上增加了一个可读写的容器层,对文件的任何更改都只存在于容器层。因此任何对容器的操作都不会影响到镜像本身。
容器层如果需要修改某个文件,系统会从容器层开始向下一层层的查找该文件,直到找到为止。
任何对于文件的操作都会记录在容器层。例如,要修改某文件,容器层会首先把在镜像层找到的文件 copy 到容器层,然后再进行修改。删除文件也只会将存在于容器层中的文件副本删除。
可以看出,Docker 容器就是一个叠加后的文件系统,而这个容器层称为 Union File System,联合文件系统。
3.3.5 LinuxOS 启动过程(扩展)
现代操作系统都是 C/S 模式的微内核架构的,由两大部分构成:内核(Server)与服务模块(Client)。
Linux 的 bootfs 文件系统由两部分构成:bootloader 与 kernel。各个容器中的 rootft 就是由宿主机的 kernel 驱动的
3.4 镜像摘要 digest
每个镜像都有一个长度为 64 位的 16 进制字符串作为其摘要 digest
3.4.1 查看摘要
在 docker pull 镜像结束后会给出该拉取的镜像的摘要 digest。
通过 docker inspect 命令可以查看指定镜像的详细信息。其中就包含该镜像的摘要信息。
通过 docker images --digests 命令也可以查看到镜像的摘要信息。
3.4.2 摘要是什么
摘要,即 digest,是镜像内容的一个 Hash 值,即所谓的 Content Hash(内容散列)。只要镜像内容发生了变更,其内容散列值就一定会发生改变。也就是说,一个镜像一旦创建完毕,其 digest 就不会发生改变了,因为镜像是只读的。
Docker 默认采用的 Hash 算法是 SHA256,即 Hah 值是一个长度为 256 位的二进制值。Docker 使用 16 进制表示,即变为了长度为 64 位的字符串。
3.4.3 摘要有何用
摘要的主要作用是区分相同:的不同镜像。
例如镜像 xxx:2.8 在生产运行过程中发现存在一个 BUG。现对其进行了修复,并使用原标签将其 push 回了仓库,那么原镜像被覆盖。但生产环境中遗留了大量运行中的修复前镜像的容器。此时,通过镜像标签已经无法区分镜像是修复前的还是修复后的了,因为它们的标签是相同的。此时通过查看镜像的 digest 就可以区分出修改前后版本,因为内容发生了变化,digest 一定会变。
为了确保再次拉取到的是修复后的镜像,可通过 digest 进行镜像拉取。其用法是:docker pull <repository>@<digest>
下面的例子是,先查出 hello-world 镜像的 digest,然后将该镜像删除,然后再通过digest 对其进行拉取。
不过,不方便的是,镜像的摘要需要由运维人员在本地进行手工维护。
3.4.4 分发散列值
在 push 或 pull 镜像时,都会对镜像进行压缩以减少网络带宽和传输时长。但压缩会改变镜像内容,会导致经过网络传输后,镜像内容与其 digest 不相符。出现问题。为了避免该问题,Docker 又为镜像配置了 Distribution Hash(分发散列值)。在镜像被压缩后立即计算分发散列值,然后使该值随压缩过的镜像一同进行发送。在接收方接收后,立即计算压缩镜像的分发散列值,再与携带的分发散列值对比。如果相同,则说明传输没有问题
3.5 多架构镜像
3.5.1 什么是多架构镜像
Multi-architecture Image,即多架构镜像,是某<repository>中的某<tag>镜像针对不同操作系统/系统架构的不同镜像实现。即多架构镜像中包含的镜像的<repository>:<tag>都是相同的,但它们针对的操作系统/系统架构是不同的
3.5.2 多架构镜像原理
无论用户使用的是什么操作系统/系统架构,其通过 docker pull 命令拉取到的一定是针对该操作系统/系统架构的镜像,无需用户自己考虑操作系统/系统架构问题。Docker Hub 能够根据提交 pull 请求的 Docker 系统的架构自动选择其对应的镜像。
在 Docker Hub 中,镜像的多架构信息保存在 Manifest 文件中。在拉取镜像时,Docker会随着 pull 命令将当前 Docker 系统的 OS 与架构信息一并提交给 Docker Hub。Docker Hub 首先会根据镜像的<repository>:<tag>查找是否存在 Manifest。
如果不存在,则直接查找并返回<repository>:<tag>镜像即可;如果存在,则会在 Manifest 中查找是否存在指定系统/架构的镜像。如果存在该系统/架构,则根据 Manifest 中记录的地址找到该镜像的位置。
3.5.3 镜像历史信息查看 history
docker history centos:02