平时接触 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 image prune。这个命令会删除所有“悬空镜像”,也就是已经没有标签、也没有被容器引用的中间层镜像。配合 -a 参数可以删除所有未被容器使用的镜像,但这里的“未被使用”判断条件比想象中宽,很多你还想保留着备用、准备拉回退版本的镜像也会被删掉。所以我平时只用 docker image prune -f 清理 dangling 镜像,不加 -a,除非确实需要释放大量磁盘空间。
还有一个容易忽略的点:docker rmi 删除的是本地镜像层数据,并不会自动删除远端仓库里的镜像。想真正删除远端镜像,得去仓库控制台或用仓库的 API。我们的私有镜像仓库里堆了很多老镜像,这个只能靠定期脚本去清理,docker 本身管不到那边。
2.4 镜像离线迁移:save、load 和 tag
内网环境或者数据合规要求高的项目里,没法直接从外网拉镜像,这时候就要用 docker save 和 docker load。docker save -o 文件名.tar 镜像名:标签,可以导出一个或多个镜像:
bash复制docker save -o nginx.tar nginx:1.25-alpine
docker load -i nginx.tar
需要注意,docker save 导出的是镜像层和元数据,不是容器快照。如果导出时包含多个镜像,load 之后都会恢复成独立镜像。跨机器迁移时,目标机器的 Docker 版本最好与源机器接近或更高,我遇到过低版本 Docker 加载高版本镜像结构时出现诡异错误的情况,换了版本后一切正常。
load 之后镜像名和标签通常还是原来的,但如果你希望机器上以另一个名字使用,可以 docker tag 给它打个别名。docker tag 原镜像名 新镜像名,本质上是给同一份镜像层数据增加一个引用标签,不会复制实际数据,所以非常轻量。我在做灰度发布时,经常会给同一个镜像打上版本号和环境名两个 tag,比如 app:1.2.0、app:prod。
2.5 inspect 和 history:镜像体检工具
docker inspect 能看镜像的完整描述,包括分层信息、环境变量、工作目录、默认命令、暴露端口、架构类型等。排查“为什么容器时区不对”或“为什么启动命令不对”时,第一步就是用 docker inspect 镜像名 看它的 Env、Entrypoint、Cmd、WorkingDir。它输出的 JSON 很长,我经常配合 jq 取字段:
bash复制docker inspect nginx:1.25-alpine --format '{{json .Config.Env}}'
docker history 则是看镜像构建历史的命令,能从上到下列出每一层由 Dockerfile 哪条指令生成、大小是多少。如果你发现镜像异常臃肿,docker history 是最直接的定位工具,哪一层体积大一眼就能看到,然后针对那一条 RUN 命令做优化。注意加 --no-trunc 参数可以看完整指令,但输出会很刷屏,适合定向排查。
3. 容器生命周期命令清单:从起一个容器开始
3.1 docker run 的完整用法与关键参数
docker run 是使用频率最高的命令,参数多到能写一本书,但绝大多数场景其实只需要掌握十几个关键参数。最基本的是 -d 后台运行、--name 指定容器名、-p 端口映射、-v 数据卷挂载、-e 环境变量注入、--restart 重启策略。举个例子,启动一个带密码的 MySQL 8 容器:
bash复制docker run -d \
--name mysql8 \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=Root@123456 \
-v /data/mysql:/var/lib/mysql \
mysql:8.0
这里 -p 3306:3306 表示宿主机 3306 端口映射到容器内 3306 端口。如果本地 3306 已经被占用,可以改成 -p 33061:3306,这样 Docker 依然正常跑,外部连的就是宿主机 33061 端口。很多新手一启动就报端口冲突,却不知道换端口,其实只要改左侧数字就行。
-v 参数是数据持久化命脉。容器删掉后,写在可写层里的数据会全部消失,所以数据库、配置文件、日志这类内容必须挂到宿主机目录。上面例子把容器内的 MySQL 数据目录映射到宿主机 /data/mysql,即使容器被 rm -f 删掉,数据也还安全。加 -e 场景最典型的是给容器注入初始化密码、时区变量,例如 TZ=Asia/Shanghai 可以解决容器内时间不对的问题。
还有一个参数我每次都会注意:--restart unless-stopped。它表示宿主机重启后,只要容器没有被手动 stop,就会自动拉起;但如果管理员主动 stop 过,就不会自动启动。这个策略比 always 更符合日常运维习惯,我一般默认用它。
3.2 容器的状态流转与查看命令
启动容器之后,第一件事就是确认它有没有跑起来。docker ps 列出所有运行中的容器,docker ps -a 连已退出的容器也一起列出来。看一个容器当前的状态,最后一列 STATUS 最有用:Up 表示运行中,Exited 表示退出,Restarting 表示不断重启中,Created 表示只创建还没启动。再配合 -q 参数可以只拿容器 ID,配合 --filter "status=exited" 可以筛出所有退出状态的容器。
我以前排查“容器为什么起不来”时,最喜欢用 docker ps -a | grep 容器名,看退出码和状态描述。Exit 0 通常表示程序正常结束;Exit 1 往往是应用启动报错,需要看日志;Exit 137 多半是内存或外部 kill 信号导致的。这些状态码是排查问题的第一层线索,配上 docker logs 才能定位到具体原因。
stop 和 kill 的区别也要说清楚。docker stop 容器名 会先发 SIGTERM,让容器内主进程优雅退出,等待超时后(默认 10 秒)再发 SIGKILL;docker kill 是直接发 SIGKILL,无情终结。能用 stop 就不要用 kill,尤其对数据库这类需要做持久化收尾工作的应用,优雅退出能减少数据损坏的概率。
3.3 进入容器与查看日志
进容器调试是日常刚需,命令核心是 docker exec 和 docker attach。强烈推荐用 docker exec,它是在运行中的容器里额外启动一个新进程,退出之后不影响容器主进程。典型用法:
bash复制docker exec -it mysql8 bash
-it 是 -i 和 -t 的组合,表示交互式终端。如果容器里没有 bash,可以试试 sh,busybox 之类极简镜像可能连 sh 都没有,那就用 docker exec -it 容器名 ls / 先看一下环境里有啥可用的命令。
docker attach 则是把当前终端直接连接到容器主进程的输入输出上,它的特点是:你用 Ctrl+C 退出时,实际上会给主进程发送中断信号,很多时候直接把容器给停了。我第一次用 attach 就踩了这个坑,那之后再也不主动用它,调试一律 exec。只有在需要看交互式程序前台输出时,attach 才有价值。
查看日志是 docker logs 的活。docker logs -f 容器名 可以实时跟踪,--tail 100 只显示最后 100 行,--since 5m 显示最近 5 分钟日志。对跑在后台的容器来说,这是第一排查手段。如果容器内部程序把日志写到文件而不是 stdout,docker logs 大概率看不到内容,这时候要 exec 进去看文件,或者当初启动时就挂载日志目录出来。
3.4 容器文件拷贝与资源监控
需要往容器里复制文件或者从容器里拷东西出来时,用 docker cp。用法很简单,docker cp 宿主机文件路径 容器名:容器内路径,反过来就是 docker cp 容器名:容器内路径 宿主机路径。我经常用它把宿主机上的配置文件覆盖进容器里临时生效,但要注意容器重启后文件可能丢失,正式场景还是要把配置做到镜像或挂载卷里。
资源监控有两个常用命令。docker top 容器名 显示容器内进程列表,相当于宿主机 ps 的容器视角,适合确认容器里跑了哪些进程,以及 PID 对应关系。docker stats 则是实时查看所有容器的 CPU、内存、网络、磁盘 IO 使用情况,类似任务管理器。docker stats 不带参数会一直刷新,带 --no-stream 参数可以只输出一次,方便脚本里采集。
我最常用的排查场景是内存超卖:容器频繁 OOM,用 docker stats 看内存占用,如果一直顶到上限,就需要加内存限制、优化 JVM 参数,或者检查是不是日志没轮转导致磁盘写满。资源类问题在容器世界里尤其隐蔽,很多系统服务“莫名其妙变慢”最后查出来都是 stats 里哪个容器吞掉大量资源。
3.5 删除容器的正确姿势
删除容器用 docker rm 容器名,可以一次删多个。如果容器还在运行,删除会失败,这时候要么先 stop 再 rm,要么直接用 docker rm -f 强制停止并删除。日常我几乎只用 -f,因为真正要删的容器多半已经不再需要了,优雅不优雅意义不大,但如果有重要未落盘数据,还是先 stop 再手动确认比较好。
批量清理更推荐 docker container prune,它会把所有已停止的容器删掉。加上 -f 参数免确认。如果想保留最近几个容器,可以用 --filter "until=24h" 只清理 24 小时之前停止的容器。我定期在测试机上跑一遍 docker container prune -f,配合 docker image prune -f,能明显释放磁盘空间。这里要注意,prune 只删宿主机上的容器,删除容器不会自动删除对应的镜像,镜像是另一个维度,需要单独清理。
4. 构建镜像必须掌握的 Dockerfile 命令清单
4.1 Dockerfile 高频指令与其背后的缓存逻辑
光会拉现成镜像不够,自己写 Dockerfile 才是真正把项目容器化的开始。高频指令拢共就这些:FROM 指定基础镜像,WORKDIR 设置工作目录,COPY 拷贝文件,ADD 拷贝并支持自动解压,RUN 执行构建命令,ENV 设置环境变量,EXPOSE 声明端口,CMD 设置默认命令,ENTRYPOINT 设置入口程序。每个指令都会生成一个镜像层,而 Docker 在构建时会尝试复用本地已有的层缓存,所以指令顺序对构建速度影响极大。
先看一下最典型的 Java 项目 Dockerfile:
dockerfile复制FROM openjdk:17-jdk-alpine
WORKDIR /app
COPY target/app.jar .
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]
这个例子虽然简单,已经覆盖了大多数场景所需的最小指令集。COPY 把构建好的 jar 放进镜像,CMD 指定启动命令。注意 CMD 的 JSON 数组写法,每个参数单独一个字符串,这是推荐写法;如果用 CMD java -jar app.jar,则走 shell 形式,进程会多一层 /bin/sh -c,信号处理会绕一道,程序退出时可能收不到信号,这是我的一个亲身教训。
缓存逻辑要重点说。Docker 执行 Dockerfile 时,如果当前指令与缓存层匹配,就会直接复用,不再执行对应操作。所以一般不变的东西放前面,经常变的代码放后面。依赖安装、包管理器缓存、基础工具下载是最重的操作,放在最前面可以大幅提高二次构建速度。如果 COPY 的文件内容变了,从这条 COPY 开始后面所有层都会失效,连重建带推送一起变慢。
4.2 RUN 的减负技巧与层数焦虑
写 RUN 命令时,最容易犯的错误是一条指令装一个包,结果写出十几个 RUN。每个 RUN 都会产生一层镜像,虽然层数和磁盘占用不是严格成正比,但层一多管理就麻烦。更关键的是,在安装依赖的过程中会产生大量临时缓存文件,如果不在同一层清理掉,它们会永久留在镜像里,白白增加几十到几百 MB 的体积。
一般做法是:多个安装操作合并成一条 RUN,用 && 连接,确保一条命令执行完所有安装和清理动作。比如:
dockerfile复制RUN apt-get update \
&& apt-get install -y curl unzip \
&& rm -rf /var/lib/apt/lists/*
这里的 rm -rf 是把 apt 缓存删掉,在构建阶段就能把体积减下来。如果分开写,就算后面再删,前面的层里依然残留着缓存数据。我见过一个镜像由 3GB 减到 900MB,就是靠合并 RUN 和删除缓存来实现的。
层数焦虑没必要过度。只要不是每个动作都单独成层、每一层还缓存了一堆垃圾,正常几十层完全没问题,Docker 对层数的效率优化做得很好。真正需要精简的是“不必要的文件被 COPY 进镜像”和“装了一堆运行时根本用不到的调试工具”,这两类才是镜像体积膨胀的元凶。
4.3 多阶段构建:把镜像从 1GB 减到 100MB
多阶段构建是 Docker 17.05 之后最值得掌握的功能。它的思路是:先用一个带完整编译工具链的镜像去构建项目,再把编译产物复制到一个干净的精简镜像里。最终发布的镜像只包含运行环境和产物,不包含编译器、依赖源码、缓存。
以一个前端项目为例:
dockerfile复制FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:1.25-alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
第一阶段 node 镜像负责 npm install 和 npm run build,第二阶段直接用 nginx 镜像把 dist 目录拷进去,最终镜像里没有任何 node、npm 或源码,只有静态文件。同理,Go、Java、Python 项目都可以用这个思路,构建阶段的镜像再大也没有关系,只要最终产物小就行。
多阶段构建还有个隐藏价值:它天然解决了“构建环境依赖和运行环境依赖不一致”的问题。很多项目编译时需要一堆 X 类库,运行时只需要 Y 类库,分成两个阶段后可以让两边各取所需。我接手过一个老项目,原先单阶段镜像里塞了 gcc、make、go 工具链,运行镜像 1.2GB,改成多阶段构建后发布镜像不到 120MB,部署速度肉眼可见提升。
4.4 .dockerignore 与构建上下文
docker build 默认把当前目录作为构建上下文,发送给 Docker 守护进程。上下文越大,构建越慢,而且如果里面有 node_modules、.git、target 这类大型目录,会把一堆没用的文件传到守护进程,甚至可能因为目录权限问题导致构建失败。正确做法是写 .dockerignore 文件,和 .gitignore 一个思路:
gitignore复制.git
node_modules
target
dist
*.log
.idea
.vscode
.dockerignore 的作用不仅是省时间,还直接影响缓存命中。如果你把 target 目录整个拷进去,里面哪怕一个临时文件变了,COPY 那层缓存就会失效,后面的依赖安装全要重来。所以在 Dockerfile 里 COPY 时,尽量只复制需要的最小文件集合,比如 COPY target/app.jar . 而不是 COPY target/ .,这样也能减少无效缓存失效。
5. 镜像之外的生态命令与高频坑
5.1 配置镜像加速器:让 pull 不再慢到怀疑人生
本地拉公共镜像慢,是很多国内团队每天都要面对的痛点。Docker 官方默认从 Docker Hub 拉取,这个服务在国内的连通性不够稳定,尤其拉一些比较大的镜像时经常超时。常规解法是给 Docker 配置 registry mirror,让 Docker 优先从镜像加速源拉取。
Linux 上修改 /etc/docker/daemon.json,加上 registry-mirrors 字段,然后重启 Docker:
json复制{
"registry-mirrors": ["https://docker.m.daocloud.io"]
}
需要注意,这个配置改的是镜像加速器,不是某个镜像私有仓库地址。加速器只对拉取公共镜像有作用,push 仍然走目标仓库地址。Docker Desktop 用户可以在 Preferences 的 Docker Engine 配置里直接改 daemon.json,改完 Apply & Restart 就行。
这里有个坑:不同加速源的效果和稳定性差异很大,而且有些加速源会临时失效。我的习惯是配置两个以上的镜像加速源,拉取失败的配置项放在前面,Docker 会按顺序尝试,但不确定会不会自动切换;更稳妥的方案是构建脚本里做个 fallback,拉取失败就换另一个镜像源重试。配置加速器不会影响你从私有仓库拉镜像,私有仓库镜像名带完整地址,走的是另一条路径。
5.2 Docker Compose 命令清单:一条命令拉起整套环境
用 docker run 管理多个容器时,命令会越来越长、关联关系越来越难维护,这时候就该上 Docker Compose。Compose 用 YAML 文件描述一组服务,命令集中在 docker compose 子命令下,一张命令清单就能覆盖大部分运维场景。
最常用的是 docker compose up -d,它根据 docker-compose.yml 或 compose.yaml 文件创建并启动所有服务。-d 表示后台运行。docker compose down 停止并删除所有服务相关容器和默认网络。docker compose ps 查看当前项目下的容器状态。docker compose logs -f 实时看所有服务的日志。docker compose config 可以校验并打印最终生效配置。
一个典型的 Redis 主从示例:
yaml复制services:
redis-master:
image: redis:7-alpine
container_name: redis-master
command: ["redis-server", "--appendonly", "yes"]
ports:
- "6379:6379"
redis-slave:
image: redis:7-alpine
container_name: redis-slave
command: ["redis-server", "--slaveof", "redis-master", "6379"]
depends_on:
- redis-master
执行 docker compose up -d,两个服务会自动创建网络和启动,容器之间可以用服务名直接通信。这里有个实用技巧:在 compose 文件里给容器起稳定的 container_name,这样后续用 docker exec redis-slave ... 等命令时不会因为容器名随机而找不到目标。
排障时 docker compose 也有自己的命令,比如 docker compose restart 重启某个服务、docker compose exec 服务名 bash 进入某个服务容器。注意这里的服务名是 compose 里定义的名称,不是容器名,别混了。Compse 项目默认使用当前目录名作为项目名,导致不同目录下的相同 compose 文件会生成不同网络和容器,多人协作时最好用 -p 参数显式指定项目名。
5.3 containerd 命令与 Docker Desktop 常见问题
不是所有容器环境都有完整的 Docker 命令。很多 Kubernetes 节点底层是 containerd,命令行工具变成了 ctr、crictl 或 nerdctl。crictl 是标准 Kubernetes 运行时命令工具,查看镜像用 crictl images,拉镜像用 crictl pull,列出容器用 crictl ps。nerdctl 则是兼容 Docker CLI 风格的 containerd 客户端,很多 docker 命令直接换成 nerdctl 就能用,例如 nerdctl build、nerdctl compose up。
Windows 用户最常见的问题之一是 Docker Desktop 启动时提示 “Virtualization support not detected”。这个报错基本指向 Windows 的虚拟化功能没有开启。排查顺序建议这样:先看 BIOS/UEFI 里 Intel VT-x 或 AMD-V 是否开启,再去 Windows 功能里确认虚拟机和 Windows 虚拟机监控程序平台是否勾选,最后在 PowerShell 里跑 systeminfo 查看 Hyper-V 要求是否全部满足。改完 BIOS 或系统功能后,必须重启电脑,Docker Desktop 才会继续正常启动。
还有一个高频坑是 Docker Desktop 的 Linux 容器和 Windows 容器模式切换问题。大部分镜像都是 Linux 容器,需要确保 Docker Desktop 右下角当前是 Linux containers 模式。如果你之前切到 Windows containers 再拉 Linux 镜像,可能会得到不兼容的报错,这时候切换回去再做一次清理。
5.4 用 alias 和速查表对抗命令遗忘
无论命令清单整理得多详细,真到夜深人静上线排障时还是会卡壳。我的个人习惯是给高频命令设置 alias,比如:
bash复制alias dps='docker ps --format "table {{.Names}}\t{{.Status}}"'
alias dpsa='docker ps -a --format "table {{.Names}}\t{{.Status}}"'
alias dlg='docker logs --tail 200 -f'
alias dex='docker exec -it'
把这些放进 ~/.bashrc 或 ~/.zshrc,日常工作能省很多敲键盘时间。但 alias 只能简化你自己的终端环境,换到一台新机器就没了,所以也不要太依赖它,还是得把原生命令记熟。
另外一个行之有效的做法是维护一份自己的速查表,不是网上抄来的,而是每次踩坑后自己补一条。我会把“容器名要放在命令最后”“端口映射左侧是宿主机、右侧是容器”“docker attach 用 Ctrl+C 会把容器停掉”这类血泪经验写进表格里。这份速查表现在已经成了我团队新成员入手的第一个学习文档,比任何系统教程都实用。
6. 整理一份镜像与容器命令速查清单
考虑到命令太多容易乱,我把最常用的命令按场景整理成一个速查表,方便直接贴到自己的笔记或团队文档里。以下是我个人实际在用的精简版本,保留了高频项,去掉了冷门参数。
| 操作场景 | 命令示例 | 说明 |
|---|---|---|
| 查看本地镜像 | docker images | 显示仓库、标签、ID、创建时间、大小 |
| 拉取镜像 | docker pull nginx:1.25-alpine | 指定标签,避免 latest 误用 |
| 删除镜像 | docker rmi 镜像ID | 删除未被容器引用的镜像 |
| 清理悬空镜像 | docker image prune -f | 删除无标签中间层镜像 |
| 导出镜像 | docker save -o nginx.tar nginx:1.25-alpine | 用于离线迁移 |
| 导入镜像 | docker load -i nginx.tar | 从 tar 文件加载镜像 |
| 查看镜像详情 | docker inspect 镜像名 | 查看配置、环境变量、入口命令 |
| 查看构建历史 | docker history 镜像名 | 排查镜像体积来源 |
| 启动容器 | docker run -d --name app -p 8080:80 镜像名 | 后台运行并映射端口 |
| 查看运行容器 | docker ps | 只看运行中的 |
| 查看所有容器 | docker ps -a | 包含已退出容器 |
| 进入容器 | docker exec -it 容器名 bash | 在运行中的容器里开交互终端 |
| 查看日志 | docker logs -f 容器名 | 实时跟踪日志输出 |
| 停止容器 | docker stop 容器名 | 优雅停止 |
| 强杀容器 | docker kill 容器名 | 直接 SIGKILL |
| 删除容器 | docker rm -f 容器名 | 停止并删除 |
| 清理停止容器 | docker container prune -f | 删除所有已停止容器 |
| 拷贝文件 | docker cp 宿主路径 容器名:容器路径 | 宿主机到容器 |
| 资源监控 | docker stats --no-stream | 查看所有容器资源占用 |
| 构建镜像 | docker build -t 仓库名/镜像名:标签 . | 当前目录作为构建上下文 |
| 多阶段构建 | 见 Dockerfile 示例 | 编译产物拷贝到精简镜像 |
| 编排启动 | docker compose up -d | 按 compose 文件创建启动服务 |
| 编排停止 | docker compose down | 停止并删除 compose 服务 |
表格只能帮你快速定位命令,真正的理解还是要回到分层镜像和容器生命周期这两个底层概念。命令记不住没关系,知道自己能在哪一步用什么工具排查,比背一堆参数更有用。
我个人在实际操作中最大的体会是:Docker 命令不是背出来的,是“用出来”的。每踩一个坑,就在心里给自己标记一次,下一次手自然就记住了。比如我曾经用 docker attach 退出时把生产环境容器给停了,那之后我每次看到 attach 都条件反射地想到 exec;我也曾经因为镜像 tag 不写版本号,半夜遇到旧代码问题,从那以后我对 latest 标签的警惕性高得不得了。命令清单可以帮你起步,但真正让你成为高手的,还是反复演练和对失败案例的分析。
