1 引言

将docker与汽车生产线类比,如果说docker引擎是汽车生产车间,那么容器就是最终的产品——汽车,而本节要介绍的镜像就如同汽车设计图纸,其重要性不言而喻——只有有了设计图(镜像),才能生产汽车(汽车)。

2 镜像管理

2.1 获取镜像

刚安装好的docker里面是没有镜像的,但我们可以从开源的镜像仓库中下载镜像,docker官方提供的docker hub就是最大的一个docker仓库,里面有全球各地用户提供的各式各样的docker镜像供我们下载使用。在下载镜像之前,我们先来熟悉一下docker镜像下载命令和相关知识。
docker [image] pull 仓库名[:标签]
上行命令就是我们常用的docker镜像下载命令,其中,仓库名指定我们要从哪个仓库下载的镜像,标签是指镜像便签,通常指代的是版本信息,例如:ubuntu:16.04和ubuntu:18.04分别指代ubuntu仓库中16.04版本的ubuntu和18.04版本的ubuntu镜像。命令中image和标签参数可加可不加,当省略标签参数时,即指使用默认的latest标签,也就是说,下载指定仓库中的的最新版本。下载ubuntu最新版本:
$ docker pull ubuntu
注意:latest标签会动态跟随最新版本变更,这意味着镜像内容也是动态变化的,所以出于稳定性考虑,在生产环境中,不要在生产环境中使用latest标签。
pull命令默认从官方docker hub仓库中下载镜像,所以,上行命令中并没有指定完整仓库名,如果需要从其他非官方仓库下载镜像,则需要指定完整仓库名,例如,从网易非常的镜像源中下载ubuntu:18.04镜像:
$ docker pull hub.c.163.com/public/ubuntu18.04

2.2 查看及查找镜像

(1)查看本机上所有镜像基本信息:
$ docker images
(2)查看指定镜像详细信息
$ docker [image] inspect 仓库名:标签
例:查看上文中下载的ubuntu:18.04镜像详细信息
$ docker inspect ubuntu:18.04
(3)查看镜像各层创建信息
$ docker history 仓库名:标签
(4)搜索镜像
$ docker search [选项] 关键词
命令中,可以通过选项指定输出内容格式、数量、部分过滤条件等,关键词是指搜索关键字。
例如:查找ubuntu相关镜像
$ docker search ubuntu

2.3 删除镜像

删除镜像可以使用一下两种命令格式:
$ docker rmi 仓库名:标签或镜像id
$ docker image rm 仓库名:标签或镜像id
定位一个镜像可以通过"仓库名:标签"和镜像id两种方式,所以,在删除镜像时,我们也可以通过这两种方式来指定要删除的镜像,也即是上面两行命令中的仓库名:标签或镜像id。
删除镜像时需要注意,每次运行删除镜像命令事实上只是删除指定镜像的一个标签,只有当该镜像仅有一个标签时,使用删除镜像命令才会真正删除镜像。啥?一个镜像还有多个标签,没错,人类除了真名都还有网名、小名、外号呢。在演示删除镜像前,我们先尝试给镜像添加标签。
先查看本地有哪些镜像:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 18.04 7698f282e524 7 days ago 69.9MB
hello-world latest fce289e99eb9 4 months ago 1.84kB
给hello-World镜像添加一个标签:
$ docker tag hello-world:latest bye-world:8000
如果成功,没有任何提示,再次查看本地所有镜像:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 18.04 7698f282e524 7 days ago 69.9MB
bye-world 8000 fce289e99eb9 4 months ago 1.84kB
hello-world latest fce289e99eb9 4 months ago 1.84kB
看,出现了bye-world镜像,但我们可没有新建或者下载镜像,这就是我们刚才为hello-World创建的新标签,看着他们相同的镜像id你就知道他们是同一个镜像了。接下来尝试删除镜像:
$ docker rmi bye-world:8000
Untagged: bye-world:8000
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 18.04 7698f282e524 7 days ago 69.9MB
hello-world latest fce289e99eb9 4 months ago 1.84kB
果然如上文所说,bye-world:8000被删除了,但事实上它所指向的镜像被没有被真正删除,因为这个镜像还有一个标签存在。我们继续参数删除hello-world:latest镜像:
$ docker rmi hello-world:latest
Error response from daemon: conflict: unable to remove repository reference "hello-world:latest" (must force) - container 53c855a9d4a9 is using its referenced image fce289e99eb9
懵逼了,失败了,咋回事?因为尚有依赖于该镜像的容器存在,所以产生冲突。这时候要删除镜像,就必须添加-f参数,强制执行:
$ docker rmi -f hello-world:latest
Untagged: hello-world:latest
Untagged: hello-world@sha256:6f744a2005b12a704d2608d8070a494ad1145636eeb74a570c56b94d94ccdbfc
Deleted: sha256:fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 18.04 7698f282e524 7 days ago 69.9MB
只剩下一个ubuntu镜像,证明删除成功。

3 创建镜像

创建镜像的方法有三种:基于已有镜像的容器创建镜像、基于dockerfile创建、基于本地模板导入,这里我们只介绍前两种。

3.1 基于已有镜像容器创建镜像

基于已有镜像容器创建镜像需通过docker commit命令,命令格式如下:
$ docker commit [选项] 容器名或容器id [<仓库名>[:<标签名>]]
在使用docker commit命令创建镜像之前,我们先得有一个容器。
$ docker run -it ubuntu:18.04 /bin/bash
root@001b647aad4e:/#
docker run命令时使用镜像创建一个容器的命令,具体个参数什么含义,我们后面继续学习。可以看到,运行这一命令后,启动了一个id为001b647aad4e的容器,记住这一id,后面要用到。
我们继续在这一容器里git环境:
root@001b647aad4e:/# git --version
bash: git: command not found
可以看到,刚创建的容器里面刚开始是没有git的,我们安装一个:
root@001b647aad4e:/# apt-get update
root@001b647aad4e:/# apt install git
root@001b647aad4e:/# git --version
git version 2.17.1
可以看到,git安装成功。
退出容器,然后使用刚才的容器创建一个镜像。
root@001b647aad4e:/# exit
exit
$ docker commit -m "Add git in ubuntu18.04" -a "God" 001b647aad4e ubuntu_git:1.0
sha256:30e6c7c480dc44743f0f030f4904089fb8568ad2333f8de3a22c4f6a71fdb451
成功创建镜像,并返回了镜像id信息。
查看一下本地镜像:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu_git 1.0 30e6c7c480dc About a minute ago 189MB
ubuntu 18.04 7698f282e524 8 days ago 69.9MB
可以看到,镜像创建成功。以ubuntu_git为基础,创建一个容器,新容器也会有git环境,换句话说,docker commit相当于是对001b647aad4e进行了一次备份。
docker commit命令创建镜像虽然简单直观,但是在时间生产中并不建议用,因为使用docker commit命令创建的镜像无法追踪镜像的创建过程,造成镜像创建过程难以重复、维护困难,且容易出现镜像臃肿的镜像。所以,在实际应用中,更推荐使用下一小节要说到的使用dockerfile文件创建镜像的方法。

3.2 使用dockerfile创建镜像

dockerfile是一个文本文件,通过每一条指令构建镜像一层,或者说dockerfile每一条指令定义了镜像每一层如何构建,所以,使用dockerfile创建镜像的过程完全是透明的、可重复的,很好的你不了docker commit命令创建镜像的不足。
还以上一小节中定制一个包含git环境的镜像为例,不过这次我们使用dockerfile来创建。
首先创建一个目录作为创建镜像的上下文路径,并进入该目录:
$ mkdir ubuntu_dockerfile_git
$ cd ubuntu_dockerfile_git/
然后创建创建dockerfile文件:
$ touch dockerfile
开始编辑dockerfile,在dockerfile内写入一下内容:
FROM ubuntu:18.04

RUN apt-get update \
&& apt-get install -y git \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
先来解释一下上面写入dockerfile文件的内容:
FROM ubuntu:18.04的意思是以ubuntu:18.04镜像为基础来构建新的镜像,每一个新的镜像,都必须有一个基础镜像,FROM命就是用于指定基础镜像,而且需要注意的是,FROM命令必须位于整个过程的第一行。
第二行的RUN命令是用来执行命令行操作。那为何上面的RUN命令执行的4条命令行操作都用一个RUN命令来执行呢?事实上,每个命令行操作都使用一个RUN命令来执行也不会出错,但,上面提到过,dockerfile中,每一条指令都会创建一层,如果每一条命令行操作的用一个RUN命令执行,这种写法就创建了4层,创建出来的镜像就显得臃肿,也增加了部署时间,另外从功能上来说,这4条命令行操作都是为了安装一个git,没必要拆分。docker镜像总层数不得操作127层。
现在可以用创建好的dockerfile文件创建镜像了,使用的是docker build命令,命令格式如下:
docker build [选项] <上下文路径/URL>
假定我们将要创建镜像的镜像名为ubuntu_dockerfile_git,使用docker build如下:
$ docker build -t ubuntu_dockerfile_git:1.0 .
在一大段的输出之后可以看到:
Successfully built 6e703a3b11e2
Successfully tagged ubuntu_dockerfile_git:1.0
说明镜像创建成功。再次查看本地镜像:
$ docker images
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu_dockerfile_git 1.0 6e703a3b11e2 About a minute ago 163MB
ubuntu_git 1.0 30e6c7c480dc 20 hours ago 189MB
ubuntu 18.04 7698f282e524 9 days ago 69.9MB
果然有刚创建的ubuntu_dockerfile_git,我们用它来创建一个容器:
$ docker run -it ubuntu_dockerfile_git:1.0 /bin/bash
root@18c03ae954ab:/# git --version
git version 2.17.1
可以看到,刚启动的容器里果然有git。
dockerfile是用的最多的一种镜像创建方法,涉及到的内容也较多,在上面的应用中,我们只介绍了FROM、RUN指令,除此之外还有COPY、CMD、ADD等众多指令没有涉及到,大家可以参考纯洁的微笑前辈的这篇博客,写得很详细且通俗易懂。

4 总结

本篇博文介绍了对docker镜像的管理,包括镜像查看、删除、创建等操作。但作为docker的核心内容,镜像管理可绝不仅仅包含这点点只是,例如镜像存出、载入、上传等内容就没有涉及到。本文只作为入门阶段抛砖引玉吧。
 
 
 
 
05-29 11:35