十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

docker images 命令详解:从基础到高阶的镜像管理实战

docker images 命令详解:从基础到高阶的镜像管理实战 平时排查服务器磁盘空间、清理无用镜像、写自动化部署脚本我敲得最多的命令就是docker images。这命令看着简单不就是列一下本地镜像嘛可你真要深挖它的参数组合能帮你省下大量时间。尤其是当你管理着几十上百个镜像或者要在 CI/CD 脚本里动态处理镜像时-a、-q、--filter、--format这几个参数用得好不好直接决定你是几分钟搞定还是折腾一下午。这篇文章我把docker images的常用参数从头到尾掰开揉碎讲一遍每个参数都结合实际场景说明为什么这么用、参数之间怎么组合最后再附上我踩过的坑。不管你是刚接触 Docker 的新手还是写脚本的老手这都值得收藏一份。1. 先把 docker images 摆到台面上它到底是干嘛的1.1 镜像列表命令在 Docker 日常管理中的位置Docker 日常操作绕不开三样东西镜像、容器、数据卷。镜像就是容器运行的模板你本地有多少镜像、每个镜像多大、标签是什么、是什么时候创建的这些信息全靠docker images来看。就像你手机里的相册不打开看永远不知道存了多少照片、占了多少空间。很多新手容易忽略的是镜像列表不是简单的看一眼就完事了。它承担了三个核心职责:第一盘查本地镜像资产搞清楚自己手上有什么第二排查磁盘占用定位哪些镜像该清理第三配合脚本做自动化比如批量删除、批量打标签、按条件导出。后面这两个职责单纯用不带参数的docker images是干不了的必须上参数。还有一个容易混淆的地方docker images是旧版命令Docker 后来把镜像相关的命令统一到了docker image子命令体系下所以docker images其实等价于docker image ls。两个命令输出一样参数也基本通用。我在下文统一用docker images来写但你在任何教程里看到docker image ls直接等价替换就行。1.2 命令形态与输出字段解读先看基本形态docker images [OPTIONS] [REPOSITORY[:TAG]]注意后面的[REPOSITORY[:TAG]]这是可选的仓库名和标签。你可以在命令后面直接指定镜像名来精确查询比如docker images nginx只看 nginx 相关的镜像。这里有个细节我想强调:如果你在镜像名后面不写 TAG比如docker images nginxDocker 只匹配标签为latest的镜像如果你想匹配所有标签得写成docker images nginx:*这种形式。这个坑我见不少人踩过后面会细说。不带任何参数执行时输出长这样REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 605c77e624dd 2 weeks ago 187MB mysql 8.0 b93ceab1a242 4 weeks ago 608MB redis 7-alpine 7a5f79b3d5a1 3 months ago 44.2MB一共六列仓库名、标签、镜像 ID、创建时间、大小。默认情况下镜像 ID 只显示前 12 位创建时间显示的是相对时间大小显示的是压缩后的可读格式。这些默认行为后面都会讲到怎么改。2. 常用参数逐个拆解每个都讲明白为什么这么用2.1 -a / --all:把隐藏的中间层镜像挖出来这是最容易让人困惑的参数。默认执行docker images时你看到的只是顶层镜像也就是你真正拉取或构建出来的那些。但实际上 Docker 在构建镜像的时候会生成很多中间层镜像这些中间层默认是隐藏的。加-a之后中间层镜像也会全部列出来。你可能会看到一大堆none:none的镜像这就是中间层或者是构建过程中产生的悬空镜像。这里我要多说一句:中间层镜像不是垃圾它们是构建缓存的一部分。如果你删除中间层下次重新构建相同 Dockerfile 时缓存就会失效构建时间会明显变长。所以看到none镜像先别急着清理要分清是中间层还是悬空的孤儿镜像。判断方法很简单:用docker images -a列出所有镜像后再看docker images --filter danglingtrue后者列出的才是真正的垃圾镜像。一个是从构建缓存角度看一个是从资源清理角度看完全是两码事。# 查看包含中间层的全部镜像 docker images -a # 只看悬空镜像真正该清理的 docker images --filter danglingtrue2.2 -q / --quiet:脚本化和批处理的王牌-q参数会让输出只显示镜像 ID其他信息全部省略。单独看好像没什么用但放到脚本里这是威力最大的参数。比如你想删除所有悬空镜像常规操作是先用docker images --filter danglingtrue -q拿到 ID 列表再传给docker rmi。命令长这样docker rmi $(docker images --filter danglingtrue -q)再比如你想把本地镜像全部删掉先拿到所有 ID再逐个删除docker rmi $(docker images -q)这里的$()是 Shell 的命令替换先把docker images -q的输出作为参数传给docker rmi。我实际写过很多类似的管道命令可以负责任地说-q是脚本化操作的基础。没有它你就得自己写 sed、awk 去截取 ID 列既容易出错又啰嗦。有一个细节必须提醒:如果本地有镜像正被容器使用docker rmi会直接报错。所以脚本里通常要配合docker ps -aq和docker rm先清理容器再清理镜像。顺序不能反这是我第一次写批量清理脚本时踩过的坑。2.3 --filter:按条件精准过滤--filter是 docker images 里最灵活的参数可以反复使用多个过滤器做组合条件。Docker 官方支持的过滤器有dangling、label、before、since、reference这几种。dangling前面已经用过就是筛选悬空镜像值为true或false。清理场景几乎必用。label是过滤标签的适合给镜像打上了自定义 label 的团队。比如构建时加了--label stageproduction查询时就这样写docker images --filter labelstageproductionbefore和since是时间维度的过滤按照镜像的创建时间来筛选。比如你想看最近 7 天创建的所有镜像先找个 7 天前的镜像作参照然后筛选docker images --filter sinceold-image:latestreference是过滤镜像名的支持通配符模式。例如只想看仓库名以 gitlab 开头的镜像docker images --filter referencegitlab*其实reference这个过滤器在工作中比想象中有用。多环境部署的时候本地可能同时存在registry.example.com/wms-api:1.2.0和registry.example.com/wms-web:1.2.0想快速筛出某个服务相关的所有版本一条命令就搞定不用再靠肉眼在一长串列表里找。多个过滤器可以叠加逻辑是 AND 关系。比如筛选悬空的并且创建时间在某镜像之后的docker images --filter danglingtrue --filter sincenginx:latest这个组合适合在磁盘告急时精确定位既悬空、又是最近构建产生的临时垃圾避免误删还在使用的旧镜像。2.4 --format:用 Go 模板定制你的输出--format是我个人最喜欢也最推荐的参数它允许你用 Go 模板语法来定义输出格式。默认的表格输出在镜像我多时很难看关键信息夹在一堆字符里肉眼扫起来费劲。常用的占位符有这些.ID镜像 ID.Repository仓库名.Tag标签.Digest镜像摘要.CreatedSince相对创建时间.CreatedAt绝对创建时间.Size镜像大小.Containers使用该镜像的容器数量举个例子只输出仓库名、标签和大小docker images --format table {{.Repository}}\t{{.Tag}}\t{{.Size}}table是强制显示表头不加的话就是纯数据行。这个区别很关键写脚本时如果想拿到干净的数据解析就不要加table人眼查看时建议加上可读性好很多。再比如你想查出被容器引用数量为 0 的镜像可以这样用docker images --format {{.Repository}}:{{.Tag}} {{.Containers}}这个信息对清理镜像特别有价值先看哪些容器数量为 0再决定动不动手。--format还可以配合模板的if条件做更精细的控制比如只打印尺寸大于 500MB 的镜像docker images --format {{if gt (atoi .Size) 500000000}}{{.Repository}}:{{.Tag}} {{.Size}}{{end}}当然这种复杂模板日常用得不多但关键时刻能救命。我用--format最多的场景是生成一份干净的镜像清单直接输出给同事或写进发布文档比截图清爽太多。2.5 --no-trunc 与 --digests:还原完整信息默认情况下镜像 ID 只显示 12 位日志完整 ID 是 64 位。--no-trunc就是让 ID 不再截断完整展示。这个参数平时用不上但有两个场景必须用:一是某次调试时需要精确指向某个镜像 ID但你想确认它的完整值二是配合脚本做精确匹配时短 ID 可能和另一个镜像的前缀冲突虽然概率极低但在自动化环境里还是用完整 ID 更稳妥。docker images --no-trunc另一个参数--digests是在输出里增加一列 DIGEST。摘要是镜像内容的哈希值同一个镜像不同标签可以有相同的 DIGEST这就能帮你识别出其实内容完全一样、只是打了不同标签的镜像。docker images --digests这个参数在排查为什么两个镜像占的空间一样大这种问题时很有用。看到 DIGEST 相同你就明白它们本质是同一份镜像内容只是标签不同清理时保留一个就行。2.6 --limit:限制输出数量--limit用来限制列出镜像的数量只对列出的镜像生效需要配合--filter才有实际意义。不加过滤器就限制数量那就只是单纯截断列表意义不大。常见用法是结合before或since取最近几个docker images --filter sincenginx:latest --limit 5这个组合在本地镜像极多、只想看最近构建的 5 个时很顺手。说实话日常使用频率不算高但了解它能避免在某些脚本场景里输出爆炸。3. 参数组合实战:三个高频场景直接抄作业3.1 场景一:一键清理悬空镜像给磁盘瘦身这是运维同学问得最多的场景。服务器跑一段时间磁盘满了一查发现全是none的悬空镜像。我推荐一个渐进式清理方案不要一上来就全删万一误删就麻烦了。第一步先看看悬空镜像有多少、占了多少空间docker images --filter danglingtrue第二步确认这些镜像确实没有被容器引用然后清理docker image prunedocker image prune是官方推荐的清理命令它会自动删除所有悬空镜像。当然你也可以用我前面写的组合命令手动删docker rmi $(docker images --filter danglingtrue -q)两者对比docker image prune更安全因为它是 Docker 内置的清理逻辑手动组合命令则更直观你能清楚看到每一步在做什么。我个人习惯在交互式环境里用docker image prune在脚本里用手动组合因为脚本里不希望有交互确认。注意docker image prune默认不会删除中间层缓存想连缓存一起清掉加-a参数docker image prune -a这条命令会删除所有没被容器使用的镜像包括带标签的。执行前务必确认没有重要的镜像只在本地存在、远端仓库没有备份这是我反复强调的一点。删镜像容易重新构建可能要花好几个小时。3.2 场景二:构建脚本里按需列出镜像用于版本发布写 CI/CD 脚本时经常需要判断某个版本的镜像是否已经构建成功。比如构建完成后你想校验myapp:1.2.0是否存在于本地。用--format和-q组合一行搞定if docker images myapp:1.2.0 --format {{.Repository}}:{{.Tag}} | grep -q myapp:1.2.0; then echo 镜像存在 else echo 镜像不存在 fi其实还有一个更直接的判断方法docker image inspect myapp:1.2.0能查是否存在但inspect在镜像不存在时会报错并输出一堆错误信息脚本里还得处理退出码反而不如 images 命令干净。再比如发布前要生成一份镜像清单做备份记录。我常用的一条命令docker images --format {{.Repository}}:{{.Tag}} {{.ID}} {{.Size}} {{.CreatedSince}} | column -t image_manifest_$(date %Y%m%d).txt这条命令把每个镜像的仓库、标签、ID、大小、创建时间整理成对齐的表格存成文件归档。配上定时任务就能形成一套最简单的镜像资产台账。3.3 场景三:镜像批量导出与迁移内网环境经常需要把镜像从一台机器迁移到另一台离线环境尤其如此。这时一般是先列出所有镜像再用docker save打包。关键是怎么把镜像列表变成docker save的输入。我的做法是docker save $(docker images -q) -o all-images.tar把本地所有镜像打包成一个 tar 文件拷贝到目标机器后执行docker load -i all-images.tar这里有个细节:如果镜像特别多打包文件会非常大有时候按仓库名分批导出更合理。比如只导出 nginx 相关的镜像docker save $(docker images --filter referencenginx* --format {{.Repository}}:{{.Tag}}) -o nginx-images.tar注意这里--format {{.Repository}}:{{.Tag}}得到的是完整的仓库名:标签列表直接作为 save 的参数。这种写法比-q更稳妥因为 save 命令需要的是镜像引用名称而不是 ID——虽然 ID 也能用但导入后镜像会丢失仓库和标签信息变成none:none。这是我实际踩过的坑当初图省事用-q导出结果在另一台机器 load 之后全是无名镜像又要重新打标签平白多折腾半小时。4. 常见问题与排查技巧实录4.1 docker images 和 docker image ls 到底啥关系前面提过docker images和docker image ls是同一个操作。Docker 从 1.13 版本开始引入docker image子命令体系把docker images、docker rmi这些顶层命令逐步收纳进子命令体系。但为了兼容历史脚本docker images这个老命令一直保留着。实际使用中两者参数完全一致输出也一致。唯一的区别是使用的命令族不同。我个人习惯在新脚本里写docker image ls因为这是官方推荐的写法但日常手敲的时候还是用docker images毕竟少敲几个字母肌肉记忆改不掉。你选哪种都行只要团队内统一。这里要提醒一下:Docker 的某些版本里docker images的输出和docker image ls在启用实验特性后可能有些微差异但正常稳定版不会遇到不用过度担心。4.2 列出来的镜像大小和实际占用对不上很多人发现docker images列出的大小总和和du -sh /var/lib/docker查出来的磁盘占用对不上于是怀疑命令有问题。其实这是正常的原因有两方面。第一镜像大小列显示的是镜像本身的逻辑大小不包含容器层。你运行了很多容器每个容器的可写层都会额外占磁盘images 命令不统计这部分。第二镜像之间共享层会复用一个基础镜像被多个镜像共用实际物理占用比逻辑大小总和要小。要查真实的磁盘占用建议用docker system df它会把镜像、容器、数据卷、构建缓存分开统计还有一个 RECLAIMABLE 列告诉你哪些可以回收docker system df这个命令配合docker images --filter danglingtrue基本能定位 90% 的磁盘异常问题。4.3 为什么 docker images 看不到刚拉取的镜像一种是网络或 registry 配置问题另一种是命令拼写问题。先说拼写:如果你指定了不存在的标签或者没写正确Docker 会拉取失败自然看不到。建议先不加任何参数docker images看一眼全量列表确认镜像是不是真的在本地。另一种情况在某些企业环境里配置了私有 registry 镜像源拉取后镜像仓库名带有完整的前缀比如registry.internal.example.com/myapp:1.0。你用docker images myapp去查是查不到的必须带上前缀或者直接用--filter reference*myapp*做模糊匹配。还有 Docker Desktop 在 Windows 上常见的启动失败问题报错是virtualization support not detected这时候镜像列表根本加载不出来。这个报错多半是虚拟化没开启或者 Hyper-V 相关组件没就绪解决思路是到 BIOS 里确认虚拟化开关再检查 Windows 的虚拟化功能是否启用。这不是 docker images 命令本身的错但确实是排查镜像列表时最容易遇到的拦路虎尤其是新手在第一台 Windows 机器上装 Docker Desktop 时经常碰到。遇到这类环境问题先把 Docker 引擎跑起来再回头谈镜像命令。4.4 常用参数速查表最后整理一份速查表方便贴在手边随时翻。参数作用典型组合-a列出中间层镜像docker images -a-q只输出镜像 ID配合 rmi 批量删除--filter danglingtrue筛出悬空镜像配合 prune 清理--filter referencexxx*按镜像名模糊匹配筛选指定服务--filter beforexx列出某个镜像之前创建的时间维度过滤--filter sincexx列出某个镜像之后创建的时间维度过滤--format自定义输出格式脚本解析、文档输出--no-trunc显示完整镜像 ID精确匹配--digests显示镜像摘要值判断镜像内容是否相同--limit限制输出条数配合过滤器取前 N 条最后分享一个我个人特别喜欢的小技巧。每次要写部署文档时我用这条命令直接生成一份干净的镜像版本表docker images --format table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.CreatedAt}}\t{{.Size}} -f danglingfalse比截图好看比手敲准确还能直接贴进 Markdown 表格继续加工。docker images 的每个参数单独看都不复杂但把它们组合起来你能覆盖镜像管理的绝大多数场景。用熟之后你会发现很多之前需要反复查询、手动拼装的活儿一条命令就解决了。
返回列表