Docker镜像

简介

  镜像是Docker的三大核心概念之一。
  Docker运行容器前需要本地存在对应的镜像,如果镜像不存在本地,Docker会尝试先从默认镜像仓库下载(默认使用Docker Hub公共注册服务器中的仓库),用户也可以通过配置,使用自定义的镜像仓库。
  本章将介绍围绕镜像这一核心概念的具体操作,包括如何使用pull命令从Docker Hub仓库中下载镜像到本地;如何查看本地已有的镜像信息;如何在远端仓库使用search命令进行搜索和过滤;如何删除镜像标签和镜像文件;如何创建用户定制的镜像并且保存为外部文件。最后,还将介绍如何向Docker Hub仓库中推送自己的镜像。

 

获取镜像

  镜像是Docker运行容器的前提。
  读者可以使用docker pull命令从网络上下载镜像。该命令的格式为docker pull NAME[:TAG]。对于Docker镜像来说,如果不显式地指定TAG,则默认会选择latest标签,即下载仓库中最新版本的镜像。
  下面,博主将演示如何从Docker Hub的Ubuntu仓库下载一个最新的Ubuntu操作系统的镜像。

[root@gavin ~]# sudo docker pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
5b7339215d1d: Pull complete 
14ca88e9f672: Pull complete 
a31c3b1caad4: Pull complete 
b054a26005b7: Pull complete 
Digest: sha256:9b1702dcfe32c873a770a32cfd306dd7fc1c4fd134adfb783db68defc8894b3c
Status: Downloaded newer image for ubuntu:latest

  该命令实际上下载的就是ubuntu:latest镜像,目前最新的18.04版本的镜像。
  下载过程中可以看出,镜像文件一般由若干层组成,行首的5b7339215d1d这样的字串代表了各层的ID。下载过程中会获取并输出镜像的各层信息。层(Layer)其实是AUFS(Advanced Union File System,一种联合文件系统)中的重要概念,是实现增量保存与更新的基础。
  读者还可以通过指定标签来下载特定版本的某一个镜像,例如18.04标签的镜像。

[root@gavin ~]# sudo docker pull ubuntu:18.04
18.04: Pulling from library/ubuntu
Digest: sha256:9b1702dcfe32c873a770a32cfd306dd7fc1c4fd134adfb783db68defc8894b3c
Status: Downloaded newer image for ubuntu:18.04

  上面两条命令实际上都相当于sudo docker pull registry.hub.docker.com/ubuntu:latest命令,即从默认的注册服务器registry.hub.docker.com中的ubuntu仓库来下载标记为latest的镜像。

  下载镜像到本地后,即可随时使用该镜像了,例如利用该镜像创建一个容器,在其中运行bash应用。

[root@gavin ~]# sudo docker run -t -t ubuntu:latest /bin/bash
root@74bf842f3c6c:/#

 

查看镜像信息

  使用docker images命令可以列出本地主机上已有的镜像。
  例如,下面的命令列出了本地刚从官方下载的ubuntu:18.04以及ubuntu:latest镜像。

[root@gavin ~]# sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              18.04               4c108a37151f        2 weeks ago         64.2MB
ubuntu              latest              4c108a37151f        2 weeks ago         64.2MB

  在列出信息中,可以看到有几个字段信息:

  • 来自于哪个仓库,比如ubuntu仓库。
  • 镜像的标签信息,比如18.04。
  • 镜像的ID号(唯一)。
  • 创建时间。
  • 镜像大小。

  其中镜像的ID信息十分重要,它唯一标识了镜像。
  TAG信息用于标记来自同一个仓库的不同镜像。例如ubuntu仓库中有多个镜像,通过TAG信息来区分发行版本,包括14.04、15.04、16.10、17.04、18.04等标签。
  为了方便在后续工作中使用这个镜像,还可以使用docker tag命令为本地镜像添加新的标签。例如添加一个新的ubuntu:v1.0镜像标签如下:

[root@gavin ~]# sudo docker tag ubuntu:latest ubuntu:v1.0

  再次使用docker images列出本地主机上镜像信息,可以看到多了一个ubuntu:v1.0标签的镜像。

[root@gavin ~]# sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              18.04               4c108a37151f        2 weeks ago         64.2MB
ubuntu              latest              4c108a37151f        2 weeks ago         64.2MB
ubuntu              v1.0                4c108a37151f        2 weeks ago         64.2MB

  细心的读者可能会注意到,这些不同标签的镜像的ID是完全一致的,说明它们实际上指向了同一个镜像文件,只是别名不同而已。标签在这里起到了引用或快捷方式的作用。
  使用docker inspect命令可以获取该镜像的详细信息。

[root@gavin ~]# sudo docker inspect 4c108a37151f
[
    {
        "Id": "sha256:4c108a37151f54439950335c409802e948883e00c93fdb751d206c9a9674c1f6",
        "RepoTags": [
            "ubuntu:18.04",
            "ubuntu:latest",
            "ubuntu:v1.0"
        ],
        "RepoDigests": [
            "ubuntu@sha256:9b1702dcfe32c873a770a32cfd306dd7fc1c4fd134adfb783db68defc8894b3c"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2019-06-18T22:51:38.340092056Z",
        "Container": "fdea049ea807b599050e885a88784e009ed78ebcc4d498be93744bb9374c6134",
        "ContainerConfig": {
            "Hostname": "fdea049ea807",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ",
                "CMD [\"/bin/bash\"]"
            ],
            "ArgsEscaped": true,
            "Image": "sha256:ae950a0376fe6c4d08fa7ff395f50f4a909e26e9f2d865d8641cda024161c6ee",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {}
        },
        "DockerVersion": "18.06.1-ce",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/bash"
            ],
            "ArgsEscaped": true,
            "Image": "sha256:ae950a0376fe6c4d08fa7ff395f50f4a909e26e9f2d865d8641cda024161c6ee",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 64184378,
        "VirtualSize": 64184378,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/c2dab2bd224b9fa08454dd83047c951dc083d7e66cbd3bc121525f90d91aa3f8/diff:/var/lib/docker/overlay2/6247f7d6c45adb4475889cfa641dfc3c917de3a501d7e29c09833bdb98acf3de/diff:/var/lib/docker/overlay2/2adcd34ff16da9a82706938907f6f2bcee53ec5e0e7e6d6b8ee90eea80d635e4/diff",
                "MergedDir": "/var/lib/docker/overlay2/4d6fe2c8be4a0d1a7afc7a648c8be8dfbda2eb1b621db2b3a2832c5e3aa659f9/merged",
                "UpperDir": "/var/lib/docker/overlay2/4d6fe2c8be4a0d1a7afc7a648c8be8dfbda2eb1b621db2b3a2832c5e3aa659f9/diff",
                "WorkDir": "/var/lib/docker/overlay2/4d6fe2c8be4a0d1a7afc7a648c8be8dfbda2eb1b621db2b3a2832c5e3aa659f9/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:ba9de9d8475e7f5e40086358a1353b3cc080994fc6d31e4272dd3acb69b0151e",
                "sha256:fbd2732ad777cb5db2515fa62b6122b797be233d01db02e0a19e5d894688cad6",
                "sha256:dda1518598187bf87704acc22aa0ec2a67d9e7835c24346dfca118ab42c5cd0b",
                "sha256:75e70aa52609fdbd63b58d46d6f7c20470062e1c9bb75616f7703a358a61e5ca"
            ]
        },
        "Metadata": {
            "LastTagTime": "2019-07-09T18:06:36.890136591+04:00"
        }
    }
]

  docker inspect 命令返回的是一个JSON格式的消息,如果我们只要其中一项内容时,可以使用-f参数来指定,例如,获取镜像的Architecture信息:

[root@gavin ~]# sudo docker inspect -f {{".Architecture"}} 4c108a37151f
amd64

 

搜寻镜像

  使用docker search命令可以搜索远端仓库*享的镜像,默认搜索Docker Hub官方仓库中的镜像。用法为docker search TERM,支持的参数包括:

  • --automated=false仅显示自动创建的镜像。
  • --no-trunc=false 输出信息不截断显示。
  • -s,--stars=0指定仅显示评价为指定星级以上的镜像。

  例如,搜索带mysql关键字的镜像如下所示:

[root@gavin ~]# sudo docker search mysql
NAME                              DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
mysql                             MySQL is a widely used, open-source relation…   8364                [OK]                
mariadb                           MariaDB is a community-developed fork of MyS…   2866                [OK]                
mysql/mysql-server                Optimized MySQL Server Docker images. Create…   623                                     [OK]
percona                           Percona Server is a fork of the MySQL relati…   438                 [OK]                
centurylink/mysql                 Image containing mysql. Optimized to be link…   60                                      [OK]
centos/mysql-57-centos7           MySQL 5.7 SQL database server                   57                                      
mysql/mysql-cluster               Experimental MySQL Cluster Docker images. Cr…   46                                      
deitch/mysql-backup               Automated and scheduled mysql database dumps…   39                                      [OK]
tutum/mysql                       Base docker image to run a MySQL database se…   32                                      
schickling/mysql-backup-s3        Backup MySQL to S3 (supports periodic backup…   28                                      [OK]
bitnami/mysql                     Bitnami MySQL Docker Image                      27                                      [OK]
linuxserver/mysql                 A Mysql container, brought to you by LinuxSe…   20                                      
prom/mysqld-exporter                                                              19                                      [OK]
centos/mysql-56-centos7           MySQL 5.6 SQL database server                   15                                      
mysql/mysql-router                MySQL Router provides transparent routing be…   12                                      
circleci/mysql                    MySQL is a widely used, open-source relation…   12                                      
arey/mysql-client                 Run a MySQL client from a docker container      10                                      [OK]
yloeffler/mysql-backup            This image runs mysqldump to backup data usi…   6                                       [OK]
openshift/mysql-55-centos7        DEPRECATED: A Centos7 based MySQL v5.5 image…   6                                       
fradelg/mysql-cron-backup         MySQL/MariaDB database backup using cron tas…   4                                       [OK]
genschsa/mysql-employees          MySQL Employee Sample Database                  2                                       [OK]
jelastic/mysql                    An image of the MySQL database server mainta…   1                                       
monasca/mysql-init                A minimal decoupled init container for mysql    0                                       
widdpim/mysql-client              Dockerized MySQL Client (5.7) including Curl…   0                                       [OK]
ansibleplaybookbundle/mysql-apb   An APB which deploys RHSCL MySQL                0                                       [OK]

  可以看到返回了很多包含关键字的镜像,其中包括镜像名字、描述、星级(表示该镜像的受欢迎程度)、是否官方创建、是否自动创建等。
  默认的输出结果将按照星级评价进行排序。官方的镜像说明是官方项目组创建和维护的,automated资源则允许用户验证镜像的来源和内容。

 

删除镜像

使用镜像的标签删除镜像

  使用docker rmi命令可以删除镜像,命令格式为docker rmi IMAGE [IMAGE...],其中IMAGE可以为标签或ID。
  例如,要删除掉ubuntu:v1.0镜像,可以使用如下命令

[root@gavin ~]# sudo docker rmi ubuntu:v1.0
Untagged: ubuntu:v1.0

  读者可能会担心,本地的ubuntu:latest镜像是否会受到此命令的影响。无需担心,当同一个镜像拥有多个标签的时候,docker rmi命令只是删除了该镜像多个标签中的指定标签而已,并不影响镜像文件。因此上述操作相当于只是删除了镜像4c108a37151f的一个标签而已。
  为保险起见,再次查看本地的镜像,发现ubuntu:latest镜像(准确地说,是4c108a37151f镜像)仍然存在:

[root@gavin ~]# sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              18.04               4c108a37151f        2 weeks ago         64.2MB
ubuntu              latest              4c108a37151f        2 weeks ago         64.2MB

  但当镜像只剩下一个标签的时候就要小心了,此时再使用docker rmi命令会彻底删除该镜像。
  假设本地存在一个标签为mysql:latest的镜像,且没有额外的标签指向它,执行docker rmi命令,可以看出它会删除这个镜像文件的所有AUES层:

[root@gavin ~]# sudo docker rmi mysql:latest
Untagged: mysql:latest
Untagged: mysql@sha256:415ac63da0ae6725d5aefc9669a1c02f39a00c574fdbc478dfd08db1e97c8f1b
Deleted: sha256:c7109f74d339896c8e1a7526224f10a3197e7baf674ff03acbab387aa027882a
Deleted: sha256:35d60530f024aa75c91a123a69099f7f6eaf5ad7001bb983f427f674980d8482
Deleted: sha256:49d8bb533eee600076e3a513a203ee24044673fcef0c1b79e088b2ba43db2c17
Deleted: sha256:2e7d501ae7df8ee0eca0fe0b16c6e9fad9a3664811445f38f32636b47366eec3
Deleted: sha256:6a362ed9781f7b3f0c63b061dfb0f14d9ba10d021df10712a131158c103b0d18
Deleted: sha256:3e58b58898622709169f72e7fa20244e084316f3ee66142728bce3f35bb9538b
Deleted: sha256:4beb9add2b61bbae54c13e9d9f374b1fe8573226c2fe889bdd5dc8eed19ffbc1
Deleted: sha256:b3a6af4f3db06bbe8f661019f7dbc354b5e63318fca01d8f1e6218f0afbaa5eb
Deleted: sha256:037818566b488757260ae3d0064fbf6e47365cd08dc6409b7a018a512ef17f25
Deleted: sha256:000ec65531a617f550ee04f67c875b70f4b395af00b5f5bb7ed480b17078bc0b
Deleted: sha256:11d387a2efcce7596530d6be2299b6528b0afe070aba3caf3432ca31c3b0132d
Deleted: sha256:a883a9d05facd6220d9251787142b41cc6675f247bc47c94071e665adf65dbbf
Deleted: sha256:cf5b3c6798f77b1f78bf4e297b27cfa5b6caa982f04caeb5de7d13c255fd7a1e

使用镜像的ID删除镜像

  当使用docker rmi命令后面跟上镜像的ID(也可以是ID能进行区分的部分前缀串)时,会先尝试删除所有指向该镜像的标签,然后删除该镜像文件本身。
  注意,当有该镜像创建的容器存在时,镜像文件默认是无法被删除的,例如:先利用ubuntu镜像创建一个简单的容器,输出一句话'hello docker':

[root@gavin ~]# sudo docker run ubuntu:latest echo 'hello docker'
hello docker

  使用docker ps -a命令可以看到本机上存在的所有容器:

[root@gavin ~]# sudo docker ps -a
CONTAINER ID        IMAGE               COMMAND                 CREATED             STATUS                     PORTS               NAMES
f062ef2957f1        ubuntu:latest       "echo 'hello docker'"   2 minutes ago       Exited (0) 2 minutes ago                       sleepy_euler

  可以看到,后台存在一个退出状态的容器,是刚基于ubuntu:latest镜像创建的。
  试图删除该镜像,Docker会提示有容器正在引用,无法删除:

[root@gavin ~]# sudo docker rmi ubuntu:latest
Untagged: ubuntu:latest

  结果我们这里删除成功了,原因是存在相同ID的镜像(ubuntu:18.04,ubuntu:latest),前面只是删除了一个tag(标签),这里我们再删除ubuntu:18.04

[root@gavin ~]# sudo docker rmi ubuntu:18.04
Error response from daemon: conflict: unable to remove repository reference "ubuntu:18.04" (must force) - container f062ef2957f1 is using its referenced image 4c108a37151f

  果不其然提示有容器正在引用,无法删除。
  如果要想强行删除镜像,可以使用-f参数:

[root@gavin ~]# sudo docker rmi -f ubuntu:18.04
Untagged: ubuntu:18.04
Untagged: ubuntu@sha256:9b1702dcfe32c873a770a32cfd306dd7fc1c4fd134adfb783db68defc8894b3c
Deleted: sha256:4c108a37151f54439950335c409802e948883e00c93fdb751d206c9a9674c1f6

  博主不推荐使用-f参数来强制删除一个存在容器依赖的镜像,因为这样往往会造成一些遗留问题。
  因此,正确的做法是,先删除依赖该镜像的所有容器,再来删除镜像。首先删除容器f062ef2957f1:

[root@gavin ~]# sudo docker rm f06
f06

  此时再使用ID来删除镜像,此时会正常打印出删除的各层信息:

[root@gavin ~]# sudo docker rmi 4c108a37151f
Untagged: ubuntu:latest
Untagged: ubuntu@sha256:9b1702dcfe32c873a770a32cfd306dd7fc1c4fd134adfb783db68defc8894b3c
Deleted: sha256:4c108a37151f54439950335c409802e948883e00c93fdb751d206c9a9674c1f6
Deleted: sha256:7c1abf1dbbfd02a48330a7317ab45a6091d53e2e9cc062f0f3dbd2b7539947a6
Deleted: sha256:5a614dda4a54650168ee2cd30ce2e39576dad5c9a0d1907c02445687b4ea5090
Deleted: sha256:bd042113a73a5c9c6680990740446b7324afb39e243ade3d33bdaa9ffaf8d294
Deleted: sha256:ba9de9d8475e7f5e40086358a1353b3cc080994fc6d31e4272dd3acb69b0151e

 

创建镜像

  创建镜像的方法有三种:基于已有镜像的容器创建、基于本地模板导入、基于Dockerfile创建。
  本文将重点介绍前两种方法。最后一种基于Dockerfile创建的方法将在后续博文中专门予以详细介绍。

基于已有镜像的容器创建

  该方法主要是使用docker commit命令,其命令格式为docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]],主要选项包括:

  • -a,--author=""作者信息。
  • -m,--message=""提交消息。
  • -p,--pause=true 提交时暂停容器运行。

  下面将演示如何使用该命令创建一个新镜像。首先,启动一个镜像,并在其中进行修改操作,例如创建一个test文件,之后退出:

[root@gavin ~]# sudo docker run -ti ubuntu:18.04 /bin/bash
root@e8382cf8c930:/# touch test
root@e8382cf8c930:/# exit

  记住容器的ID为:e8382cf8c930。
  此时该容器跟原ubuntu:18.04镜像相比,已经发生了改变,可以使用docker commit命令来提交为一个新的镜像。提交时可以使用ID或名称来指定容器:

[root@gavin ~]# sudo docker commit -m "Added a new file" -a "Docker Newbee" e8382cf8c930 test:1.0
sha256:a7f06e6700e36df75ad4dfc952bab4861f35edb840f50aeb3b657d8cc27e9403

  顺利的话,命令会返回新创建的镜像的ID信息,例如:a7f06e6700e36df75ad4dfc952bab4861f35edb840f50aeb3b657d8cc27e9403
  此时查看本地镜像列表,即可看到新创建的镜像:

[root@gavin ~]# sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
test                1.0                 a7f06e6700e3        2 minutes ago       64.2MB
ubuntu              18.04               4c108a37151f        3 weeks ago         64.2MB

基于本地模板导入

  也可以直接从一个操作系统模板文件导入一个镜像。在这里,推荐使用OpenVZ提供的模板来创建。OPENVZ模板的下载地址为https://wiki.openvz.org/Download/templates/precreated
  比如,笔者下载了一个centos:7.0的模板压缩包后,可以使用以下命令导入:

[root@gavin data]# sudo cat centos-7-x86_64.tar.gz | docker import - centos:7.0
sha256:0c4f10b8e790e76e2b60d4afff42248b04abacfb9918109e8b3dc94d72cafda1

  然后查看新导入的镜像,已经在本地存在了:

[root@gavin data]# sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
centos              7.0                 0c4f10b8e790        About a minute ago   589MB
test                1.0                 a7f06e6700e3        16 minutes ago       64.2MB
ubuntu              18.04               4c108a37151f        3 weeks ago          64.2MB

 

存出和存入镜像

  可以使用docker save和docker load命令来存出和载入镜像。

存出镜像

  如果要存出镜像到本地文件,可以使用docker save命令。例如,存出本地的ubuntu:18.04镜像为文件 ubuntu_18.04.tar:

[root@gavin /]# sudo docker save -o ubuntu_18.04.tar ubuntu:18.04 

存入镜像

  可以使用docker load从存出的本地文件中再导入到本地镜像库,例如从文件ubuntu_18.04.tar导入镜像到本地镜像列表,如下所示:

[root@gavin /]# sudo docker load --input ubuntu_18.04.tar

  或

[root@gavin /]# sudo docker load < ubuntu_18.04.tar

  这将导入镜像以及其相关的元数据信息(包括标签等),可以使用docker images命令进行查看。

 

上传镜像

  可以使用docker push命令上传镜像到仓库,默认上传到DockerHub官方仓库(需要登录),命令格式为docker push NAME[:TAG]。
  用户在DockerHub网站注册后,即可上传自制的镜像。例如博主上传本地的test:1.0镜像,博主在Docker上注册的用户名是xiaohui1994,可以先给test:1.0添加新的标签xiaohui1994/test:1.0,然后用docker push命令上传镜像:

[root@gavin /]# docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: xiaohui1994
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
[root@gavin /]# sudo docker push xiaohui1994/test:1.0
The push refers to repository [docker.io/xiaohui1994/test]
bb817e704dea: Pushed 
75e70aa52609: Mounted from library/ubuntu 
dda151859818: Mounted from library/ubuntu 
fbd2732ad777: Mounted from library/ubuntu 
ba9de9d8475e: Mounted from library/ubuntu 
1.0: digest: sha256:ec47f750b7827f9e5483a4ac48d12fadf8cfe05b2e7839d0884b1bbacdf70441 size: 1359

  此时登录DockerHub可以看到刚上传的镜像:

Docker镜像

 

 

这篇文章是我学习 Docker 的记录,内容参考自《Docker技术入门与实战》

 

上一篇:Spring Boot搭建Web服务脚手架


下一篇:javascript – 为什么我的crypto.sublte.digest实现会产生等长字符串的等效十六进制哈希值?