每次带新人或者给团队做分享我都会被问到同一个问题Docker命令这么多到底该怎么记哪些又是真正常用的说实话网上关于Docker常用命令的文章一抓一大把但很多要么只丢给你一张命令速查表要么堆了一堆生僻参数看完还是不知道该在什么场景下用。这篇文章我不打算做那种“命令字典”而是按实际使用场景把高频命令串起来讲从镜像管理、容器生命周期到网络、数据卷、Compose每一组命令我都会告诉你它是用来干什么的、为什么要这样写以及我在真实运维中踩过哪些坑。不管你是刚接触Docker的新手还是在Linux服务器上部署过几个容器的开发者看这一篇应该都能有收获。1. 镜像管理拉取、查看、删除的一整套打法镜像之于容器就好比ISO安装包之于虚拟机。日常操作中绝大部分时间都花在“找镜像”和“拉镜像”上。这部分命令虽然简单但组合起来用能解决不少低级问题。1.1 拉取镜像时最容易被忽略的两个细节拉镜像的命令是docker pull但你真不一定每次都把参数写对。我在服务器上执行过最多的完整写法是docker pull mysql:8.0 docker pull nginx:1.25-alpine这里有两个细节值得你注意。第一一定要写tag不要直接docker pull mysql。不写tag时默认拉取latest而latest是个会变动的标签。今天拉下来的是8.0过几个月再拉可能就变了。生产环境里我见过不止一次因为latest漂移导致重启服务后行为不一致的事故所以现在凡是写进脚本或compose文件的镜像全部固定到具体版本号。第二能选alpine就尽量选alpine变体。同样的Nginx普通版本镜像体积在190MB左右而nginx:1.25-alpine只有40多MB。不仅是下载快、占磁盘少更重要的是alpine系镜像的攻击面更小里面默认没有bash、没有多余工具链出了问题反而不容易被乱改。代价是一些依赖glibc的软件跑不了但这在绝大多数Web服务场景下不算问题。如果你要查某个镜像有哪些tag可以去仓库官网看或者直接用命令拉取时让服务端报错——当tag不存在时Docker会返回可用列表。虽然不优雅但应急时能用。1.2 给镜像打tag比想象中更有用的操作很多人以为docker tag就是给镜像起个外号实际上它的作用是把镜像归入某一个仓库路径和版本下。我在和内网镜像仓库打交道时最常用的是这样docker tag nginx:1.25-alpine registry.internal.example.com/nginx:1.25-alpine docker push registry.internal.example.com/nginx:1.25-alpine打tag的本质是给镜像ID加了一个引用。同一个镜像ID可以挂多个tag都不会额外占用磁盘空间。所以你在本地测试时想模拟“某个版本被重新发布”完全不用重新拉镜像打好tag直接推就行。还有个小技巧当你想把本地镜像导出给同事用时除了docker save存成tar包打tag推到公共仓库再让他pull也是一种协作方式。虽然多了一步认证但胜在方便增量传输。1.3 查看镜像别只会用docker images列出本地镜像用docker images确实没错但有个更直观的命令容易被忽略——docker image ls。两者输出几乎一样我习惯把docker image当作一个子命令体系来记docker image ls docker image inspect mysql:8.0 docker image history mysql:8.0inspect命令会输出一个超长的JSON里面有镜像的环境变量、工作目录、端口声明等所有原数据。调试容器起不来但不知道默认配置时inspect就是你能找到的最权威的文档之一而且它是直接从镜像本身读出来的绝对和实际运行一致。docker image history则能看到镜像的每一层是怎么构建出来的包括每一层的命令和大小。排查“为什么镜像这么大”时这个命令比docker images有用得多。我曾经排查过一个莫名其妙涨到2GB的Java镜像一查history才发现是构建过程中把整个.m2仓库拷进去了后面没清理干净白白多了1.5GB。1.4 删除镜像的进阶操作删除镜像的基本命令是docker rmi 镜像ID或名称但实际场景往往是容器还在占用镜像导致删除报错。这时候要先删容器或先停容器。批量清理时我推荐两条命令一个是删除所有悬空镜像docker image prune悬空镜像指的是没有tag、也没有被任何容器引用的镜像层残留。每次用docker build重新构建同名镜像后旧版本就会变成悬空镜像日积月累非常吃磁盘。加上-a参数会连未被容器使用的所有镜像一起删谨慎使用建议在测试环境跑一次看清楚再上生产。这里我要特别提醒一句千万不要在服务器上随手执行docker system prune -a --volumes。这条组合命令会把所有未运行的容器、未使用的网络、没有容器引用的镜像和所有未被容器使用的数据卷全部干掉。数据卷一旦删除想找回比登天还难。我见过有人辛辛苦苦搭的数据库容器一条清理命令下去数据直接蒸发。真要清理空间咱们把命令拆开一点一点执行。2. 容器生命周期管理核心中的核心这一章节是Docker命令里最值钱的部分。容器生命周期管理命令包括创建、启动、停止、删除、暂停等一旦理解清楚容器的状态流转后面的网络、数据卷都好学得多。2.1 docker run的关键参数别急着背全docker run是参数最多、最灵活的一条命令但多数人只需要记住几个高频组合。一个典型的Web服务启动命令长这样docker run -d \ --name my-web \ -p 8080:80 \ -v /opt/nginx/html:/usr/share/nginx/html:ro \ --restart unless-stopped \ nginx:1.25-alpine参数拆开来看-d后台运行。不加它前台日志会一直刷屏按CtrlC容器就停了。--name给容器起名字。之后所有操作都可以用名字来引用不用记那一长串容器ID。-p 8080:80端口映射。宿主机8080端口转发到容器内80端口。-v /opt/nginx/html:/usr/share/nginx/html:ro将宿主机目录挂载到容器内ro表示容器内只读。这是修改Nginx页面而不重新进入容器最常用的方式。--restart unless-stopped重启策略。服务器重启后Docker会自动拉起容器但如果你手动docker stop了它它就不会被再次启动。生产环境绝大多数容器都该配这个策略。-e环境变量参数我再单独提一下。很多镜像首次启动时需要注入配置比如MySQL的root密码docker run -d --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDMyPass123456 \ -e TZAsia/Shanghai \ mysql:8.0-e是明文写在命令行里的因此不要在里面传生产环境的敏感密钥。你在服务器上执行history命令时这些密码会暴露在shell历史里。真到了生产环境优先使用--env-file参数从文件加载docker run -d --env-file .env mysql:8.02.2 查看容器状态ps命令的三种打开方式列出正在运行的容器用docker ps列出所有容器包括已停止的用docker ps -a。这个命令太常用了但还有两个值得记的参数docker ps -a docker ps -a --filter statusexited docker ps --format table {{.Names}}\t{{.Status}}\t{{.Ports}}--filter可以按状态过滤容器比如只看异常退出的容器在批量清理时非常有用。--format可以用Go模板自定义输出字段服务器上容器一多默认输出能把屏幕挤爆精简成三列后看着清爽多了。我给新人培训时常说一句话先ps看清现状再决定下一步操作永远不要在不清不楚的情况下执行批量清理命令。2.3 启动、停止、重启和“暂停”的区别启动和停止容器的命令其实是一组对称操作docker start my-container docker stop my-container docker restart my-containerstop会先给容器内主进程发SIGTERM信号等待一段宽限期默认10秒后再发SIGKILL强杀。这个宽限期可以通过-t参数调整比如docker stop -t 30 my-container如果你的应用在停止前需要做数据落盘、清理临时文件之类的操作把宽限期调大一点是必要的。我调优过一个内部服务默认10秒停止时间总是不够日志里频繁出现“killed before graceful shutdown completed”后来调整到60秒就正常了。docker pause和docker unpause用的是Linux的cgroup freezer机制把容器内的所有进程挂起但不终止进程。这个命令在诊断故障时非常有用——比如容器内出现CPU飙高问题你想保留现场又不让它继续产生日志时先pause再调查比直接stop更从容。2.4 删除容器时那些纠结的选择删除已停止的容器用docker rm 容器名删除正在运行的容器需要加-f强制删但我不建议你一上来就rm -f。有一种情况必须依靠强制删除容器内部进程卡死stop等了很久也停不掉。这时候可以docker rm -f my-containerrm -f的原理是先对容器主进程发SIGKILL再删除容器的可写层。注意可写层里如果存了数据删除容器后这些数据就没了。所以再次提醒需要持久化的数据一定要用数据卷或挂载目录而不是顺手写在容器里。批量删除已退出容器是我几乎每天都会执行的操作docker rm $(docker ps -aq --filter statusexited)先拿到所有已退出容器的ID列表再传给docker rm。不放心的话可以先执行docker ps -aq --filter statusexited | head看几条再删。命令行操作最忌“凭感觉写一条没人验证过的清理命令”。3. 进入容器、看日志和拷贝文件容器跑起来了但你不可能永远只靠docker ps看个健康状态。日常维护中更常做的是进入容器内部执行命令、看报错日志、把文件拷出来分析。3.1 进入容器的exec和attach到底有什么区别进入正在运行的容器执行命令推荐使用docker execdocker exec -it my-container bash-i表示保持标准输入打开-t表示分配一个伪终端两个参数配合起来才能得到一个可以交互的shell。如果容器内没有bash就用shdocker exec -it my-container shalpine镜像默认只有shUbuntu系镜像才有bash。很多人在alpine容器里执行docker exec -it xxx bash然后报错并不是命令错了而是容器里没装bash换sh就好。docker attach则是把当前终端连接到容器主进程的标准输入输出上。它的行为更像“接入主进程”如果你在容器里跑的是Nginxattach进去不会得到shell只会看到Nginx的访问日志。按CtrlC可能直接给容器主进程发送中断信号。所以我几乎不用attach做日常操作只有在排查某些初始化脚本交互行为时才会用它。如果你只是想执行一条命令而不想进入交互shell可以直接docker exec my-container cat /etc/nginx/nginx.conf这条命令会把文件内容直接输出到当前终端不会真的“进入”容器。批量巡检时非常方便比如同时查看多个容器的运行时间docker ps --format {{.Names}} | xargs -I {} docker inspect --format {{.Name}} Uptime{{.State.StartedAt}} {}3.2 看日志的高频套路查看容器日志用docker logs这是排查问题时我第一个敲的命令docker logs my-container docker logs --tail 200 -f my-container--tail 200只显示最近200行避免日志量太大刷屏-f是持续跟踪输出类似tail -f适合启动容器后观察是否正常。一个容易踩坑的地方是有些进程把日志输出到文件而不是标准输出这时候docker logs什么都看不到。Docker日志收集机制只捕获容器内PID 1进程的stdout和stderr。要解决这个问题要么在启动命令里把日志同时symlink到/dev/stdout要么用docker exec去容器里看实际日志文件。日志量大的服务默认的json-file日志驱动会无限占用磁盘。强烈建议给Docker加一个日志轮转配置在/etc/docker/daemon.json里写好{ log-driver: json-file, log-opts: { max-size: 50m, max-file: 5 } }这个配置表示单个日志文件最大50MB最多保留5个文件。改完配置要重启Docker守护进程才会生效而且只对之后创建的容器生效。已经跑着的容器趁版本发布重启时顺便重建一下即可。3.3 与宿主机之间拷贝文件容器里有个配置文件想改一下又不想进容器装vim最简单的方式是拷出来改完再拷回去docker cp my-container:/etc/nginx/nginx.conf ./nginx.conf.bak docker cp ./nginx.conf my-container:/etc/nginx/nginx.confdocker cp还能在容器和容器之间做中转先从一个容器拷出来再拷进另一个容器虽然少见但比绕道宿主机要省事得多。拷贝完文件后记得重启容器让配置生效很多nginx配置不是热加载的别折腾半天发现改动没被读进去。3.4 资源占用查看top、stats和port查看容器内部进程列表用docker top my-container它本质上读取的是宿主机上对应进程的信息输出格式和Linux的top类似。实时查看所有容器的CPU、内存、网络IO用docker statsdocker stats就像Docker版本的htop不加参数时每秒刷新一次。排查“哪个容器把服务器内存吃光了”时这是最直接的手段。也可以指定容器名只盯一个docker stats --no-stream my-container加--no-stream是只输出当前一次快照而不持续刷新适合在脚本里抓数据。查看端口映射关系用docker port my-container它会列出容器内端口映射到了宿主机的哪个端口。当你在服务器上配置防火墙时需要确认的就是这个映射结果比如容器跑起来了但外部无法访问先用docker port确认宿主机端口是不是真的被监听了。4. 网络与数据卷容器间协作的两大基础设施单容器跑服务不难难的是多个容器互联、数据持久化。这部分命令不多但背后涉及Docker的网络模型和数据卷设计理解它们才能真正做到“部署不慌”。4.1 玩转docker network从默认bridge到自定义网络Docker安装后默认有三个网络bridge默认桥接网络、host主机网络、none无网络。默认情况下所有容器都会连到bridge网络上容器之间通过IP可以互访但不推荐直接依赖IP因为容器重建后IP会变。最优雅的做法是创建一个自定义网络然后让容器用容器名互相访问docker network create my-net docker run -d --name web1 --network my-net nginx:1.25-alpine docker run -d --name web2 --network my-net nginx:1.25-alpine docker exec web1 ping web2在自定义网络里Docker内置DNS会把容器名解析成对应IP。这就是我建议所有多容器项目都创建自定义网络的原因。默认bridge网络虽然能容器互联但不支持这种自动DNS解析用起来特别憋屈。查看网络列表和网络详情docker network ls docker network inspect my-netinspect会列出网络里有哪几个容器、IP分配情况、子网掩码等。排查两个容器能不能通信时先确认它们是不是在同一个网络下。把运行中的容器连到另一个网络用docker network connect my-net web1 docker network disconnect old-net web1这在多环境迁移时很实用。容器启动后才发现没连对网络不需要重启重建直接connect就能补上。4.2 数据卷命名卷和bind mount的正确选择Docker数据持久化有两个主流方案命名卷named volume和bind mount宿主机目录挂载。命名卷的常见命令是docker volume create mydata docker volume ls docker volume inspect mydata docker run -d --name db -v mydata:/var/lib/mysql mysql:8.0命名卷由Docker管理位置在/var/lib/docker/volumes/下你不用关心它在宿主机上的具体路径迁移时用docker run --volumes-from或者备份卷目录即可。缺点是文件分散在系统目录内想直接在宿主机上查看不太方便。bind mount则直接指定宿主机路径docker run -d --name web -v /opt/html:/usr/share/nginx/html:ro nginx:1.25-alpine优点是你可以在宿主机上用vim直接改文件改完容器里立刻可见这个方式特别适合开发调试或者部署那些配置在宿主机上改起来更顺手的应用。一个常见的取舍是数据库等需要严格备份的应用用命名卷Web页面、配置文件等需要经常在宿主机改的用bind mount。清理数据卷用docker volume prune它会删除所有没有被容器使用的数据卷。执行之前务必看清楚列表。还有一个经常被忽略的命令docker run --volumes-from可以复制另一个容器的数据卷挂载。在做数据迁移或者临时开一个备份容器时很实用docker run --rm --volumes-from db -v $(pwd):/backup alpine tar cvf /backup/db-backup.tar /var/lib/mysql这条命令利用一个临时alpine容器把db容器里的MySQL数据目录打包成tar放到宿主机当前目录。不需要停库虽然数据一致性问题在写频繁的库里存在但做个粗略备份足够了。4.3 容器间互联的host网络和端口映射经验默认bridge模式下容器访问宿主机服务不少人会误写成容器IP或localhost。实际上容器内的localhost是容器自己要访问宿主机上的服务时常见做法是使用host.docker.internalDocker Desktop环境或者在Linux服务器上用--network host直接共享宿主机的网络栈。docker run -d --name app --network host my-imagehost模式下容器不会创建自己的网络命名空间直接使用宿主机IP因此也不需要-p做端口映射。性能好一些但容器之间没法用隔离的端口空间容易出现端口冲突。我的经验是单机部署、追求低延迟的场景可以用host模式其他情况优先用bridge -p映射这样更灵活也更安全。5. 构建镜像与Docker Compose批量部署的利器拉取现成镜像只是Docker用法的第一步。日常开发中你还需要构建自定义镜像并且用Compose把多个服务一次性编排起来。5.1 docker build和.dockerignore的使用要点构建镜像的核心命令是docker build -t my-app:1.0.0 .-t指定镜像名称和tag最后的.是构建上下文路径。Docker会把这个目录下的所有文件发送给守护进程作为构建上下文。为了不让本地垃圾文件比如node_modules、.git、target一起打过去要养成写.dockerignore的习惯类似.gitignorenode_modules .git *.log Dockerfile .dockerignoreDockerfile文件本身默认也会被当作构建上下文的一部分但写进.dockerignore后就没法在构建中使用它了一般不会有人需要所以不写进去就行。构建时如果希望复用缓存加速构建命令会自动做缓存只要Dockerfile每层指令没有变化后续构建会快很多。但缓存有时会让人踩坑——比如你用apt-get install装包源更新了但Docker仍用缓存层。碰到这种情况可以在Dockerfile中该指令之前用ARG CACHEBUST1并在构建时传不同值强制绕开缓存。或者干脆加一行docker build --no-cache -t my-app:1.0.0 .5.2 docker commit临时镜像的救命稻草docker commit能把一个正在运行的容器保存为新镜像docker commit my-container my-image:snapshot这种方式不推荐用于生产因为它把容器的可写层整个打包镜像是黑盒、不可复现。但在应急场景下它是救命稻草——比如某个容器里手工装了一堆工具、改了配置还没写成Dockerfile容器又急着迁移或备份commit一下能快速度过难关。提交之后记得用上-m写清备注不然过了两周你自己也看不出这个镜像是什么状态下提交的。5.3 docker compose优雅编排多容器手动跑docker run解决单容器很方便但一套系统需要MySQL、Redis、后端服务、前端页面四个容器时每一条都要手动敲参数改一个端口还得重新复制粘贴很容易出错。Docker Compose就是为了解决这个问题。一个最简的docker-compose.yml长这样version: 3.9 services: mysql: image: mysql:8.0 container_name: my-mysql restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: MyPass123456 TZ: Asia/Shanghai ports: - 3306:3306 volumes: - mysql-data:/var/lib/mysql redis: image: redis:7-alpine container_name: my-redis restart: unless-stopped ports: - 6379:6379 app: build: ./app container_name: my-app restart: unless-stopped depends_on: - mysql - redis ports: - 8080:8080 volumes: mysql-data:在项目目录下执行docker compose up -dup会根据YAML文件创建并启动所有服务-d表示后台运行。常用的组合还有docker compose ps docker compose logs -f app docker compose exec app bash docker compose down docker compose down -vdown会停止并删除所有由up创建的资源。down -v代表连定义在volumes块里的数据卷也一起删除。如果你只是想停服务保留数据用down不加-v或者干脆docker compose stop。docker compose up -d之后如果要重建某个服务比如改动了Dockerfile或YAML配置docker compose up -d --build app这条命令只会重建app服务不影响其它已经在跑的服务。Compose是为单机多容器设计的远程集群场景交给Kubernetes或Docker Swarm处理。6. 系统级命令与空间回收做一个负责任的运维除了针对单个镜像或者容器的命令Docker还提供了一组系统级命令用来查看守护进程状态、清理磁盘空间、跟踪事件。很多“服务器空间不足”的告警最终都是靠这些命令定位的。6.1 查看Docker引擎信息和版本刚接手一台陌生服务器时先敲三条命令确认环境:docker version docker info docker system dfdocker version显示客户端和守护进程的版本号。注意返回内容包含Client和Server两部分如果Server部分连不上说明Docker守护进程没起来先查systemctl status docker。docker info内容更丰富包含存储驱动、CPU核数、内存大小、镜像数量、容器数量等。排查资源问题时我习惯先看这里确认Docker能使用的系统资源上限。docker system df是磁盘空间排查利器它会把Docker各类资源占用的磁盘列成一张表包括镜像、容器、本地卷、构建缓存各自占了多少以及可回收空间是多少。6.2 清理系统空间的正确姿势我把空间清理分成三级第一级只清悬空数据docker image prune docker builder prune这两条分别清理悬空镜像和不再被使用的BuildKit构建缓存是相对安全的操作不会影响正在运行的容器。第二级清未被容器使用的资源docker container prune docker network prunedocker container prune只删已停止的容器不会动运行中的。network prune删掉未被任何容器引用的自定义网络。这两步执行完往往能腾出不少空间。第三级全面清理但保留数据卷docker system prune -a这条命令会删除所有未被运行中容器使用的镜像包括那些没有tag的中间镜像和下载后用完的临时镜像但默认不会删除数据卷。虽然清理力度大但执行前最好先跑一次docker system df看清要被清掉的东西有多大。如果在最前面加上--volumes就是我一直警告大家慎用的“核弹级清理”docker system prune -a --volumes数据卷是容器持久化数据的根本一条命令全没了。我宁可让你分三步执行也别为了省事一键梭哈。6.3 查看实时事件日志docker events是一条比较低调但实用的命令它会实时输出Docker守护进程接收到的操作事件docker events --filter typecontainer --filter eventdie比如你可以用这条命令监控有没有容器意外退出。在自动化运维脚本里结合docker events和另一个进程做告警能第一时间发现异常。平时排障时直接docker events挂在那里再手动启动一个容器你就能在事件流里看到pull、create、start、die等完整流程。7. 高频故障排查那些绕不开的坑最后分享一组我在实际运维中反复遇到的故障场景每个问题都对应明确的现象和排查思路。这部分内容算是我个人经验的沉淀不是网上常见的报错列表而是真实踩坑后的记录。7.1 容器启动后立刻退出现象docker ps看不到容器但docker ps -a能看到一堆状态为Exited (0)或Exited (1)的记录。排查方法先看退出码。0表示进程主动正常退出比如你启动一个没灌前台命令的busybox容器它跑完默认cmd就退出了非0退出码则说明进程出错。看日志docker logs 容器名常见原因前台进程没有保持运行。比如启动Nginx时必须让nginx以daemon off方式跑否则Nginx进程fork到后台后容器的PID 1进程就认为任务结束直接退出。运行一个Web服务其实本质是要让一个进程持续占着前台。很多镜像默认CMD已经做好了但你要覆盖默认CMD时就会遇到这坑。解决方案是启动命令里加-g daemon off;或使用tail -f /dev/null保持前台临时测试用不推荐生产。7.2 端口被占用现象docker run -p 8080:80报错提示bind: address already in use。排查方法lsof -i :8080 ss -ltnp | grep 8080看到是哪个进程占了端口后要么停掉旧进程要么把宿主机端口换一个。这里有一个经验之谈不要为了省事直接用-p 80:80去碰1024以下端口非root进程无法绑定Docker虽然能通过自己的iptables规则处理但如果你机器上还有别的Web服务很容易冲突。测试环境统一用8000以上的高位端口生产再按需调整。7.3 Docker Desktop报virtualization support not detectedWindows上使用Docker Desktop时偶尔会碰到启动失败提示“Docker Desktop failed to start because virtualisation support wasnt detected”之类的错误。排查思路Docker Desktop在Windows上依赖虚拟化技术报错通常意味着系统的虚拟化功能没有正常开启。先打开任务管理器在“性能”页签里看“虚拟化”这一行是否显示“已启用”。如果显示禁用需要进BIOS/UEFI把Intel VT-x或AMD-V打开。笔记本用户还要检查是不是开了某些虚拟机监控程序独占虚拟化资源。开启后重启电脑再启动Docker Desktop一般能恢复正常。另外Windows自带的Hyper-V和Windows虚拟机监控程序平台也要保证处于启用状态。如果你不想用Hyper-V架构新版Docker Desktop的WSL2后端也可以但同样依赖虚拟化支持。7.4 镜像拉取极慢或超时这个问题在国内环境尤其常见。直接拉Docker Hub官方镜像时经常慢到让人抓狂很多人第一反应是配置一个镜像加速器。加速器的地址一般在云服务商的控制台就能找到把你自己的专属地址配置到Docker配置里即可。Linux服务器上改/etc/docker/daemon.json{ registry-mirrors: [https://your-mirror-server.example.com] }配置完成后执行sudo systemctl daemon-reload sudo systemctl restart docker注意改镜像加速只影响后续拉取操作已经存在的镜像不会重新下载。Docker Desktop用户可以在Settings - Docker Engine里直接编辑JSON配置。还有一点容易忽略确保服务器时间和镜像仓库服务器时间一致。如果时间偏差太大HTTPS证书校验会失败拉取时报证书相关错误看起来像网络问题其实是时间问题。date -R看一眼偏差大就及时同步。7.5 容器内命令找不到进入容器执行ps、vim、netstat等命令时报command not found这不是你的Docker坏了而是容器镜像本身精简掉了这些工具。处理方式先用镜像自带的工具代替。比如查看监听端口用netstat没有可以试ss查看进程用ps没有可以到/proc目录手工查看或者用docker top从宿主机侧看。真需要调试工具临时装一套但注意容器重启后工具会丢失因为容器可写层不会持久化。生产环境建议在Dockerfile里把调试工具提前打好或者准备一个专用的debug镜像。7.6 容器内文件修改后不生效修改了容器内文件但访问没有变化先别急着怀疑缓存按照这个顺序排查第一确认改动保存位置是否和实际生效路径一致。很多镜像会有一层软链接比如某些发行版镜像的/etc/localtime是指向/usr/share/zoneinfo/...的软链直接覆盖会得到“Text file busy”或明明写了却没变化的结果。第二确认改动有没有被子进程重新拉取。Nginx这类进程会缓存配置改完文件后需要reloaddocker exec my-nginx nginx -s reload第三确认是不是有多个实例。你改了A容器请求却负载到了B容器这在docker compose和swarm架构下经常发生。搜一下到底有哪些容器在跑这台服务。7.7 如何面对那些“找不到命令帮助”的时刻当你记不清某个命令的参数时最靠谱的办法不是上搜索引擎而是先看本机帮助docker run --help docker ps --help docker network --helpDocker命令体系挺清晰的每个子命令都能用--help查看详细选项。操作系统上的命令也同理man docker-run或者直接看官方文档。很多参数光靠死记硬背容易漏用到什么查什么慢慢就形成肌肉记忆了。我在实际使用中还有一个习惯把常用命令的“冷门却实用”参数写在shell的alias或者notes里比如给docker ps加一个docker ps --format的别名界面清爽很多。工具存在的意义是减轻人的负担不是增加背诵压力。写在最后整理这篇Docker常用命令时我回顾的不只是每个命令的用法还有那些让新手怀疑人生的排障经历。Docker本身并不复杂难的是在你已经有一堆业务系统在跑时还能冷静地判断容器状态、排除网络问题、管理数据持久化。我的建议依然是在测试环境多造几个“事故场景”比如故意把端口占用、故意退出容器、故意删掉数据卷然后自己一步步查日志、看状态、恢复。摔过几次之后这些命令才会真正内化成你的本能反应。最后希望这篇梳理能帮你节省一点满地翻文档的时间。