平时接触 Docker,最容易遇到的情况就是:知道它好用,但一上命令行就卡壳。我自己最早也是靠一页命令清单撑过来的,pull 什么、run 什么、进容器用什么、删镜像用什么,全是小抄上的内容。后来在项目里反复踩坑、反复查文档,才慢慢把 Docker 镜像相关的命令串成体系。这篇就把我这些年常用的 Docker 镜像命令清单整理一遍,连着镜像原理、容器生命周期、Dockerfile 构建、Compose 编排一起聊透,适合刚上手 Docker 的运维或开发同学,也适合当团队内部速查文档。
1. 先把镜像这个概念揉碎了说清楚
1.1 镜像不是“一个文件”,而是一堆只读层的叠加
很多人一开始都会把 Docker 镜像理解成一个类似 ISO 的安装包,这种理解不算错,但会导致后面看不懂镜像为什么能省空间、容器为什么能秒起。更准确的说法是:镜像其实是由一层一层只读文件系统叠加出来的,每一层对应 Dockerfile 里的一条或几条指令,层与层之间靠 UnionFS 这类机制合并成一个完整的根文件系统。
我常用一个类比来解释:镜像就像一个千层糕,每一层都有自己的内容,有的是系统基础环境,有的是安装好的依赖库,有的是我们拷贝进去的代码。Docker 在启动容器时,并不会把这个千层糕重新复制一份,而是在最上面再加一层可写层,这一层只属于当前容器。容器里所有写操作都发生在这一层,下面这些只读层可以被多个容器共享。
理解了这一点,再看命令就非常直观。docker pull 拉的不是单一二进制文件,而是一组带元数据的分层信息;docker push 推送时如果远端已经有相同层,甚至可以复用,秒传完成。这也是为什么 Docker 镜像比传统虚拟机模板瘦这么多、分发速度快这么多。很多刚入门的同学会疑惑“怎么容器里改的东西一删容器就没了”,答案就在这里:底层只读层没变,可写层跟着容器一起扔掉了。想保留修改,要么 commit,要么用数据卷,要么把它写回 Dockerfile 重新构建。
1.2 镜像与容器的关系,像“类”和“实例”
如果写过代码,用“类与实例”来理解镜像和容器是最好的。镜像是静态的、可以复制的定义,容器则是由镜像动态创建出来的运行实例。一个镜像可以同时启动多个容器,相互之间环境隔离,端口可以映射到宿主机的不同位置,文件系统在可写层上彼此独立。
实操中很多人会把 docker pull 和 docker run 混着说,实际上 pull 只是把镜像从仓库下载到本地,run 则是用本地镜像创建并启动容器。如果本地没有这个镜像,docker run 会自动触发一次 pull,这就是为什么有时候直接 run 也能成功启动。但这个“自动”也带来一个隐藏问题:如果远程仓库镜像标签被更新了,而本地已经缓存了旧镜像,直接 run 时 Docker 可能不会主动重新拉取,导致启动的还是旧版本代码。我在这里吃过好几次亏,尤其排查“为什么我改了镜像,跑起来还是旧代码”的时候,十有八九是本地缓存了 old tag。
所以我的习惯是:需要明确版本时,直接在 tag 里写死版本号,不用 latest;上线前最好自己 pull 一次或用 docker image inspect 看一下本地镜像创建时间。镜像与容器的边界要想清楚,命令才不会用乱。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 镜像管理命令清单:拉、查、删、导
2.1 查看本地镜像的三板斧
最基础的命令是 docker images,等价于 docker image ls。它展示五列信息:仓库名(REPOSITORY)、标签(TAG)、镜像 ID(IMAGE ID)、创建时间(CREATED)和大小(SIZE)。我一般只关注前两列和最后一列,前三列反而容易造成误解,因为 IMAGE ID 显示的是短 ID,长 ID 被截断了,不能直接拿来作为唯一标识去 pull 或 run,需要配合 docker inspect 看完整值。
如果需要脚本化处理,docker images -q 可以只输出镜像 ID,docker images --digests 会多显示仓库摘要,用来确认这个镜像具体对应哪个远端版本。最有用的是 --format 参数,可以按 Go 模板提取字段,例如:
bash复制docker images --format "table {{.Repository}}:{{.Tag}}\t{{.Size}}"
这个输出格式我在写监控脚本时经常用。还有一个小提醒:docker images 命令只会显示本地所有顶层镜像,如果中间层镜像没有被引用,不会出现在默认列表里。想看完整的中间层,需要 docker image ls -a,我平时几乎不看,但排查镜像占用空间时会打开。
2.2 拉取和推送镜像,最好别用默认 tag
docker pull 的基本写法是 docker pull 仓库地址/镜像名:标签。仓库地址不带时默认走 Docker Hub。例如 docker pull nginx:1.25-alpine,就是拉取 nginx 官方仓库里标签为 1.25-alpine 的镜像。这里最重要的习惯是不要裸写 docker pull nginx,除非你明确知道自己要 latest。
latest 标签本质是个变动的指针,今天拉的和下周拉的可能不是同一个版本,甚至同一个镜像名的 latest 在不同架构下内容也不一样。我们的项目现在统一要求:开发环境至少锁定次版本号,生产环境锁定精确版本,必要时连摘要一起锁。例如 docker pull nginx@sha256:1234...,这种写法可以精确到一个不可变的镜像内容,但日常用起来稍显啰嗦。
推送镜像前需要 docker login 登录目标仓库,自建私有仓库就用 docker login registry.example.com。推送命令是 docker push 镜像名:标签。如果你要推送到非默认端口或非 443 的私有仓库,镜像名也得带上完整仓库地址,比如 docker push registry.example.com:5000/nginx:1.25-alpine。很多新人第一次 push 失败,原因就是镜像名没带仓库地址,Docker 默认把它当成 Docker Hub 仓库去处理。
2.3 删除镜像:rmi、prune 和强制删除的代价
删除本地镜像的命令是 docker rmi 镜像ID或镜像名,可以一次跟多个参数。如果镜像正被某个容器使用,普通 rmi 会被拒绝,报 conflict,这时候要先删容器,或者用 docker rmi -f 强制删除。不过我强烈不建议动不动就用 -f,因为强制删除会让引用这个镜像的容器处于一种很尴尬的状态,虽然容器还能跑,但镜像信息已经不完整了,排障时非常容易误导人。
更稳妥的清理方式是 docker
