使用Docker镜像
写在前面
镜像是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 | docker pull hub.c.163.com/public/ubuntu:18.04 |
{“registry-mirrors”: [“http://f1361db2.m.daocloud.io"]}
1 | 当然也可以在启动配置参数中添加`--registry-mirror=proxy_URL`来指定镜像代理服务器地址。 |
[envythink@localhost ~]$ docker run -it ubuntu bash
root@cae6035fd1b2:/# echo “Hello World”
Hello World
root@cae6035fd1b2:/# exit
1 | ### 查看镜像信息 |
[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 | 接下来详细解释一下上述列出的信息: |
[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 | 这样后续就可以直接使用`envyubuntu:latest`来表示这个镜像,细心的你可能发现这个`envyubuntu:latest`镜像和之前的`ubuntu:latest`镜像两者的镜像ID一样,因此可以知道`docker tag`只是给原来的镜像添加了一个新的快捷访问方式,也就是CentOS中的链接。 |
[envythink@localhost ~]$ docker inspect envyubuntu:latest -f .Architecture
amd64
1 | ##### 使用history命令查看镜像历史 |
[envythink@localhost ~]$ docker history envyubuntu:latest
IMAGE CREATED CREATED BY SIZE COMMENT
9140108b62dc 8 hours ago /bin/sh -c #(nop) CMD [“/bin/bash”] 0B
1 | 可以发现上面一些过长的命令被自动截断了,如果想查看完整的输出命令,可以使用`--no-trunc`选项参数来设置。 |
[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 | 从返回结果中可以看到有关镜像的基本信息,如镜像名称、描述、收藏数(受欢迎程度)、是否官方创建、是否自动创建等,注意默认的输出结果是按照星级评价来进行排序的。 |
[envythink@localhost ~]$ docker image rm envyubuntu:latest
Untagged: envyubuntu:latest
1 | 请注意我们删除上述envyubuntu:latest镜像的时候,本地的ubuntu:latest镜像是不受到任何影响的。当某一个镜像拥有多个标签的时候,此时执行`docker image rm`或者是`docker rmi`命令的时候,只是删除了该镜像多个标签中的指定标签而已,并不影响镜像文件,也就是仅仅删除了这个镜像的一个标签副本而已。 |
[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 | 但是需要注意,如果这个镜像只剩下一个标签,那么此时执行`docker image rm`或者是`docker rmi`命令的时候就会删除这个镜像文件的所有文件层。 |
[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 | 但是笔者并不建议使用`-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 | ### 清理镜像 |
[envythink@localhost ~]$ docker image prune -f
1 | ### 创建镜像 |
[envythink@localhost ~]$ docker run -it envyubuntu:latest /bin/bash
root@9dfcfb7dac63:/# touch test.txt
root@9dfcfb7dac63:/# exit
1 | 接着可以使用`docker ps -a`命令来查看一下当前所有容器的运行状况,如下所示: |
[envythink@localhost ~]$ docker commit -m “Added a new file” -a “Docker Envy” 9dfcfb7dac63 test:0.1
sha256:71ea5620150363e696d187c8e139fcd1fc4ab809a26c3d6f20bcee1ae422f025
1 | 可以看到执行命令后会返回新创建的镜像的ID信息,此时使用`docker images`命令查看本地镜像时就可以发现新创建的镜像已经存在了,如下所示: |
[envythink@localhost ~]$ cat ubuntu-18.04-x86_64-minimal.tar.gz | docker import - ubuntu:18.04
1 | 其对应的解释如下图所示: |
[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 | 这样我们就通过上述命令创建出一个`python:3`的镜像。请注意该命令最后面有一个`.`号,请注意这个`.`号不是用来指定Dockerfile文件的所在位置,实际上使用`-f`参数来指定Dockerfile的路径。那么问题来了这个`.`号的作用是什么? |
[root@localhost envythink]# docker save -o envyubuntu_latest.tar envyubuntu:latest
[root@localhost envythink]# ls
envyubuntu_latest.tar
1 | ##### 载入镜像 |
[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 | 上面那种方式将导入镜像及其相关的元数据信息,里面包含标签等,当显示导入成功后,开发者可以使用`docker images`命令查看发现与原来的镜像是一样的。 |
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的前提,也是最基本的资源,所以在平时使用过程中需要累积和定制自己的镜像文件,这一点对提高工作效率有着非常大的帮助。