要说 Docker 最让人头疼的地方,不是它有多少新概念,而是命令行工具里动不动就是几十个参数、几十条子命令。我刚接触那会儿也走了不少弯路:容器跑不起来不知道看哪里,端口映射不通怀疑镜像有问题,后来才发现是网络模式没选对。我把平时真正会用到的指令按场景整理了一遍,顺手把容易踩的坑也标了出来。这份内容适合两类人看:一类是刚把 Docker 装好、还不知道怎么下手的新手,另一类是会敲 docker run 但部署和排障总要临时翻文档的开发者。读完你可以把它当成一份可持续使用的速查手册,而不是收藏完就吃灰的清单。
我尽量不讲太高深的理论,只聊实际怎么用、为什么这么用、以及哪些参数组合会坑你。指令以 docker CLI 为核心,从容器生命周期一直讲到 Compose 项目级操作,覆盖开发、测试、上线前常用的几大场景。
1. 容器生命周期:run 全家桶和它背后的一长串状态
1.1 用 run 创建容器,参数要按场景记住
docker run是把镜像变成运行中容器的唯一入口,也是大多数人的第一个 Docker 命令。它的完整写法是:
docker run [选项] 镜像 [命令] [参数...]日常开发里最常用的一套参数大概长这样:
docker run -d \ --name demo-api \ -p 8080:80 \ -v /home/test/app-code:/app \ -e APP_ENV=production \ --restart unless-stopped \ demo/api:latest逐条拆开说:
-d表示后台运行,不会占住当前终端。配合日志命令使用,是服务类容器最常见的启动方式。--name给容器起个唯一名字。如果不指定,Docker 会随机生成一个名字,后续 stop、logs、exec 的时候特别难记。我强烈建议正式环境一律用--name。-p 8080:80表示把宿主机的 8080 端口映射到容器内的 80 端口。这里有个很容易搞反的位置:左边是宿主机端口,右边是容器端口。第一次用的时候写反的人不在少数。-v /home/test/app-code:/app表示目录挂载。左边宿主机路径,右边容器内路径,规则跟端口一样。-e APP_ENV=production是向容器里注入环境变量。不同镜像定义的环境变量名称不同,比如 MySQL 镜像通常用MYSQL_ROOT_PASSWORD。--restart unless-stopped表示容器异常退出或宿主机重启后自动拉起,除非是你手动 stop。这个参数对长期跑的服务非常有用。
还有一个--rm参数,它会让容器在退出时自动删除。它适合临时跑一次性命令的场景,比如:
docker run --rm -it ubuntu:22.04 bash如果你给一个长期运行的容器加了--rm,容器一旦异常退出就会被直接删掉,连日志都没机会保留,所以服务类容器不推荐加--rm。
-it是另外两个参数的组合,展开来是-i和-t。-i保持标准输入打开,-t分配一个伪终端。想进入容器交互式操作时离不开这俩参数,比如docker run -it ubuntu:22.04 bash。去掉-t的情况下,很多命令的交互界面会显示异常,比如缺少终端控制字符。
1.2 查看容器状态,不要只盯着 docker ps
docker ps只显示当前正在运行的容器,这本身就藏了个坑:容器退出后,你明明记得自己启动过,但docker ps里就是看不到。这时候需要加-a参数,显示所有容器,包括已退出的:
docker ps -a看到全部容器之后,你会遇到另一个麻烦:容器一多,光靠人眼找目标太累。加过滤条件或者定制输出格式会直观很多:
docker ps -a --filter "status=exited" docker ps -a --format "table {{.Names}}\t{{.Image}}\t{{.Status}}"--filter "status=exited"能筛出所有已退出的容器,清理的时候配合删除命令特别好用。--format则让你自定义输出列,脚本里抓容器名非常方便。
看容器状态时,还要习惯关注退出码。退出码 0 表示容器正常结束,非 0 意味着当时发生了什么异常。这块我会在后面的排查章节展开,先说一个最常见的现象:容器一直处于 restarting 状态,说明它启动即崩溃,而 Docker 正在按 restart 策略不断重启它。这时候要抓紧看日志,而不是反复重启。
1.3 停止、删除、重启:别把 rm 和 rmi 混着用
容器的启停指令很直接:
docker start 容器名 docker stop 容器名 docker restart 容器名 docker kill 容器名stop和kill的区别值得说一说。stop会先给容器主进程发 SIGTERM 信号,让它有机会做退出前清理动作;如果超时还没退出,再发 SIGKILL 强制结束。kill则是直接发 SIGKILL,不留情面。正常情况下优先用stop,只有容器卡死、怎么都停不下来的时候才用kill。
删除容器对应的是docker rm,注意别和删除镜像的docker rmi搞混,这两个命令名字只差一个字母,但作用完全不同。我之前就见过有人把docker rm mysql当成删除镜像来用,结果把运行中的 MySQL 容器删掉了。
docker rm 容器名 docker rm -f 容器名rm只能删除已停止的容器,如果容器还在运行,需要加-f强制删除。-f会先强制终止容器再删除,所以生产环境用之前一定要确认容器不是不可中断的服务。
批量清理退出容器的常用写法是:
docker rm $(docker ps -aq --filter "status=exited")这条命令先找出所有退出状态的容器 ID,再逐一把它们删除。如果机器上已经没有任何退出容器,命令会在docker rm这边报“参数为空”的错误,不影响其他操作。如果想把机器上的容器全部清掉,可以这样写:
docker rm -f $(docker ps -aq)这条命令风险很大,一旦执行,所有容器都会消失,包括运行中的。我只建议在彻底不需要的测试机上使用。
1.4 进入容器用 exec,不要依赖 attach
进入运行中容器的最常用方式是:
docker exec -it demo-api bashexec会在容器里启动一个新进程,然后通过终端连接到这个新进程。你在这个新进程里做的操作不会影响容器的主进程,关掉终端也不会导致容器退出。
不少人一开始会误用docker attach。attach是把当前终端直接连到容器的主进程上。问题是,你在 attach 的终端里按 Ctrl+C,可能直接给主进程发去中断信号,导致容器停了。我吃过这个亏:在 attach 终端里想退出,结果把整个服务干掉了。所以日常调试尽量用exec,少用attach。
有时候容器很精简,连 bash 都没有,那就用sh:
docker exec -it nginx sh还有一点:进入容器后默认是 root 用户,但有些生产镜像出于安全考虑会禁用 root。此时用-u指定用户即可:
docker exec -it -u www-data demo-api bash在容器内做调试时,建议只读,不要随手改文件。容器是临时状态,重启后会丢,改了也白改,真要改配置应该回宿主机改挂载目录或者重新构建镜像。
2. 镜像管理:从 pull、tag 到 build、save/load 的完整闭环
2.1 拉镜像和打标签,先理解仓库路径结构
拉取镜像几乎人人都会:
docker pull nginx docker pull mysql:8.0 docker pull registry.example.com/team/app:v1.0第二条能看懂,第三条的含义就需要解释一下了。镜像的完整名称由三段组成:仓库地址、命名空间、镜像名和标签。如果省略仓库地址,默认去官方仓库拉取;如果省略标签,默认拉取latest。
latest虽然方便,但对正式部署来说是个定时炸弹。因为同一个latest今天和明天的镜像内容可能完全不一样,那么你在服务器上拉到的构建版本就不再可控。真实项目里应该给镜像打上明确的版本号,比如demo/api:v1.2.0。
docker tag起到的是“复制引用”的作用,不是复制镜像实体:
docker tag demo-api:v1.0 registry.example.com/team/demo-api:release-1.0给本地镜像补一个带仓库地址的标签后,才能推送到远端仓库。因为推送时镜像名里必须包含目标仓库的完整路径。
想确认镜像到底存在哪里,可以用:
docker images docker image ls这两条等价。看的时候关注两点:IMAGE ID是不是多个标签共用同一个 ID,以及镜像大小是否异常膨胀。多个标签指向同一个 ID 时,删除其中一个标签不会释放空间,只有所有引用都删完,镜像本身才会被清理。
2.2 用 Dockerfile 构建镜像,上下文目录比 Dockerfile 更重要
构建镜像的核心指令是:
docker build -t demo/api:v1.2 .这条命令里,-t指定构建后的镜像名和标签,最后的.叫上下文路径。很多人会以为.只是告诉 Docker“Dockerfile 在当前目录”,实际上它表示“把当前整个目录发给 Docker 守护进程”。也就是说,上下文里的所有文件都会被传入构建环境。如果你在一个包含几 GB 日志、依赖目录的文件夹里执行 build,整个过程会非常慢,因为 Docker 要先把整个目录打包传输。
解决办法很简单:在项目根目录放一个.dockerignore文件,语法类似.gitignore:
node_modules .git *.log .cache dist这样构建时这些目录和文件就不会被发送给守护进程,既加快速度,也避免把密钥、日志等敏感内容打进镜像。
构建过程还有两个高频参数:
docker build --no-cache -t demo/api:v1.2 . docker build --target release -t demo/api:v1.2 .--no-cache用于强制重新下载依赖和执行所有层,适合排除了“缓存导致构建结果不对”的情况。--target用于多阶段构建中指定构建到哪一层,比如只构建到builder阶段,不产出最终精简镜像。
构建的时候如果发现某一步执行了RUN却没有任何输出变化,大概率是 Docker 层缓存生效了。判断是否真的用了旧缓存的标志是构建日志里有CACHED字样。想彻底重建,就使用--no-cache。
2.3 镜像离线迁移用 save/load,别用 export/import 结果来装镜像
在内网或离线环境部署,经常要把镜像从一台机器搬到另一台。最稳的组合是:
docker save -o nginx-1.27.tar nginx:1.27 docker save nginx:1.27 | gzip > nginx-1.27.tar.gz docker load -i nginx-1.27.tar docker load < nginx-1.27.tar.gzsave会保留镜像的层级结构、历史元数据、标签信息,load加载后得到的还是完整镜像,可以直接 run,也可以 push。文件体积大时,建议搭配 gzip 压缩再传输,能省很多带宽。
这里要特别提醒一句:不要用docker export/import来做镜像迁移。export针对的是容器,导出的只是容器的文件系统快照,不带镜像层信息、环境变量、默认启动命令都会丢失。导出后导入得到的是个“裸文件系统”,用它来当镜像跑,往往起动不了或缺少变量。区别概括一下:镜像用save/load,一次性容器快照才用export/import。
2.4 清理镜像,rmi 和 prune 一起配合
删除单个镜像用docker rmi:
docker rmi demo/api:v1.0 docker rmi $(docker images -q demo/api)如果后续的这个镜像正在被某个容器使用,删除会报错。可以先停容器、删容器,再删镜像。
更常见的“悬空镜像”(dangling image)清理方式是:
docker image prune悬空镜像指的是构建时被覆盖、已经没有标签引用的旧镜像层,留着白白占空间。prune会把这些<none>镜像清掉。如果是开发机,偶尔跑一下没问题。
真正危险的是:
docker image prune -a-a会把所有没有被容器使用的镜像全部删除,包括你精心构建、准备稍后部署的版本。这个命令一旦执行,只能重新拉取。在 CI 临时环境或资源紧张的测试机上可以考虑,生产环境请务必三思。
3. 数据卷与网络:这两块最容易翻车,也是最需要提前规划的地方
3.1 持久化不是把数据写在容器里,而是挂到宿主机上
容器本身是临时状态,删掉容器,容器内写入的文件就全部消失了。想让数据留存,必须用卷。
Docker 里有两类持久化方式:绑定挂载和命名卷。
绑定挂载就是把宿主机目录直接挂进容器:
docker run -d --name demo-web \ -v /home/test/website:/usr/share/nginx/html \ nginx:1.27宿主机上的/home/test/website会直接映射成容器内的网站根目录。好处是宿主机改文件,容器内立刻能看到,非常适合本地开发。代价是你需要小心宿主机的目录权限和属主,容器内进程没有权限写入时会报权限错误。
命名卷是由 Docker 管理的存储区域:
docker volume create app-data docker run -d --name demo-db \ -v app-data:/var/lib/mysql \ mysql:8.0app-data是卷名,/var/lib/mysql是容器内数据目录。MySQL 数据会写到app-data卷里,容器删除后卷依然存在,重新创建容器时指定同一个卷名,旧数据就回来了。
命名卷的好处是不用关心数据散落在宿主机的哪个具体路径,还能被多个容器共享。查看和管理卷用这几条:
docker volume ls docker volume inspect app-data docker volume rm app-data docker volume prunedocker volume prune会删除所有没被容器使用的卷。这里我想多提醒一句:单独的一份system prune并不会删除卷,卷要单独清理。很多人以为已经清理干净了,实际磁盘空间几乎没有变化,原因多半就是卷还赖在系统里。
绑定挂载和命名卷的选择原则很简单:开发调试、需要直接看文件时用绑定挂载;正式服务和数据库用命名卷。
3.2 文件进出容器,靠 docker cp
容器与宿主机互拷文件用docker cp:
docker cp demo-web:/etc/nginx/nginx.conf ./nginx.conf docker cp ./index.html demo-web:/usr/share/nginx/html/index.html第一个命令把容器里的 nginx 配置拷出来,第二个把宿主机里的 html 文件放进容器。
这个命令在排查问题时非常有用。比如容器里的服务读不到某个配置文件,你可以在宿主机准备好正确版本,cp进去再重启容器验证。注意cp只能用于复制文件,不能修改容器内文件权限和属主,涉及到属主问题还是得用 exec 处理。
3.3 网络:默认 bridge、自定义网络和 host 模式
Docker 默认提供了三种网络模式:bridge、host、none。查看:
docker network ls默认情况下,容器都跑在名为bridge的默认网络中。同一个默认网络里的容器可以用 IP 互相访问,但问题是 IP 会随容器重建变化,很不稳定,而且默认网络不支持容器名解析。也就是说,在容器 A 里直接用容器名访问容器 B 是不行的。
解决办法是创建自定义 bridge 网络:
docker network create demo-net创建时把容器都加入这个网络:
docker run -d --name demo-api --network demo-net demo/api:latest docker run -d --name demo-web --network demo-net nginx:1.27自定义网络自带 DNS 解析,demo-web容器里直接curl http://demo-api:8080就能访问到 API 容器。这不仅消除了 IP 变化问题,也让服务之间的地址变得可读。
已经启动的容器想加入某个网络,不需要重启:
docker network connect demo-net demo-db docker network disconnect demo-net demo-dbconnect是动态操作,很多时候比重新创建容器灵活得多。排查问题时可以先让容器临时加入某个网络,试验完再断开。
host模式则是完全不同的思路:
docker run -d --name demo-api --network host demo/api:latesthost 模式下容器不再拥有独立网络栈,直接共享宿主机网络,也就是说不需要-p做端口映射,容器内监听什么端口,宿主机就监听什么端口。优点是网络性能好、延迟低,缺点是端口冲突风险高,隔离性弱。除非你有明确的性能需求,否则不推荐默认使用 host 模式。
三种模式的选择,我建议记一个原则:容器间需要互相访问就建自定义网络,不需要通信就各自用默认 bridge 网络;只有追求极低延迟的本地工具类容器才考虑 host。
3.4 端口映射查证:docker port 比 ps 好用
排查端口问题时,我经常用docker port:
docker port demo-api它会输出容器端口和宿主机端口的对应关系。比docker ps里那一长串PORTS列直观很多。它显示的格式一般是:
80/tcp -> 0.0.0.0:8080看到这个就知道,访问宿主机的 8080 就会转发到容器的 80 端口。
4. 日志与资源:排障时最能救命的那组命令
4.1 日志先看 tail 和 follow,再谈其他
查看容器日志的基础命令是:
docker logs demo-api不加任何参数时,会把容器启动以来写入标准输出的全部日志打出来。如果日志很多,终端直接淹没。日常用得最多的是组合参数:
docker logs -f --tail 200 demo-api-f表示持续跟踪输出,类似tail -f。--tail 200表示只显示最近 200 行。先看最近日志,再决定是否往上翻,这是排障的固定节奏。
按时间过滤也经常用到:
docker logs --since 30m demo-api docker logs --until 10m demo-api--since 30m是近 30 分钟的日志,--until是比较冷的用法,一般配合排查特定时间窗口的异常。
一个很容易忽略的点:docker logs只能看到容器主进程写入标准输出或标准错误的内容。如果容器里的应用直接写日志文件而不打 stdout,docker logs什么都看不到。遇到“容器没日志”的情况,先确认应用日志是输出到控制台还是写到文件。写文件的场景下,要么改应用配置,要么用 exec 进入容器查看对应日志文件。
日志体积无限增长也是个常见隐患。可以在启动时给日志加上轮转限制:
docker run -d --name demo-api \ --log-driver json-file \ --log-opt max-size=10m \ --log-opt max-file=3 \ demo/api:latest这样单份日志最大 10MB,最多保留 3 份。不配置这个参数,跑上一段时间后,/var/lib/docker里的日志文件会悄悄吃满磁盘。
4.2 inspect 是一台侦探工具,别只会 cat
docker inspect输出的是容器完整配置和运行时状态,内容非常长,实际使用中不推荐整段硬看:
docker inspect demo-api > demo-api.json更多时候是用它来提取某个字段。比如只看容器状态:
docker inspect -f '{{.State.Status}}' demo-api只看 OOM 标志:
docker inspect -f '{{.State.OOMKilled}}' demo-api只看挂载信息:
docker inspect -f '{{json .Mounts}}' demo-api | jq这里的关键是-f配合 Go 模板语法。如果你不熟悉模板,记两个最基础的就够用:字段路径用点号逐级深入,用{{json .某字段}}输出 JSON 格式。OOMKilled字段是排查内存超限被杀的核心指标,很多时候容器显示 exited,但原因不明,就是它。
内存或 CPU 飙升的时候,docker top可以用来查看容器内进程的实时视图:
docker top demo-api它展示容器内各进程的 PID、用户、CPU 占用和启动命令,是确认“容器里到底哪个进程在消耗资源”的第一手信息。
4.3 实时资源看板与资源配置限制
docker stats是最直观的资源看板:
docker stats docker stats --no-stream不加参数时它会持续刷新,按 Ctrl+C 退出。--no-stream表示只输出一次当前快照,适合用来抓瞬时状态。输出里包含 CPU 使用率、内存使用、网络 IO、磁盘 IO。生产环境要留意的是内存和 CPU 占用,如果某个容器长期接近资源上限,就要优化应用或增加实例数。
限制容器资源配额是在 run 时指定参数:
docker run -d --name demo-batch \ --cpus=1.5 \ --memory=1g \ --memory-swap=1g \ demo/batch:latest常见参数对照:
| 参数 | 作用 | 示例 |
|---|---|---|
--cpus | 限制最多使用几个 CPU 核心 | --cpus=1.5 |
--memory/-m | 限制内存上限 | --memory=1g |
--memory-swap | 限制内存加交换分区总和 | --memory-swap=1g |
--pids-limit | 限制容器内可创建的进程数 | --pids-limit=200 |
--memory-swap有个细节:它要大于--memory。如果设置的是--memory=1g --memory-swap=1g,意味着容器最多用 1G 内存,而且不允许使用交换空间,内存一到上限就可能被 OOM 杀掉。如果你希望允许容器在内存吃紧时使用交换,可以把 swap 设成 2g。
不设置这些限制的后果,我在实际环境里看过太多次:某个容器的应用出现内存泄漏,把整台宿主机的内存吃满,其他服务全部变慢甚至宕机。所以只要是在同一台机器上跑多个容器,就必须加配额。这不是可选优化,而是基本操作。
4.4 看退出码快速判断死因
容器退出后,第一件事就是看退出码。常见对应关系如下:
| 退出码 | 含义 | 常见场景 |
|---|---|---|
| 0 | 正常退出 | 任务执行完成,或主进程正常关闭 |
| 130 | 128 + 2,被 SIGINT 中断 | 有人用 Ctrl+C 中断了前台容器 |
| 137 | 128 + 9,被 SIGKILL 强制杀死 | 手动docker kill,或被 OOM 杀 |
| 143 | 128 + 15,被 SIGTERM 终止 | docker stop发信号后容器退出 |
| 127 | 命令找不到 | 启动命令或 exec 里的命令在镜像里不存在 |
拿到退出码之后,再配合docker inspect -f '{{.State.OOMKilled}}' container验证是否 OOM。如果确实被 OOM 杀掉,优先排查应用内存占用,而不是盲目重启。重启只会重复相同的结果。
5. Compose 指令:把常用操作从单容器扩展到项目级编排
5.1 compose 的日常命令和 Docker 原生命令的对照
单容器用 docker 命令没问题,项目一多、服务一多,就得用 Compose。它的核心文件是compose.yaml或docker-compose.yml,里面定义了一组服务。在最常见的用法下,命令从docker run变成了:
docker compose up -d这条命令会读取当前目录下的 Compose 文件,把里面定义的所有服务构建、创建并启动,-d表示后台运行。这里有个 Google 提醒:docker compose是新的子命令写法,老式写法docker-compose是一个独立工具,命令参数略有差异,本文以新版docker compose为准。
项目管理的几个对照:
| 操作 | 原生命令 | Compose 命令 |
|---|---|---|
| 查看所有服务状态 | docker ps | docker compose ps |
| 查看日志 | docker logs 容器名 | docker compose logs 服务名 |
| 进入服务容器 | docker exec -it 容器名 sh | docker compose exec 服务名 sh |
| 停止服务 | docker stop 容器名 | docker compose stop |
| 删除服务容器 | docker rm 容器名 | docker compose rm |
| 停止并删除 | 多条命令组合 | docker compose down |
定位更精确的日志命令:
docker compose logs -f --tail=50 apiapi是 Compose 文件里的服务名,不是容器名。Compose 会自动管理容器名的前缀和序号,所以日常操作直接按服务名来,比记容器名省心得多。
5.2 配置变更和重建镜像时的常用组合
Compose 项目改动配置后,不需要down再up,直接执行:
docker compose up -dCompose 会检测配置或镜像变化,按需重建服务。如果你改了 Dockerfile,希望重新构建镜像再启动,用:
docker compose up -d --build--build会先重新构建涉及的服务镜像,再更新容器。这样避免了你手动 build 之后再 up 的两个步骤。
单独运行某个服务的临时命令,用:
docker compose run --rm db sh这个命令不会启动项目里的其他服务,只启动db服务并执行sh,退出后自动删除容器。用来做一次性命令行操作非常方便。注意它和docker compose exec的区别:run创建新容器,exec进入已运行容器。
临时扩展服务副本数,可以这样:
docker compose up -d --scale worker=3这个用在对 worker 类服务做本地扩容测试的场景。不过需要提醒,--scale会让服务名称附加上数字后缀,容器名会变成项目名-worker-1、项目名-worker-2这种,清理时如果忘了down,容易留下多余的容器。
down这个命令也有些讲究:
docker compose down docker compose down -v不带-v的down会删除服务容器和默认网络,但保留命名卷。带-v会连卷一起删除。-v一旦执行,数据库和持久化数据就没了。所以生产环境或重要数据环境不要直接用-v,除非你备份完备。我个人的习惯是在一个 Compose 项目里,默认只执行不带-v的down,卷单独按需清理。
6. 清理与维护:prune 很爽,但红线必须明确
6.1 先看磁盘占用再动手
清理之前先摸清家底:
docker system df它会显示镜像、容器、卷、构建缓存的占用总量,以及有多少“可回收”空间。想看更细的,加-v:
docker system df -v这个命令展示的是每个镜像、容器、卷的具体占用和复用情况,是判断“到底是什么在占空间”的起点。我见过不少人动不动就system prune -a,结果空间没释放多少,反倒把想留的镜像都清走了,原因就是没有先看 df 直接动手。
6.2 prune 的参数含义和保命技巧
docker system prune是“安全模式”的清理:
docker system prune它会清理已停止的容器、悬空的镜像、未被使用的网络、构建缓存。这个命令对运行中的容器和正在被使用的镜像没有影响,所以相对安全。
危险版本是:
docker system prune -a多了一个-a,会把所有没有被容器引用的镜像全部清理掉。包括你刚构建好、还没来得及部署的版本,也包括你打算保留下来做回滚的旧版本。执行之后再去docker images看,镜像列表会突然空掉一大半。生产环境下,这条命令等同于“删库重来”。
需要保留特定对象时,可以用 label 过滤。给需要保留的资源打上标签:
docker volume create app-data --label keep=true执行清理时排除带该标签的对象:
docker volume prune --filter "label!=keep"label!=keep表示只清理“没有 keep 标签或标签值不等于 keep”的卷。这样就给重要卷上了一道保险。
prune 还有一些实用过滤参数:
docker system prune -a --filter "until=24h" docker image prune --filter "until=24h"until=24h只清理创建时间超过 24 小时的对象,最近构建的镜像、最近的临时容器会被保留,这让清理命令在开发机上可用性高了很多。
6.3 几个省事的“顺手指令”
除了 prune,还有几条命令虽然不是天天用,但关键时刻能省大把时间。
宿主机信息查看:
docker system info它包含 CPU 核心数、内存、存储驱动、容器数量上限等信息。排查“为什么资源配额上限不对”时,第一眼就应该看这里。
事件监听:
docker events这条命令会持续输出 Docker 守护进程的所有事件,比如容器创建、销毁、异常退出。当你想确认“某个容器是不是因为 OOM 反复被杀”,docker events能直接给出时间线和事件类型。
镜像历史:
docker history demo/api:latest它展示镜像每一层的构建指令和大小。排查“为什么镜像这么大”时,逐层看能很快定位到是哪一条RUN或者哪一次文件复制撑大了镜像。
写到这里,其实已经把日常最常用的 Docker 指令库整理完了。如果让我提炼几条真正值得长期坚持的习惯,我会说:创建容器一定带--name,服务类容器一定加配额限制和日志大小上限,跨容器访问一律用自定义网络,清理磁盘先看system df再决定 prune 的力度。按这个节奏操作,大多数和 Docker 相关的“诡异问题”都能少碰一大半。