写在前面

镜像是Docker三大核心概念中最重要的一部分,而Docker运行容器前需要本地存在对应的镜像,如果镜像不存在,Docker会尝试从默认的镜像仓库中下载(默认使用Docker Hub公共注册服务器的仓库),用户也可以通过配置来使用自定义的镜像仓库,笔者在前面就自定义了镜像仓库。

既然镜像这么重要,那么本篇就围绕镜像这一核心概念来具体介绍相关操作:(1)如何使用pull命令从Docker Hub仓库中下载镜像到本地;(2)如何查看本地已有的镜像信息和管理镜像标签;(3)如何在远端仓库中使用search命令进行搜索和过滤;(4)如何删除镜像标签和镜像文件;(5)如何创建用户定制的镜像并且保存为外部文件;(6)如何往Docker Hub仓库中推送自己的镜像。

获取镜像

镜像是运行容器的前提,因此首先是需要获取镜像,开发者可以使用docker [image] pull命令直接从官方的Docker Hub网站上进行获取,该命令的格式为docker [image] pull NAME[:TAG],其中NAME是镜像仓库名称,用来区分镜像,而TAG则是镜像的标签,一般用来表示版本信息,因此通常情况下描述一个镜像需要使用”名称+标签”这一格式。

举个例子,获取一个Ubuntu18.04系统的基础镜像可以使用如下命令:

1
[envythink@localhost ~]$ docker pull ubuntu:18.04

运行结果如下所示:

对于Docker镜像来说,如果后面不显式指定TAG,则默认会选择latest标签,也就是会下载仓库中最新版本的镜像。

此时上面的命令可以修改为:

1
[envythink@localhost ~]$ docker pull ubuntu

其实也就相当于执行docker pull ubuntu:latest命令。请注意,镜像的latest标签是最新版的,因此可能是不稳定的,所以在生产环境中一定不能使用默认的latest标签。

细心的你可能发现了在下载过程中,镜像文件是由若干层(layer)组成,像171857c49d0f这样的字符串其实就是该层的唯一id(完整的id包括256比特,64个十六进制字符组成)。使用docker pull命令下载镜像的时候,里面会输出镜像各层的信息,当不同的镜像包含相同的层时,本地仅存储层的一份内容,这无疑可以减少存储空间。

现在有一个问题,就是在不同的镜像服务器的情况下,可能会出现镜像重名的情况。也就是说,其实镜像的仓库名称中还应该添加仓库地址(register,注册服务器)作为前缀,如果你之前使用的是默认的官方DockerHub地址,就可以忽略该前缀。

举个例子,使用docker pull ubuntu:18.04命令其实就相当于执行docker pull register.hub.docker.com/ubuntu:18.04命令,即从默认的注册服务器DockerHub Register中的ubuntu仓库来下载标记为18.04的镜像。

由于官方镜像仓库在国外,因此访问速度是非常慢的,通常是从非官方仓库下载,此时需要在仓库名称前指定完整的仓库地址。举个例子,假设从网易蜂巢的镜像源来下载ubuntu:18.04的镜像,此时可以使用的命令如下:

1
2
3
4
5
docker pull hub.c.163.com/public/ubuntu:18.04
````
当然这个pull命令支持添加一些选项参数,如`-a`或者`--all-tags`它的值可以是true或者false,表示是否获取仓库中的所有镜像,默认肯定是否。`--disable-content-trust`参数表示取消镜像的内容校验,默认是真。

前面也说过官方镜像仓库在国外,所以访问速度是非常慢的,同时为了避免每次执行命令前都添加register地址,因此可以使用镜像代理服务来加速Docker镜像的获取过程。CentOS系统只需在`/etc/docker/daemon.json`文件中添加一行配置即可,如下所示:

{“registry-mirrors”: [“http://f1361db2.m.daocloud.io"]}

1
2
3
当然也可以在启动配置参数中添加`--registry-mirror=proxy_URL`来指定镜像代理服务器地址。

为了后续演示的需要,这里先使用`docker pull ubuntu:18.04`命令来下载一个18.04版本的ubuntu系统镜像,然后就使用该镜像创建一个容器,并在其中运行bash命令,执行输出“Hello World”的命令,如下所示:

[envythink@localhost ~]$ docker run -it ubuntu bash
root@cae6035fd1b2:/# echo “Hello World”
Hello World
root@cae6035fd1b2:/# exit

1
2
3
### 查看镜像信息
##### 使用images命令列出所有镜像
开发者可以使用`docker images`或者`docker image ls`命令来列出本地主机上已有的所有镜像的基本信息,如下所示:

[envythink@localhost ~]$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 9140108b62dc 8 hours ago 72.9MB
haproxy latest 4e531c2cb889 5 months ago 92.4MB
pxc latest a6a51beefff1 9 months ago 494MB
percona/percona-xtradb-cluster latest a6a51beefff1 9 months ago 494MB

1
2
3
4
5
6
7
8
9
10
11
12
13
接下来详细解释一下上述列出的信息:
- REPOSITORY:表示来自哪个仓库。这里的ubuntu则表示ubuntu系列的基础镜像。
- TAG:表示镜像的标签。这里的latest表示最新的版本信息,请注意标签只是标记,并不能标识镜像内容。
- IMAGE ID:表示镜像的ID,注意这是镜像的唯一标识ID。如果两个镜像的ID相同,说明它们指向了同一个镜像,只是具有不同的标签名称而已。
- CREATED:表示创建时间,也就是镜像最后的更新时间。
- SIZE:表示镜像大小,一般来说比较优秀的镜像其体积就越小。

由于镜像ID非常重要,它唯一标识了镜像,因此在使用镜像ID的时候,可以使用该ID的前若干个字符组成的可区分串来代替完整的ID。TAG信息只是用来标记来自同一仓库的不同镜像,如ubuntu仓库的多个镜像,则使用TAG消息来区分不同的发行版本,如18.04、20.04等。SIZE信息只是表示该镜像的逻辑体积大小,实际上由于相同的镜像层本地只会存储一份,因此物理上占用的存储空间会小于各镜像的逻辑体积之和。

当然images也支持多种子命令,如`-a`或者`--all=true|false`表示列出所有(包含临时文件)镜像大小,默认是fasle。`-f`或者`--filter=[]`参数,它表示过滤列出的镜像,如dangling=true等,它只显示没有被使用的镜像,也可指定带有特定标注的镜像等。更多的子命令可以使用`man docker-images`命令来进行查看。

##### 使用tag命令来添加镜像标签
一般来说,为了后续工作中使用特定镜像,会使用`docker tag`命令来为本地镜像任意添加新的标签。举个例子,给之前下载的ubuntu镜像添加一个新的`envyubuntu:latest`标签,如下所示:

[envythink@localhost ~]$ docker tag ubuntu:latest envyubuntu:latest

1
然后再次使用`docker images`命令来列举出本地主机上的镜像信息,可以看到多了一个`envyubuntu:latest`标签的镜像,如下所示:

[envythink@localhost ~]$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
envyubuntu latest 9140108b62dc 8 hours ago 72.9MB
ubuntu latest 9140108b62dc 8 hours ago 72.9MB
haproxy latest 4e531c2cb889 5 months ago 92.4MB
pxc latest a6a51beefff1 9 months ago 494MB
percona/percona-xtradb-cluster latest a6a51beefff1 9 months ago 494MB

1
2
3
4
5
6
7
这样后续就可以直接使用`envyubuntu:latest`来表示这个镜像,细心的你可能发现这个`envyubuntu:latest`镜像和之前的`ubuntu:latest`镜像两者的镜像ID一样,因此可以知道`docker tag`只是给原来的镜像添加了一个新的快捷访问方式,也就是CentOS中的链接。
##### 使用inspect来查看详细信息
如果我们需要查看某个镜像的详细信息,可以使用`docker inspect [image]`命令来进行查看:

![](https://upload-images.jianshu.io/upload_images/8964398-41cd44e2d323eaaa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

可以发现上面返回的是一个JSON格式的对象,但是显示的内容太多,如果只想其中某一项内容时,可以使用`-f`参数来进行过滤,如只想获取镜像的Architecture信息:

[envythink@localhost ~]$ docker inspect envyubuntu:latest -f .Architecture
amd64

1
2
3
4
##### 使用history命令查看镜像历史
前面也说过镜像文件由多个层组成,现在问题来了,如何知道每个层的具体内容?可以使用history命令来列出各层的创建信息。

举个例子,可以使用如下命令来查看envyubuntu:latest镜像的创建过程:

[envythink@localhost ~]$ docker history envyubuntu:latest
IMAGE CREATED CREATED BY SIZE COMMENT
9140108b62dc 8 hours ago /bin/sh -c #(nop) CMD [“/bin/bash”] 0B
8 hours ago /bin/sh -c mkdir -p /run/systemd && echo ‘do… 7B
8 hours ago /bin/sh -c [ -z “$(apt-get indextargets)” ] 0B
8 hours ago /bin/sh -c set -xe && echo ‘#!/bin/sh’ > /… 811B
8 hours ago /bin/sh -c #(nop) ADD file:da80f59399481ffc3… 72.9MB

1
2
3
4
5
6
可以发现上面一些过长的命令被自动截断了,如果想查看完整的输出命令,可以使用`--no-trunc`选项参数来设置。

### 搜索镜像
开发者可以使用`docker search [option] keyword`命令来搜索Docker Hub官方仓库中的镜像。该命令支持的选项参数如下:(1)`-f`或者`--filter filter`表示过滤输出内容;(2)`--format string`表示格式化输出内容;(3)`--limit int`表示限制输出结果的个数,默认为25个;(4)`--no-trunc`表示不截断输出结果。

这些选项参数都不用记忆,用的使用时候使用`man docker-search`命令查看一下即可。举个例子,搜索官方提供的镜像中包含nginx关键字的镜像,如下所示:

[envythink@localhost ~]$ docker search –filter=is-official=true nginx
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
nginx Official build of Nginx. 13785 [OK]

1
再举个例子,搜索官方提供的镜像中所有收藏数超过8的包含tensorflow关键字的镜像:

[envythink@localhost ~]$ docker search –filter=stars=8 tensorflow
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
tensorflow/tensorflow Official Docker images for the machine learn… 1766
jupyter/tensorflow-notebook Jupyter Notebook Scientific Python Stack w/ … 236
tensorflow/serving Official images for TensorFlow Serving (http… 97
xblaster/tensorflow-jupyter Dockerized Jupyter with tensorflow 54 [OK]
rocm/tensorflow Tensorflow with ROCm backend support 54
floydhub/tensorflow tensorflow 25 [OK]
bitnami/tensorflow-serving Bitnami Docker Image for TensorFlow Serving 14 [OK]
opensciencegrid/tensorflow-gpu TensorFlow GPU set up for OSG 12

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
从返回结果中可以看到有关镜像的基本信息,如镜像名称、描述、收藏数(受欢迎程度)、是否官方创建、是否自动创建等,注意默认的输出结果是按照星级评价来进行排序的。

其实这些在`man docker-search`命令中都有介绍:

![](https://upload-images.jianshu.io/upload_images/8964398-7471685fe5908d76.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

### 删除和清理镜像
##### 使用标签删除镜像
开发者可以使用`docker rmi`或者`docker image rm`命令来删除镜像,相应的命令格式为`docker rmi IMAGE[IMAGE...]`,其中IMAGE可以是标签或者ID。

该命令支持的选项参数如下:(1)`-f`或者`--force`表示强制删除镜像,即使有容器依赖它;(2)`-no-prune`表示不清理未带标签的父镜像。

同样这些选项参数都不用记忆,用的时候使用`man docker-image-rm`命令查看一下即可。

举个例子,将之前创建的envyubuntu:latest镜像给删除,相应的命令如下:

[envythink@localhost ~]$ docker image rm envyubuntu:latest
Untagged: envyubuntu:latest

1
2
3
请注意我们删除上述envyubuntu:latest镜像的时候,本地的ubuntu:latest镜像是不受到任何影响的。当某一个镜像拥有多个标签的时候,此时执行`docker image rm`或者是`docker rmi`命令的时候,只是删除了该镜像多个标签中的指定标签而已,并不影响镜像文件,也就是仅仅删除了这个镜像的一个标签副本而已。

此时开发者可以确认一下,本地的ubuntu:latest镜像依旧也是存在的:

[envythink@localhost ~]$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 9140108b62dc 9 hours ago 72.9MB
haproxy latest 4e531c2cb889 5 months ago 92.4MB
pxc latest a6a51beefff1 9 months ago 494MB
percona/percona-xtradb-cluster latest a6a51beefff1 9 months ago 494MB

1
2
3
4
5
6
7
但是需要注意,如果这个镜像只剩下一个标签,那么此时执行`docker image rm`或者是`docker rmi`命令的时候就会删除这个镜像文件的所有文件层。
##### 使用镜像ID来删除镜像
前面说过当使用`docker image rm`或者是`docker rmi`命令的时候,其后面也是可以接镜像的ID(也可以是能进行区分的部分ID串前缀),此时会先尝试删除所有指向该镜像的标签,然后删除该镜像文件本身。因为多个标签指向的都是同一个镜像ID,所以最终肯定会删除该镜像本身。

但是需要注意,当有该镜像创建的容器存在时,镜像文件默认是无法被删除的。

举个例子,可以使用之前的ubuntu:latest镜像来创建一个简单的容器,并输出一句话:

[envythink@localhost ~]$ docker run ubuntu:latest echo “hello,I am envy”
hello,I am envy

1
接着使用`docker ps -a`命令来查看本机上存在的所有容器:

[envythink@localhost ~]$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fd56a307081b ubuntu:latest “echo ‘hello,I am en…” 24 seconds ago Exited (0) 23 seconds ago nostalgic_lewin

1
可以看到这个容器就是基于前面的ubuntu:latest镜像而创建出来的,不过它的状态是退出而已。但是开发者是无法删除该ubuntu:latest镜像的,Docker会提示有容器正在运行,无法删除,如下所示:

[envythink@localhost ~]$ docker image rm ubuntu:latest
Error response from daemon: conflict: unable to remove repository reference “ubuntu:latest” (must force) - container cae6035fd1b2 is using its referenced image 9140108b62dc

1
且它告诉我们,如果想强行删除镜像,可以使用`-f`参数:

[envythink@localhost ~]$ docker image rm -f ubuntu:latest
Untagged: ubuntu:latest
Untagged: ubuntu@sha256:bc2f7250f69267c9c6b66d7b6a81a54d3878bb85f1ebb5f951c896d13e6ba537

1
2
3
但是笔者并不建议使用`-f`参数来强制删除一个存在容器依赖的镜像,正确的做法是先删除依赖该镜像的所有容器,再删除镜像。

第一步,查看本地已经存在的容器,如下所示:

[envythink@localhost ~]$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fd56a307081b ubuntu:latest “echo ‘hello,I am en…” 13 minutes ago Exited (0) 13 minutes ago nostalgic_lewin

1
第二步,删除容器ID为fd56a307081b的容器,注意删除容器使用的命令是`docker rm`:

[envythink@localhost ~]$ docker rm fd56a307081b
fd56a307081b

1
第三步,查看当前本地主机上的所有镜像信息:

[envythink@localhost ~]$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
envyubuntu latest 9140108b62dc 9 hours ago 72.9MB
ubuntu latest 9140108b62dc 9 hours ago 72.9MB

1
第四步,使用镜像ID来删除镜像,此时会正常打印输出各层的信息:

[envythink@localhost ~]$ docker image rm ubuntu:latest
Untagged: ubuntu:latest
Deleted: sha256:bc2f7250f69267c9c6b66d7b6a81a54d3878bb85f1ebb5f951c896d13e6ba567
Deleted: sha256:bc937250f69267c9c6b66d7b6a81a54d38726785f1ebb5f951c896d13e6b0978

1
2
3
4
5
6
7
8
### 清理镜像
一般来说,Docker使用一段时间后,系统中可能会遗留一些临时的镜像文件,以及一些没有使用的镜像,此时可以使用`docker image prune`命令来进行清理。

该命令支持的选项参数如下:(1)`-f`或者`--force`表示强制删除镜像,而不进行提示确认;(2)`-a`或者`--all`表示删除所有无用镜像,不仅仅是临时镜像;(3)`-filter filter`表示只清理符合给定过滤器的镜像。

同样这些选项参数都不用记忆,用的时候使用`man docker-image-prune`命令查看一下即可。

举个例子,开发者可以使用如下命令来自动清理临时的遗留镜像文件层,最后会提示释放的存储空间:

[envythink@localhost ~]$ docker image prune -f

1
2
3
4
5
6
7
8
9
10
11
### 创建镜像
创建镜像有三种方法:(1)基于已有镜像的容器创建;(2)基于本地模板导入;(3)基于Dockerfile创建。

##### 基于已有镜像的容器创建
基于已有镜像的容器创建,主要是使用`docker commit [container]`命令,其对应的格式为`docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]`,主要的选项参数格式为:(1)`-a`或者`--author=""`表示作者信息;(2)`-c`或者`--change=[]`表示提交的时候执行Dockerfile指令,包括`CMD|ENTRYPOINT|ENV|EXPOSE|LABEL|ONBUILD|USER|VOLUME|WORKDIR`等;(3)`-m`或者`--message=""`表示提交信息;(4)`-p`或者`--pause=true`表示提交时暂停容器的运行。

同样这些选项参数都不用记忆,用的时候使用`man docker-commit`命令查看一下即可:

![](https://upload-images.jianshu.io/upload_images/8964398-82b3d0c6f4761046.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

接下来通过一个例子,来演示如何使用`docker commit [container]`命令创建一个新镜像。第一步,启动已经存在的ubuntu:latest镜像,并在其中进行修改操作。如新建一个test文件,之后退出即可,相应的代码如下:

[envythink@localhost ~]$ docker run -it envyubuntu:latest /bin/bash
root@9dfcfb7dac63:/# touch test.txt
root@9dfcfb7dac63:/# exit

1
2
3
4
5
接着可以使用`docker ps -a`命令来查看一下当前所有容器的运行状况,如下所示:

![](https://upload-images.jianshu.io/upload_images/8964398-7cd2efff09ae2dc5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

请记住刚才我们创建的容器ID为9dfcfb7dac63,此时该容器与原envyubuntu:latest镜像相比,已经发生了变化,因此可以使用`docker commit [container]`命令来提交为一个新的镜像。注意提交的时候可以使用ID或者名称来指定容器,如:

[envythink@localhost ~]$ docker commit -m “Added a new file” -a “Docker Envy” 9dfcfb7dac63 test:0.1
sha256:71ea5620150363e696d187c8e139fcd1fc4ab809a26c3d6f20bcee1ae422f025

1
2
3
4
5
6
7
8
可以看到执行命令后会返回新创建的镜像的ID信息,此时使用`docker images`命令查看本地镜像时就可以发现新创建的镜像已经存在了,如下所示:

![](https://upload-images.jianshu.io/upload_images/8964398-855ae90a448e06bc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

##### 基于本地模板导入
用户也可以直接从一个操作系统模板文件中导入一个镜像,主要使用`docker import [container]`命令,其对应的命令格式为`docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]`。要直接导入一个镜像可以使用OpenVZ提供的模板来创建,也可以使用其他已导出的镜像模板来创建。

举个例子,本地已经存在了一个名为ununtu-18.04的模板压缩包,之后可以使用如下命令直接导入:

[envythink@localhost ~]$ cat ubuntu-18.04-x86_64-minimal.tar.gz | docker import - ubuntu:18.04

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
其对应的解释如下图所示:

![](https://upload-images.jianshu.io/upload_images/8964398-424968badc3a3d0e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

##### 基于Dockerfile创建
基于Dockerfile创建镜像是最常见的方式,Dockerfile是一个由一组指令组成的文本文件,其中的每条指令对应Linux中的一条命令,它可以利用给定的指令描述基于某个父镜像来创建新镜像。

Dockerfile结构大致分为4个部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。请注意Dockerfile的每行只支持一条指令,但是每条指令可以携带多个参数,支持使用以`#`号开头的注释。

接下来学习一些较为常用的Dockerfile操作指令,如下表所示:

指令|说明|
-|-|
FROM镜像|用于指定新镜像所基于的镜像,注意它必须是第一条指令|
MAINTAINER 名字|新镜像的维护人信息|
RUN 命令|在所基于的镜像上执行命令,并提交到新镜像中|
EXPOSE端口号|指定新镜像加载到Docker时开启的端口号|
ENV 环境变量 变量值|设置一个环境变量的值,之后的RUN会使用|
ADD 源文件/目录 目标文件/目录|将源文件复制到目标文件,源文件要与Docker位于同一目录下,或者为一个URL|
COPY 源文件/目录 目标文件/目录|将本地主机上的源文件/目录复制到目标地点,源文件/目录要与Dockerfile在同一目录下|
VOLUME["目录"]|在容器中创建一个挂载点|
USER 用户名 /UID| 指定运行容器时的用户|
WORKDIR 路径|为后续的RUN、CMD、ENTRYPOINT指定工作目录|
ONBUILD命令|指定所生成的镜像作为一个基础镜像时所要运行的命令|
CMD["要运行的程序","参数1","参数2"] |指定启动容器时运行的命令或脚本,只能有一条CMD命令,多条时只有最后一条被执行|

举个例子,接下来通过介绍基于envyubuntu:latest镜像来安装Python3,进而构成一个新的`python:3`镜像,相应的操作如下:

第一步,创建镜像工作目录并切换至该目录,在`/home/envythink`目录下新建pyhello目录,然后切换至该目录:

[envythink@localhost ~]$ mkdir pyhello
[envythink@localhost ~]$ cd pyhello/

1
第二步,在pyhello目录下新建Dockerfile文件,并在里面添加配置信息:

#基于ubuntu:latest镜像
FROM ubuntu:latest

#维护人的信息
LABEL version=”1.0” maintainer=”docker envy envyzhan@aliyun.com

#创建镜像时执行的脚本文件
RUN yum update && yum install -y python3

1
第三步,创建镜像。开发者可以使用`docker build [image] .`命令来创建镜像,编译成功后本地将多出一个`python:3`的镜像,如下所示:

docker build -t python:3 .

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
这样我们就通过上述命令创建出一个`python:3`的镜像。请注意该命令最后面有一个`.`号,请注意这个`.`号不是用来指定Dockerfile文件的所在位置,实际上使用`-f`参数来指定Dockerfile的路径。那么问题来了这个`.`号的作用是什么?

其实Docker在运行时分为Docker引擎(服务器守护进程)和客户端工具,而当我们使用docker各种命令的时候,其实就是在使用客户端工具与Docker引擎进行交互,而我们在使用`docker build`命令构建镜像时,其实这个过程是在Docker引擎内完成的,而不是在本地客户端。那么问题来了,如果开发者在Dockerfile中使用了类似于COPY、ADD等指令来操作文件时,Docker引擎是如何获取这些文件呢?

因此这里就有一个镜像构建上下文的概念,当构建镜像的时候,用户来指定构建镜像的上下文路径,而`docker build`命令会将这个路径下所有的文件都打包上传给Docker引擎,之后Docker引擎将这些内容展开,就能获取到所有指定上下文中的文件。

还记得前面在介绍COPY指令的时候,特别要求源文件要与Dockerfile在同一目录下,如`COPY ./hello.txt /test`命令,该命令并不是复制本地当前目录下的hello.txt文件,而是docker引擎中展开的构建上下文中的文件,所以如果复制的文件超出了docker引擎中展开的构建上下文的范围,那么docker引擎是无法找到那些文件。综上所述,上述`docker build .`命令中的`.`号是指在指定镜像构建过程中的上下文环境的目录。

在理解了这个镜像构建上下文以后,接下来思考这个`.dockerignore`文件的作用,如果你之前有使用过git,那么肯定可以知道`.gitignore`文件的作用,它用来配置需要忽略上传的文件或者文件夹信息,因此接着这个设计理念自然可以猜到这个`.dockerignore`文件就是用于指定在构建镜像过程中的上下文环境目录需要忽略的文件或者文件夹。

### 存出和载入镜像
接下来开始学习docker镜像的save和load子命令,开发者可以使用`docker save [image]`和`docker load [image]`命令来存出和载入镜像。
##### 存出镜像
开发者如果想导出镜像到本地,可以使用`docker save [image]`命令,同时该命令支持`-o`也就是`-output string`参数,用于指定导出镜像到某个文件中。

举个例子,将本地的envyubuntu:latest镜像导出到本地为envyubuntu_latest.tar,使用的命令如下:

[root@localhost envythink]# docker save -o envyubuntu_latest.tar envyubuntu:latest
[root@localhost envythink]# ls
envyubuntu_latest.tar

1
2
3
4
##### 载入镜像
开发者如果想将之前通过`docker save [image]`命令导出的tar文件再次导入到本地镜像库,可以使用`docker load [image]`命令,同时该命令支持`-i`也就是`-input string`参数,用于指定需要载入镜像的名称。

同样举个例子,将之前存出的envyubuntu_latest.tar文件导入镜像到本地镜像列表,使用的命令如下:

[root@localhost envythink]# docker load -i envyubuntu_latest.tar
Loaded image: envyubuntu:latest

1
当然了也可以使用输入重定向符号`<`,此时相应的命令为:

[root@localhost envythink]# docker load < envyubuntu_latest.tar
Loaded image: envyubuntu:latest

1
2
3
上面那种方式将导入镜像及其相关的元数据信息,里面包含标签等,当显示导入成功后,开发者可以使用`docker images`命令查看发现与原来的镜像是一样的。
### 上传镜像
接下来介绍docker镜像的push子命令,这个名称非常重要,也很实用。开发者可以使用`docker push [image]`命令来将本地镜像上传到仓库,默认上传到Docker Hub官方仓库,注意此过程需要用户登录,因此建议开发者都去Docker Hub官网注册一个账号,之后就可以上传自制的镜像。完整的命令格式如下所示:

docker push [image] NAME[:TAG] | [REGISTRY_HOST[:REGISTRY_PORT]/]NAME[:TAG]

1
举个例子,用户lichee想上传本地的ubuntu:latest镜像到Docker Hub官方仓库,可以先添加新的标签lichee/ubuntu:latest,然后使用这里的`docker push [image]`命令来上传镜像,如下所示:

[root@localhost envythink]# docker tag ubuntu:latest lichee/ubuntu:latest
[root@localhost envythink]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 9140108b62dc 2 weeks ago 72.9MB
lichee/ubuntu latest 9140108b62dc 2 weeks ago 72.9MB
[root@localhost envythink]# docker push lichee/ubuntu:latest
The push refers to repository [docker.io/lichee/ubuntu]
Sending image list

Please login prior to push:
Username:
Password:
Email:

请注意第一次上传镜像时,会提示需要输入用户名,密码和邮箱等信息,之后这些信息会存到本地的`~/.docker`目录下。

### 小结
本篇主要介绍了docker镜像相关的一些重要操作,如获取、查看、搜索、删除、创建、存出、载入、上传等,当然这些已经能满足大部分的工作场景,再必要的时候开发者可以使用`docker image help`命令来查看docker支持的镜像操作子命令。docker镜像是使用Docker的前提,也是最基本的资源,所以在平时使用过程中需要累积和定制自己的镜像文件,这一点对提高工作效率有着非常大的帮助。