本节将会涉及Docker的镜像操作。
1. 获取镜像
如何获取Docker Hub上的镜像?可通过docker pull命令获取,其格式为: docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签],具体可通过docker pull --help命令查看。
Docker镜像仓库地址的格式一般为<域名/IP>[:端口号],仓库名一般为两段式名称,即<用户名>/<软件名>,对于Docker Hub,默认的用户名为library。
例:获取ubuntu:16.04镜像,其中可看到默认用户library,16.04位镜像标签。
$ docker pull ubuntu:16.04 16.04: Pulling from library/ubuntu 8f7c85c2269a: Pull complete 9e72e494a6dd: Pull complete 3009ec50c887: Pull complete 9d5ffccbec91: Pull complete e872a2642ce1: Pull complete Digest: sha256:d3fdf5b1f8e8a155c17d5786280af1f5a04c10e95145a515279cf17abdf0191f Status: Downloaded newer image for ubuntu:16.04
从下载过程中可看到docker的分层存储概念。下载会进行分层下载,下载过程中给出每一层ID的前12位,下载结束后,给出完整的sha256摘要,确保下载一致性。
2. 运行镜像
基于镜像,可以启动并运行一个容器。格式为:docker run [选项] 镜像名 [CMD]。
例:运行ubuntu:16.04 镜像。
$ docker run -it --rm ubuntu:16.04 bash root@b5744a2879f8:/#
运行后,可以看到已进入到容器内部,且以root用户进入。
查看容器中的系统信息:
root@e59690e24ff2:/# cat /etc/os-release NAME="Ubuntu" VERSION="16.04.3 LTS (Xenial Xerus)" ID=ubuntu ID_LIKE=debian PRETTY_NAME="Ubuntu 16.04.3 LTS" VERSION_ID="16.04" HOME_URL="http://www.ubuntu.com/" SUPPORT_URL="http://help.ubuntu.com/" BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/" VERSION_CODENAME=xenial UBUNTU_CODENAME=xenial
命令中的-it选项:-i表示交互式操作,-t表示终端,因为打算进入bash执行一些命令,并查看返回结果,因此需要交互式终端;
--rm选项:该选项表示容器退出后随之将容器删除。默认情况下,退出容器不会立即删除,需要手工docker rm。这里只是演示执行命令,不需要排障和保留结果,因此使用该参数,避免空间浪费。
bash命令:放在镜像名(ubuntu: 16.04)后面的是命令,bash命令可以提供交互式shell。
进入容器后,该容器即为ubuntu系统,可以执行ubuntu相关的任何命令。
退出容器,使用exit命令即可。
3. 列出镜像
想要列出已存在的镜像,可使用docker image ls命令。列表会提供仓库名、标签、镜像ID、创建时间、占用空间。
$ docker image ls | grep -v 192.168 | grep -v gcr | grep -v none | grep -v content | grep -v down | grep -v media | grep -v wal REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu 16.04 2a4cca5ac898 5 days ago 111MB jupyterhub/jupyterhub latest c5dc992337c7 7 days ago 670MB nginx v3 fbe2b1559cb0 9 days ago 108MB nginx v2 3e652016d731 9 days ago 108MB nging v2 3d79377a847b 9 days ago 108MB quay.io/coreos/etcd latest 94bc3af972c9 9 days ago 37.2MB busybox latest 807fd4df40d1 12 days ago 1.14MB apollo-configservice latest 277dd2dccb3c 12 days ago 191MB apollo-adminservice latest 84a3ec4dfcb5 12 days ago 185MB apollo-portal latest 40cfb14be3f0 13 days ago 164MB jupyter/minimal-notebook latest 3130da5c9146 2 weeks ago 2.73GB docker-start-web latest b92c92688046 2 weeks ago 113MB test latest b92c92688046 2 weeks ago 113MB friendlyhello latest bf1ed1612b69 2 weeks ago 148MB nginx latest 3f8a4339aadd 3 weeks ago 108MB ifrs latest 01c81b407ffb 4 weeks ago 476MB cloudnativelabs/kube-router latest 79413998ed60 4 weeks ago 88.4MB ubuntu 14.04 67759a80360c 5 weeks ago 221MB jenkins latest 5fc84ab0b7ad 5 weeks ago 809MB jetty latest 2938aa22262c 5 weeks ago 547MB python 2.7-slim 4fd30fc83117 5 weeks ago 138MB rethinkdb latest 98ac1e7f55fd 5 weeks ago 182MB mysql 5.7 7d83a47ab2d2 5 weeks ago 408MB mysql latest 7d83a47ab2d2 5 weeks ago 408MB portainer/portainer latest f71b185552bf 5 weeks ago 33.2MB openjdk 8-jre-alpine a7441b26c41b 6 weeks ago 81.9MB registry 2 177391bcf802 7 weeks ago 33.3MB registry latest 177391bcf802 7 weeks ago 33.3MB alpine latest e21c333399e0 7 weeks ago 4.14MB hello-world latest f2a91732366c 2 months ago 1.85kB quay.io/coreos/flannel v0.9.1-amd64 2b736d06ca4c 2 months ago 51.3MB swarm latest 59c0df55980b 2 months ago 15.8MB busybox latest 6ad733544a63 2 months ago 1.13MB centos centos7.4.1708 3afd47092a0e 2 months ago 197MB nobodyiam/apollo-quick-start latest 6b3290a6a9cc 3 months ago 144MB dockersamples/visualizer stable 8dbf7c60cf88 5 months ago 148MB shipyard/shipyard latest 36fb3dc0907d 15 months ago 58.8MB shipyard/docker-proxy latest cfee14e5d6f2 2 years ago 9.46MB microbox/etcd latest 6aef84b9ec5a 2 years ago 17.9MB
注意:一个镜像可以对应多个标签,因此可以看到mysql的镜像ID为7d83a47ab2d2,而对应两个标签,分别为latest和5.7。
4. 镜像体积
Docker Hub中的镜像与下载下来的镜像大小可能不同,因为Docker Hub上显示的是压缩后的大小,而下载过程中会进行解压,因此下载后的镜像尺寸更大一些。
docker image ls中列出的镜像体积总和并非是所有镜像实际硬盘消耗,由于分层存储结构,不同镜像可能会使用相同基础镜像,因此实际占用磁盘大小比列表显示总和要小很多。
可以通过docker system df 查看镜像、容器、数据卷所占用空间。
$ docker system df TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 115 24 13.92GB 9.966GB (71%) Containers 32 27 116.7MB 0B (0%) Local Volumes 14 6 10.19GB 436.7MB (4%) Build Cache
5. 虚悬镜像
有一种特殊镜像,仓库名与标签均为<none>。该镜像原本是存在镜像名和标签,随着发布新版本后,该镜像名被转移到新下载的镜像上,就镜像上的镜像名及标签则被取消,从而成为了<none>。
镜像拉取命令docker pull与镜像构建命令docker build均可能导致这种现象。这种镜像也被成为虚悬镜像(dangling image)。
可以使用docker image ls -f dangling=true专门显示虚悬镜像。
$ docker image ls -f dangling=true REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> b12c7031cf96 3 days ago 177MB <none> <none> b170d97325c2 3 days ago 686MB <none> <none> 4fec837318a2 3 days ago 231MB <none> <none> a4b3b3e053aa 10 days ago 177MB <none> <none> 7e1c59663166 2 weeks ago 191MB
6. 中间层镜像
为了加速镜像构建,重复利用资源,docker会利用中间层镜像。默认docker image ls列表只会显示顶层镜像,增加 -a 参数即可显示包括中间层镜像在内的所有镜像。
$ docker image ls -a REPOSITORY TAG IMAGE ID CREATED SIZE allinone-service latest e9a3879ed76f 3 hours ago 177MB <none> <none> ba0c65b39c64 3 hours ago 177MB <none> <none> 423675da3624 3 hours ago 177MB <none> <none> 935dd95fcf8c 3 hours ago 132MB
7. 列出部分镜像
(1) 根据仓库名列出镜像:docker image ls image_name
$ docker image ls ubuntu REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu 16.04 2a4cca5ac898 5 days ago 111MB ubuntu 14.04 67759a80360c 5 weeks ago 221MB
(2) 基于仓库名+标签列出镜像: docker image ls image_name:tag
$ docker image ls ubuntu:16.04 REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu 16.04 2a4cca5ac898 5 days ago 111MB
(3) docker image ls 之前 --filter过滤器参数。
如:列出mysql:latest之前(before)/后(since)构建的镜像。
$ docker image ls -f since=mysql:latest REPOSITORY TAG IMAGE ID CREATED SIZE allinone-service latest e9a3879ed76f 3 hours ago 177MB download_worker_test latest b5a2e88c7a66 46 hours ago 855MB
(4) 如果构建镜像时,定义了LABEL,也可以通过LABEL进行过滤,如: docker image ls -f label=con.example.version=0.1
(5) 以特定格式显示
例:
以镜像id进行显示:docker image ls -q ,--filter与-q结合产生指定范围的ID列表,然后作为参数传入另一个docker命令,进而可以成批进行某种操作,这种做法在Dockjer中十分常见。
(6) 有时对表格的结构不满意,希望自己组织列,可以使用Go的模板语法。
例:
a. 列出只包含镜像ID和仓库名:docker image ls --format "{{.ID}}: {{.Repository}}"
b. 以表格等距显示,并且有标题行,自己定义显示列:docker image ls --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}"
8. 使用commit理解镜像构建
注意:不要使用commit定制镜像,定制镜像应该使用Dockerfile完成,Dockerfile会在下一节详解。
和镜像一样,容器也是多层存储。容器以镜像为基础层,在其上加一层作为容器运行的存储层。
例:
定制一个Web服务器,理解镜像如何构建:
(1) 使用nginx镜像启动容器,命名为webserver,并映射80端口。命令为:docker run --name webserver -d -p 80:80 nginx。使用浏览器,输入: localhost,即可出现nginx显示界面。如下图所示:
(2) 我们希望将该页面信息改为Docker文字,可以使用docker exec命令进入容器,修改器内容。如下命令所示:
$ docker exec -it webserver bash root@9b59f2338c3a:/# echo ‘<h1>Hello, Docker!</h1>‘ > /usr/share/nginx/html/index.html root@9b59f2338c3a:/# exit exit
显示信息如下:
(3) 修改了容器的文件,可以通过docker diff命令查看具体改动。
$ docker diff webserver C /var C /var/cache C /var/cache/nginx A /var/cache/nginx/fastcgi_temp A /var/cache/nginx/proxy_temp A /var/cache/nginx/scgi_temp A /var/cache/nginx/uwsgi_temp A /var/cache/nginx/client_temp C /root A /root/.bash_history C /run A /run/nginx.pid C /usr C /usr/share C /usr/share/nginx C /usr/share/nginx/html C /usr/share/nginx/html/index.html
(4) 现在定制好了,希望能将其保存下来形成镜像。
当运行容器时,且不使用卷时,任何文件修改都会被记录于容器存储层。可以使用docker commit命令将容器的存储层保存下来形成镜像。即在原有镜像基础上,再叠加容器的存储层,并构成新的镜像,以后我们运行这个新镜像的时候,就会拥有原有容器最后的文件变化。
docker commit的格式为:docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]
可以使用命令将容器保存为镜像:docker commit --author "ws<ws@qq.com>" --message "修改默认网页" webserver nginx:v2
其中: author指定修改作者,--message记录本次修改内容。可以使用docker image ls显示新的定制镜像,使用docker history具体查看镜像内的历史记录,如:docker history nginx:v2
(5) 镜像定制好后,可以重新运行该镜像:docker run --name web2 -d -p 81:80 nginx:v2
注意:慎用docker commit
因为docker commit会将大量无关的修改内容、构建内容添加进来,如果不小心清理,将会导致镜像极为臃肿,其次docker commit意味着所有对镜像的操作都是黑箱操作,生成的镜像也称为黑箱镜像,随着时间的延长,会无法清楚地记得所修改操作,即使docker diff也只会提供少许。