在 Docker 中, 应用是通过容器来运行的, 而容器的运行是基于镜像的, 类似面向对象设计中类与对象的关系 -- 没有类的定义就谈不上实例的创建与使用, 没有镜像的定义就谈不上容器的创建与运行.
1. 获取镜像
镜像从哪里来, 一般两个途径, 一是公共镜像库, 如官方镜像库 Docker Hub, 上面有大量的高质量的镜像直接可拿来用; 二是自定义, 我们可基于一个已有镜像, 在其基础上增加一些层(还记得镜像的分层存储特性吧), 然后构建形成自己的镜像.
如果我们知道某个镜像的名称, 则可直接通过 docker pull 来下载镜像到本地, 如 Ubuntu,Redis,nginx 等, docker pull 命令的格式如下(中括号表示可有可没有)
docker pull [选项] [Docker Registry 的地址 [: 端口号]/] 仓库名[: 标签]
其中选项可设置:
-a, -all-tags: 下载仓库中所有标签 (一般指版本) 的镜像
-disable-content-trust: 跳过镜像验证, 默认为 true
Docker Registry 的地址即镜像仓库地址, 一般为域名或 IP 加端口号, 如果不指定则默认为 Docker Hub; 仓库名包含两部分,<用户名>/<软件名>, 对于 Docker Hub, 如果不给出用户名, 则默认为 library, 表示官方提供; 标签一般是对应软件的版本号, 如果不指定则默认为 latest.
比如我们要下一个 nginx 镜像, 则可执行如下命令
- [root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker pull nginx
- Using default tag: latest
- latest: Pulling from library/nginx
- fc7181108d40: Already exists
- d2e987ca2267: Pull complete
- 0b760b431b11: Pull complete
- Digest: sha256:48cbeee0cb0a3b5e885e36222f969e0a2f41819a68e07aeb6631ca7cb356fed1
- Status: Downloaded newer image for nginx:latest
这里我们没有指定选项, 也没有指定镜像仓库地址, 那么默认会从 Docker Hub 获取镜像(但 Docker Hub 由于在国外, 速度比较慢, 所以一般要设置国内加速器, 参考 Docker 笔记(三):Docker 安装与配置 http://blog.jboost.cn/2019/07/14/docker-3.html 第二部分: 配置国内镜像), 也没有给出用户名, 所以默认是 library(第三行), 没有指定标签, 所以默认是 latest(第二行), 由第四至第六行可见, 这个镜像包含三个层, 并且第一个层已经存在了(之前下载的镜像已经包含了这个层, 直接复用), 镜像分层的概念及层的复用, 应该已经理解了.
如果我们不知道镜像的完整名称怎么办, 那就搜索一下, 有两个途径, 一是通过命令, 假设我们记不起 nginx 全称了, 只记得 ngi, 则可通过如下命令搜索
- [root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker search ngi
- NAME DESCRIPTION STARS OFFICIAL AUTOMATED
- nginx Official build of Nginx. 11693 [OK]
- jwilder/nginx-proxy Automated Nginx reverse proxy for docker con... 1628 [OK]
- richarvey/nginx-PHP-fpm Container running Nginx + PHP-FPM capable of... 726 [OK]
- bitnami/nginx Bitnami nginx Docker Image 69 [OK]
- linuxserver/nginx An Nginx container, brought to you by LinuxS... 69
- tiangolo/nginx-rtmp Docker image with Nginx using the nginx-rtmp... 48 [OK]
- nginx/nginx-ingress NGINX Ingress Controller for Kubernetes 20
- nginxdemos/hello NGINX webserver that serves a simple page co... 18 [OK]
- jlesage/nginx-proxy-manager Docker container for Nginx Proxy Manager 17 [OK]
- schmunk42/nginx-redirect A very simple container to redirect HTTP tra... 17 [OK]
- crunchgeek/nginx-pagespeed Nginx with PageSpeed + GEO IP + VTS + more_s... 13
- blacklabelops/nginx Dockerized Nginx Reverse Proxy Server. 12 [OK]
- ...
该命令会从 Docker Hub 搜索镜像名包含 ngi 的镜像, 其中 STARS 表示收藏用户数, OFFICIAL 为 [OK] 表示官方提供的镜像, AUTOMATED [OK]表示由自动构建生成, 一般选择 STARS 最多, 官方提供的镜像.
这种方式获取到的信息有限, 比如具体包含哪些版本不知道. 还有一个途径是直接在 Docker Hub 网站上搜索, 打开 https://hub.docker.com/ , 在搜索框输入 ngi, 如下图
则会列出所有满足条件的镜像, 点开 nginx 结果链接, 可以看到提供的版本(通过版本链接可以查看定义对应镜像的 Dockerfile), 及相应的文档说明. 这种方式获取的信息更加全面, 所以推荐这种方式!
另外, 当我们没有执行 docker pull, 直接通过 docker run xx 来运行一个容器时, 如果没有对应的镜像, 则会先自动下载镜像, 再基于镜像启动一个容器, 比如我们在 Docker 笔记(三):Docker 安装与配置 http://blog.jboost.cn/2019/07/14/docker-3.html 中检验 docker 是否安装成功时运行的 hello-world
2. 管理本地镜像
将镜像下载到本地后, 我们可以基于镜像来创建, 运行容器, 及对镜像进行管理.
查看本地镜像
- [root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker image ls
- REPOSITORY TAG IMAGE ID CREATED SIZE
- nginx latest f68d6e55e065 2 weeks ago 109MB
- MySQL latest c7109f74d339 5 weeks ago 443MB
- hello-world latest fce289e99eb9 6 months ago 1.84kB
上面各列依次列出了镜像名称, 标签(版本), 镜像 ID, 创建时间, 镜像大小. 镜像可以拥有多个标签(版本). 镜像的大小总和一般要大于实际的磁盘占有量, 为什么? 回忆一下镜像的分层存储概念, 层是可以复用的, 某个层其中一个镜像有了, 另一个镜像就不会再下载了. 口说无凭, 我们来验证下, docker system df 可列出镜像, 容器, 数据卷所占用的空间
- [root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker system df
- TYPE TOTAL ACTIVE SIZE RECLAIMABLE
- Images 3 1 497.1MB 497.1MB (99%)
- Containers 1 0 0B 0B
- Local Volumes 0 0 0B 0B
- Build Cache 0 0 0B 0B
通过 docker image ls 列出的各镜像大小总共约 552MB, 但这里列出的镜像大小只有约 497MB, 这下有凭有据了吧.
根据条件列出镜像
- docker image ls nginx # 根据名称列出镜像
- docker image ls nginx:latest # 根据名称与标签列出镜像
- docker image ls -f since=hello-world:latest # -f 是 --filter 的缩写, 过滤器参数, 列出在 hello-world:latest 之后建立的镜像, before=hello-world:latest 则查看之前建立的镜像
指定显示格式
- docker image ls -q # 只显示镜像 ID
- docker image ls --digests # 列出镜像摘要
- docker image ls --format "{{.ID}}: {{.Repository}}" # 使用 Go 的模板语法格式化显示, 这里显示格式为 镜像 ID: 镜像名称
- docker image ls --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}" # 自己定义表格格式
虚悬镜像
有时候会看到某些镜像既没有仓库名, 也没有标签, 均为 <none>. 这些镜像原本是有镜像名和标签的, 随着官方镜像维护, 发布了新版本后(新版本会复用之前的镜像名称与标签, 一般是 bug 修复版), 重新 docker pull xx 时, 这个镜像名被转移到了新下载的镜像身上, 而旧的镜像上的这个名称则被取消, 从而成为了 < none> . 除了 docker pull 可能导致这种情况, docker build 也同样可以导致这种现象. 由于新旧镜像同名, 旧镜像名称被取消, 从而出现仓库名, 标签均为 <none> 的镜像. 这类无标签镜像被称为虚悬镜像(dangling image) , 可以用下面的命令专门显示这类镜像:
docker image ls -f dangling=true
一般虚悬镜像没什么意义了, 可以通过如下命令删除
docker image prune
中间层镜像
为了加速镜像构建, 重复利用资源, Docker 会利用中间层镜像. 所以在使用一段时间后, 可能会看到一些依赖的中间层镜像. 默认的 docker image ls 列表中只会显示顶层镜像, 如果希望显示包括中间层镜像在内的所有镜像的话, 可以加 -a
$ docker image ls -a
这样会看到很多无标签的镜像, 与虚悬镜像不同, 这些无标签的镜像很多都是中间层镜像, 是其它镜像所依赖的镜像. 这些无标签镜像不应该删除, 否则会导致上层镜像因为依赖丢失而出错. 实际上, 这些镜像也没必要删除, 因为相同的层只会存一遍, 而这些镜像是别的镜像的依赖, 因此并不会因为它们被列出来而多存了一份, 无论如何你也会需要它们. 只要删除那些依赖它们的镜像后, 这些依赖的中间层镜像也会被连带删除.
删除镜像
删除镜像命令格式
docker image rm [选项] <镜像 1> [<镜像 2> ...]
选项可以设置:
-f, -force 强制删除镜像
-no-prune 不删除没有标签的父镜像
- <镜像 1>,<镜像 2> 等可以是镜像的名称, 镜像的全 ID, 也可以是镜像 ID 的前面几个数字(只要与其它镜像区分开来就行), 或者是镜像摘要. 如删除镜像名称为 MySQL 的镜像
- [root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker image rm MySQL
- Untagged: MySQL:latest
- Untagged: MySQL@sha256:415ac63da0ae6725d5aefc9669a1c02f39a00c574fdbc478dfd08db1e97c8f1b
- Deleted: sha256:c7109f74d339896c8e1a7526224f10a3197e7baf674ff03acbab387aa027882a
- Deleted: sha256:35d60530f024aa75c91a123a69099f7f6eaf5ad7001bb983f427f674980d8482
- Deleted: sha256:49d8bb533eee600076e3a513a203ee24044673fcef0c1b79e088b2ba43db2c17
- ...
由上面命令的执行结果可见, 删除镜像包括另个行为: Untagged,Deleted.
当我们使用上面命令来删除镜像的时候, 实际上是在要求删除某个 / 某些标签的镜像. 所以首先需要做的是将满足要求的所有镜像标签都取消, 这就是 Untagged 的行为. 一个镜像可以对应多个标签, 因此当我们删除了所指定的标签后, 可能还有别的标签指向了这个镜像, 如果是这种情况, 那么 Delete 行为就不会发生, 仅仅是取消了这个镜像的符合要求的所有标签. 所以并非所有的 docker image rm 都会产生删除镜像的行为, 有可能仅仅是取消了某个标签而已.
当该镜像所有的标签都被取消了, 该镜像很可能就失去了存在的意义, 因此会触发删除行为. 镜像是多层存储结构, 因此在删除的时候也是从上层向基础层方向依次进行判断删除. 如果某个其它镜像正依赖于当前镜像的某一层, 这种情况, 依旧不会触发删除该层的行为. 直到没有任何镜像依赖当前层时, 才会真实的删除当前层.
另外还需要注意是容器对镜像的依赖. 如果基于镜像启动的容器存在(即使容器没有运行处于停止状态) , 同样不可以删除这个镜像. 我们之前说了容器是以镜像为基础, 再加一层容器存储层组成的多层存储结构去运行的. 所以如果这些容器是不需要的, 应该先将它们删除, 然后再来删除镜像.
通过组合命令来删除
- docker image rm $(docker image ls -q nginx) # 删除镜像名称为 nginx 的所有镜像
- docker image rm $(docker image ls -q -f since=hello-world:latest) # 删除所有在 hello-world:latest 之后建立的镜像
3. 总结
本文对镜像的获取及本地镜像的基本管理做了介绍, 本文镜像的获取途径都是从镜像仓库直接获取, 镜像的另一个获取途径便是自定义, 接下来会通过实例来进行介绍, 欢迎关注.
我的个人博客地址: http://blog.jboost.cn/
来源: https://www.cnblogs.com/spec-dog/p/11198723.html