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