欢迎您, 来到 宁时修博客.^_^

Docker系列3--Docker镜像

2018/11/18 言则行 Docker 546
Docker容器技术

一、Docker镜像(Image)

    操作系统分为内核和用户空间。在Linux 上内核启动后,会挂载  root  文件系统提供用户空间支持。而 Docker 镜像(Image),就相当于是一个  root  文件系统。比如官方镜像  ubuntu:16.04  就包含了完整的一套Ubuntu 16.04 最小系统的  root  文件系统。

    Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。


二、Docker镜像分层存储

    镜像包含操作系统完整的  root  文件系统,体积庞大,因此在Docker 设计时,充分利用 Union FS 的技术,将其设计为分层存储的架构。镜像并非是像一个 ISO 那样的打包文件,镜像只是一个虚拟的概念,实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。

    镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,实际上该文件会一直跟随镜像。因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。

    分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。



三、使用镜像

    Docker 运行容器前需要本地存在对应的镜像,如果本地不存在,Docker 会从镜像仓库下载该镜像。


    1、获取镜像

    Docker Hub 上有大量的高质量的镜像可以用,网址:https://hub.docker.com/

    从 Docker 镜像仓库获取镜像的命令是  docker pull ,查看命令帮助:

$ docker pull --help

Usage:	docker pull [OPTIONS] NAME[:TAG|@DIGEST]

Pull an image or a repository from a registry

Options:
  -a, --all-tags                Download all tagged images in the repository
      --disable-content-trust   Skip image verification (default true)
  -q, --quiet                   Suppress verbose output

    命令格式有两种,不带仓库地址,默认从 Docker Hub上拉取镜像:

docker pull [选项] 仓库名[:标签]
docker pull [选项] [Docker Registry地址[:端口号]]/仓库名[:标签]


    Docker 镜像仓库(Docker Registry)地址:格式一般是  <域名/IP>[:端口号]  ,默认地址是 Docker Hub。

    仓库名:仓库名是两段式名称,即  <用户名>/<软件名>  。对于 Docker Hub,如果不给出用户名,则默认为  library  ,也就是官方镜像。

    如:

$ docker pull ubuntu:16.04
16.04: Pulling from library/ubuntu
18d680d61657: Pull complete 
0addb6fece63: Pull complete 
78e58219b215: Pull complete 
eb6959a66df2: Pull complete 
Digest: sha256:76702ec53c5e7771ba3f2c4f6152c3796c142af2b3cb1a02fce66c697db24f12
Status: Downloaded newer image for ubuntu:16.04


    上面的命令中没有给出 Docker 镜像仓库地址,因此从 Docker Hub 获取镜像。镜像名称是  ubuntu:16.04 ,表示 官方镜像  library/ubuntu 仓库中标签为  16.04  的镜像。

    从下载过程中体现镜像分层存储的概念,表明镜像由多层存储构成。下载也是一层一层的,并非单一文件。下载过程中给出了每一层的 ID 的前 12 位,下载结束后,给出该镜像完整的  sha256  的摘要,以确保下载一致性。

    每次下载镜像所看到的层 ID 以及  sha256 的摘要和这里的不同。是因为官方镜像是一直在维护的,有任何新的 bug,或者版本更新,都会进行修复再以原来的标签发布,这样可以确保任何使用这个标签的用户可以获得更安全、更稳定的镜像。


    2、运行镜像示例

    获取了镜像后,就能以镜像为基础启动并运行一个容器。

    以刚才拉取的 ubuntu:16.04  镜像为例,启动里面的  bash  并进行交互式操作:

$ docker run -it --rm ubuntu:16.04 bash
root@3cc3a263d78a:/#
root@3cc3a263d78a:/# cat /etc/os-release  
NAME="Ubuntu"
VERSION="16.04.5 LTS (Xenial Xerus)"
.............
root@3cc3a263d78a:/# exit
exit


    说明:

    docker run: Docker 启动并运行容器 的命令。

    -it :这是两个参数,一个是 -i:交互式操作,一个是 -t:分配一个终端。

    --rm:退出容器后将容器删除。默认退出容器后不删除容器,除非手动执行  docker rm  。使用  --rm  可以避免浪费空间。

    ubuntu:16.04  :用  ubuntu:16.04  这个镜像为基础来启动容器。

    bash  :放在镜像名后的是命令,启个交互式 Shell 。进入容器后,可以在 Shell 下操作,执行任何所需的命令。

    exit:退出容器。



    3、列出镜像

     列出已经下载的镜像:

$ docker image ls

或者

$ docker images

    镜像 ID 是镜像的唯一标识,一个镜像可以对应多个标签。同一镜像ID表示同一个镜像。


    镜像体积

    下载的镜像的所占用空间和在 Docker Hub 上看到的镜像大小不同。Docker Hub 中显示的是镜像压缩后的大小。在下载和上传过程中镜像是保持着压缩状态的,镜像下载到本地后,显示的是镜像各层展开后所占空间的总和,是本地磁盘空间占用的大小。

    docker image ls  列表中的镜像体积总和并非是所有镜像实际硬盘消耗。由于 Docker 镜像是多层存储结构,并且可以继承、复用,因此不同镜像可能会因为使用相同的基础镜像,从而拥有共同的层。Docker使用 Union FS,相同的层只需要保存一份,实际镜像硬盘占用空间可能要比列表镜像大小的总和小的多。

    以下命令查看镜像、容器、数据卷所占用的空间:

$ docker system df


    虚悬镜像

    有时候镜像列表中,可能存在没有仓库名、没有标签、显示  <none> 的镜像 。

    这种镜像原本是有镜像名和标签的,镜像发布新版本,重新 docker pull或 docker build 时,镜像名被转移到新镜像上,旧镜像上的名称、标签则被取消,成了<none>  。从而出现仓库名、标签为  <none>  的镜像,这类无标签镜像也被称为 虚悬镜像(dangling image)

    下面的命令专门显示这类镜像:

$ docker image ls -f dangling=true


    一般来说,虚悬镜像已经失去了存在的价值,可以随意删除,用下面的命令删除:

$ docker image prune


    中间层镜像

    为了加速镜像构建、重复利用资源,Docker 会利用 中间层镜像。默认的  docker image ls  列表中只会显示顶层镜像,加  -a  参数显示包括中间层镜像在内的所有镜像:

$ docker image ls -a

    这样会看到很多显示为<none>的镜像,与虚悬镜像不同,这些镜像很多都是中间层镜像,是其它镜像所依赖的镜像。这些镜像不应该删除,否则会导致上层镜像因为依赖丢失而出错。这些镜像也没必要删除,因为相同的层只会存一遍,而这些镜像是别的镜像的依赖,不会因为被列出来而多存了一份,某些时候会需要它们。只要删除那些依赖它们的镜像后,这些被依赖的中间层镜像也会被连带删除。


    列出部分镜像

    不加任何参数的 docker image ls  会列出所有顶级镜像,有时候只希望列出部分镜像。 

    根据仓库名列出镜像:

$ docker image ls ubuntu


    列出特定的某个镜像,也就是指定仓库名和标签:

$ docker image ls ubuntu:16.04


    docker image ls  支持强大的过滤器参数  --filter ,或者简写-f  。

    如:希望看到在  ubuntu:18.04  之后建立的镜像:

$ docker image ls -f since=ubuntu:18.04


    想查看某个镜像之前的镜像只需要把  since  换成  before  即可。

    如果镜像构建时,定义了  LABEL  ,可以通过  LABEL  来过滤。

$ docker image ls -f label=com.example.version=0.1


    以特定格式显示镜像

    docker image ls  会输出一个完整的表格,并非都会需要这些内容。

    比如,用  docker image ls  把所有的虚悬镜像的 ID 列出来,然后交给  docker image rm 命令作为参数来删除这些指定镜像,这个时候就用到  -q  参数。

$ docker image ls -q
4a689991aa24
7e10e8cb09ba


    --filter  配合  -q  产生出指定范围的 ID 列表,然后作为另一个  docker  命令的参数,针对这组数据成批的进行某种操作。

    对表格的结构不满意,希望自己组织列;或者不希望有标题,方便其它程序解析等,这就用到了 Go 的模板语法。

    如以下命令会列出只包含镜像ID和仓库名的镜像:

$ docker image ls --format "{{.ID}}: {{.Repository}}"
4a689991aa24: ubuntu
7e10e8cb09ba: ubuntu


    自己定义列,以含有标题行的表格等距显示:

$ docker image ls --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}"
IMAGE ID            REPOSITORY             TAG
4a689991aa24        ubuntu                 16.04
7e10e8cb09ba        ubuntu                 18.10


    4、删除本地镜像

    删除本地的镜像:

$ docker image rm IMAGE

    IMAGE 可以是  镜像短 ID  、 镜像长 ID  、 镜像名  或者  镜像摘要。


    用 ID、镜像名、摘要删除镜像。

    用镜像的完整 ID,也称为  长 ID ,来删除镜像。但是人工输入麻烦,更多的时候是用  短 ID  来删除镜像。 

    docker image ls  列出的已经是短 ID 了,一般取前3个字符以上,能足够区分镜像就可以了。

    如:删除某个镜像

$ docker image rm 7e1
Untagged: ubuntu:18.10
Untagged: ubuntu@sha256:ef5d78b10fcada65484b2dd9cd6e0704fba36021a101b2b52023a1566c4ebad4
Deleted: sha256:7e10e8cb09ba03e392d4546a631a8479e193e2f8fb68c2f95405cf39f0a59322
Deleted: sha256:226e715931cfccf71b326052ece9d4804c553aa6537f72acd124504ee905ec74
Deleted: sha256:ddc270d77a832a21b72b8e5f3514f1afbbfc3124db02571543f94481f84a6837
Deleted: sha256:3117fee3851c7ff4e7cab0381d30943277e2a7f16454854814bd4308e2c1ed9d
Deleted: sha256:f8aa66f3fe0dc030ea829621cf583caf7d5f2b19aaf57ff55b9898f0a5c2dc94


    用 镜像名 ,也就是  <仓库名>:<标签> ,来删除指定镜像:

$ docker image rm ubuntu:18.04
Untagged: ubuntu:18.04
Untagged: ubuntu@sha256:29934af957c53004d7fb6340139880d23fb1952505a15d69a03af0d1418878cb
Deleted: sha256:ea4c82dcd15a33e3e9c4c37050def20476856a08e59526fbe533cc4e98387e39
Deleted: sha256:2ac9356b41d2d032dc980b6ee2b2a911790a47b59b4fcfd92e52a0729a389403
Deleted: sha256:f19c7e29a7e3fbaf44997bab14791e3d3d26d689bc3e2e720a9d5d8a77f68d6c
Deleted: sha256:b951bb1959dc1a5dfeda46229b36b33c4cc01e3f682ee1b77af8dab1cc7cf8a3
Deleted: sha256:102645f1cf722254bbfb7135b524db45fbbac400e79e4d54266c000a5f5bc400


    更精确的是使用  镜像摘要  删除镜像:

$ docker image ls --digests

$ docker image rm ubuntu@sha256:3b811ac794645dfaa47408f4333ac6e433858ff16908965c68f63d5d315acf94
Untagged: ubuntu@sha256:3b811ac794645dfaa47408f4333ac6e433858ff16908965c68f63d5d315acf94


    Untagged 和 Deleted

    删除行为分为两类,一类是  Untagged  ,另一类是  Deleted  。

    镜像的唯一标识是其ID 和摘要,而一个镜像可以有多个标签。使用命令删除镜像的时候,实际上是在删除某个标签的镜像。

    所以首先做的是将满足要求的镜像的标签取消,这就是Untagged 信息。一个镜像可以对应多个标签,当删除了所指定的标签后,可能还有别的标签指向了这个镜像。如果是这种情况,那么  Delete 行为就不会发生。并非所有的  docker image rm  都会产生删除镜像的行为,可能只是取消了某个标签而已。

    当该镜像所有的标签都被取消了,该镜像很可能会失去了存在的意义,因此会触发删除行为。

    镜像是多层存储结构,因此在删除的时候也是从上层向基础层方向依次进行判断删除。镜像的多层结构让镜像复用变动非常容易,很有可能某个镜像正依赖于当前镜像的某一层。这种情况,依旧不会触发删除该层的行为。当没有任何层依赖当前层时,才会真实的删除当前层。这就是为什么明明没有别的标签指向这个镜像,但是它还是存在的原因,也是所删除的层数和 docker pull  看到的层数不一样的原因。

    除了镜像依赖,还有容器对镜像的依赖。如果有用这个镜像启动的容器存在(即使容器没有运行),同样不可以删除这个镜像。容器是以镜像为基础,再加一层读写层组成的多层存储结构去运行的。该镜像如果被这个容器所依赖,删除必然会导致故障。应先将不需要的容器删除,再删除镜像。



    用 docker image ls 命令来配合

    使用  docker image ls -q  来配合使用  docker image rm ,成批的删除镜像。其它过滤镜像列表的方式都可以。

    删除所有名为  redis  的镜像:

$ docker image rm $(docker image ls -q redis)
Untagged: redis:latest
Untagged: redis@sha256:f30f134bd475d451ce3207fb128bcef8ff87d0f520a39cac0c4ea285819c42a9
Deleted: sha256:415381a6cb813ef0972eff8edac32069637b4546349d9ffdb8e4f641f55edcdd
Deleted: sha256:2a5a57892da005399e6ce7166c5521cdca43a07872f23995e210bde5dae2640e
Deleted: sha256:85e1fabde4fd4d6df993de44ef3e04d15cd69f9d309c0112c6a5054a6dc8351a
Deleted: sha256:2725175b62c7479ee209454110e8293080b9711e4f0a29219e358d1afba88787
Deleted: sha256:7ae66985fd3a3a132fab51b4a43ed32fd14174179ad8c3041262670523a6104c
Deleted: sha256:bf45690ef12cc54743675646a8e0bafe0394706b7f9ed1c9b11423bb5494665b
Deleted: sha256:237472299760d6726d376385edd9e79c310fe91d794bc9870d038417d448c2d5


    删除在某个镜像之前下载或构建的镜像:

$ docker image rm $(docker image ls -q -f before=nginx:v3)
点赞
说说你的看法

所有评论: (0)

# 加入组织

1、用手机QQ扫左侧二维码

2、搜Q群:1058582137

3、点击 宁时修博客交流群