
我最早开始系统性整理 Docker 指令是因为团队里连续几次有人把容器目录挂载错了还有人分不清docker restart和docker stop配合docker start在行为上的区别。这些看起来都是小问题但在生产环境里随便一个误操作都可能把服务搞得起不来。后来我把日常高频命令按使用场景重新梳理了一遍发现真正绕不开的核心指令其实没有那么多但每一组都必须理解到位而不是死记参数。这份整合版不是照着官方文档抄一遍而是把我自己这些年实操验证过、踩过坑、确认能用的整理成果拿出来分享。内容覆盖镜像管理、容器生命周期、日志监控、网络与数据卷、Compose 编排以及高频排障组合每一条都会说明应用场景、常见参数和需要注意的地方。无论你是刚上手 Docker 的新手还是已经被业务逼着开始搞容器的开发我相信这份内容都能让你在处理问题时少走弯路。1. 镜像生命周期管理从拉取到清理的完整闭环1.1 拉取镜像时不能忽略的两个细节docker pull看起来就是把镜像拉到本地实际使用中却藏着不少细节。比如很多人直接写docker pull nginx这会默认拉取 nginx:latest 标签但 latest 这个标签并不一定指向最新版本它只代表维护者最新推送的那个镜像。在生产环境我更推荐显式指定版本号像docker pull nginx:1.25.3这样能保证每次拉取的结果可复现。如果是在本地开发环境为了提升拉取速度可以预先配置镜像加速地址。但这个操作需要修改 Docker 的 daemon 配置文件不同系统的路径略有差别常见的路径在/etc/docker/daemon.json。修改完后务必执行systemctl restart docker让配置生效。还有一个细节是拉取镜像时输出层信息里包含的Digest字段它表示镜像内容的唯一指纹当你怀疑镜像内容被人篡改时可以用docker image inspect --format{{index .RepoDigests 0}} nginx去核验这个值。1.2 查看镜像信息不只是 docker imagesdocker images是最常用的查看命令但它输出的信息其实有限默认只展示仓库名、标签、镜像 ID、创建时间和大小。当你需要了解镜像内部的配置信息时就要用到docker inspect。比如查看镜像暴露了哪些端口可以执行docker inspect nginx:1.25.3 --format{{json .Config.ExposedPorts}}查看镜像入口点和默认启动命令docker inspect nginx:1.25.3 --format{{.Config.Entrypoint}} {{.Config.Cmd}}镜像 ID 和容器 ID 都是 12 位短标识实际使用中也可以只输入前几位。但要注意镜像 ID 的唯一性只在本机生效换一台机器同一个镜像的 ID 不一定相同所以不要把镜像 ID 写死在部署脚本里这将导致在另一台机器上执行失败。如果你需要精确引用某个镜像最稳妥的方式是用镜像名加完整 tag或者直接用 Digest。1.3 构建镜像的常用参数和踩坑点docker build应该是平时使用频率最高的镜像构建命令几个关键参数值得认真掌握。-t指定镜像名称和标签最好在构建时把镜像的版本号一起打上否则构建出来的全是最新版本无法区分不同的迭代记录。-f指定 Dockerfile 路径默认使用当前目录下名为 Dockerfile 的文件如果你的构建文件叫 dockerfile.prod就必须用-f显式指定。--build-arg用于向 Dockerfile 传递构建参数比如可以把软件源地址、版本号通过这种方式传入。注意--build-arg传递的值可以通过docker history被看到所以不要在--build-arg里传密码、密钥一类的敏感信息。--no-cache会禁用构建缓存在依赖导致构建异常时往往能派上用场。比如某次我把一个基础镜像升级了但项目中依赖了旧版运行环境Dockerfile 的前半段又没有变化这时复用缓存会让后续步骤直接报错。执行docker build --no-cache后问题得到解决。不过这个命令会导致构建速度明显变慢尤其是依赖下载量大的项目要在确认缓存确实不可用的情况下再用。构建完成后检查镜像分层信息可以用docker history它能展示每一层的构建命令和大小这对排查镜像体积异常大、帮忙减肥非常有帮助。1.4 镜像清理的完整方案docker rmi删除镜像时如果有容器正在使用该镜像会提示删除失败。所以标准操作顺序是先删除依赖该镜像的容器再删除镜像。如果只是想让容器停止运行可以使用docker stop但这并不会解除容器对镜像的引用镜像依然没办法直接删除。批量清理不用的镜像时可以用docker image prune加上-a参数会删除所有未被任何容器引用的镜像docker image prune -a这个操作在本地开发环境很爽但生产环境发布前务必看清楚它会把那些留作回滚用的旧版本镜像一并清理掉。我一般会先执行docker images确认目前可用的镜像列表再决定哪些镜像需要保留哪些可以清理避免盲目清理导致回滚时找不到镜像。如果镜像占用了大量磁盘空间可以先通过docker system df查看空间分布确认究竟是镜像、容器、数据卷还是构建缓存占了大头。很多人只清理镜像却忘了构建缓存docker builder prune才是专门清理构建缓存空间的命令。这和使用rm -rf ~/.cache类似不会影响已有的镜像和容器非常安全。1.5 打标签与推送镜像docker tag用于给本地镜像重新打标签它的语法是docker tag 原镜像名:原标签 新镜像名:新标签通常在准备把镜像推送到私有仓库或用新版本号发布时使用。推送镜像到仓库前先要登录docker login 仓库地址登录信息保存在本地配置文件中默认有效期是较长时间但在脚本化构建环境里我更推荐通过环境变量或 CI 平台内置的凭证登录方式避免把控制台登录状态带到自动化流程外。推送使用docker push 仓库地址/镜像名:版本号推送前建议先确认本地镜像的架构docker build --platform参数可以指定构建目标架构。如果你的服务器是 ARM 架构却用 X86 的镜像直接推送到平台生产环境拉取后会出现 exec format error这种报错非常棘手因为从日志看根本不知道是架构不匹配。2. 容器核心操作跑起来只是开始2.1 理解 docker run 的本质docker run是所有容器操作里最核心的一条命令。它的本质是“创建并启动一个新的容器”这个容器和镜像之间是一种实例关系。理解这一点之后很多疑惑都会迎刃而解。比如你修改了容器内部的某个文件这个修改并不会影响镜像本身只会体现在当前容器层里一旦容器被删除所有修改都会随之消失。创建容器并保持后台运行最常用的写法是docker run -d --name app-service -p 8080:80 -e MYSQL_PASSWORDxxx -v /data/app:/usr/share/nginx/html nginx:1.25.3拆开看这里面有几个关键设置-d表示后台运行--name为容器指定一个可记忆的名字-p做端口映射-e设置环境变量-v挂载数据卷。它们之间没有严格的先后顺序但为了日常维护方便建议按照-d --name -p -e -v 镜像名 启动命令的顺序书写。--rm是一个容易被忽略但非常实用的参数。它告诉 Docker 在容器停止后立即删除容器本身。适用于临时容器、测试容器和一次性执行任务的场景。如果你不加--rm每次停止容器后文件系统仍然保留久而久之会累积堆积大量已停止的容器磁盘空间会被慢慢占完。-i和-t参数在需要与容器进行交互时使用-it结合在一起表示交互式终端。例如进入容器内调试docker run -it --rm node:20 /bin/bash这会在容器内启动一个 bash 会话退出后容器自动删除。这种临时环境调试方式适合快速验证镜像内命令行为不会污染当前环境。2.2 查看容器状态不能只靠 psdocker ps默认只展示正在运行中的容器加上-a才会展示包括已停止在内的所有容器。这一点经常让人困惑刚入门时以为容器停了就等于删除了实际上容器停止后依然占有磁盘空间。当容器数量多了之后输出列表会变得很长我习惯用docker ps -a --format table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}自定义格式能让我快速聚焦需要的信息。查看容器最近创建的时间、启动时长、端口映射以及状态信息在排查问题时非常有用。-q参数只输出容器 ID它在组合命令里极其好用。比如想一次性删除所有已停止的容器docker rm $(docker ps -aq --filter statusexited)这种组合理念同样适用于镜像、网络和数据卷的操作。2.3 容器生命周期管理命令对比docker start用于启动已创建的容器docker stop会给容器内主进程发送终止信号默认等待一定时间后强制执行docker restart则是先停止再启动等价于 stop 加 start 的组合。这三条命令在表面逻辑上差别不大但实际工作中docker stop和docker restart的默认行为差异很容易被忽略。docker stop默认情况下会等待容器中的主进程处理终止信号这段时间是 10 秒。如果你运行的是一个需要优雅停机的服务这个时间窗口不够时可用-t参数扩展例如docker stop -t 30 容器名。而docker restart同样会先执行停止流程再启动如果容器内的初始化逻辑比较耗时你会观察到 restart 比 start 更慢。docker pause和docker unpause是另一组容易被忽视的命令。docker pause会暂停容器中的所有进程并冻结当前状态适合在需要临时停止对外提供服务但又不关闭容器的时候使用。它与stop的最大区别是容器内的进程并未终止而是被挂起所以docker ps中仍能看到容器处于 Up 状态只是状态列会显示 paused。需要恢复时执行docker unpause。2.4 进入容器的正确姿势与几个常见误区docker exec是在运行中的容器内执行命令的最常用手段也是最实用的调试工具。进入容器终端最常用的命令docker exec -it 容器名 bash这里解释一下为什么不用docker attach。attach是直接连接到容器的主进程如果你在容器里运行的是一个启动 Web 服务的命令那么 attach 后你会看到服务日志但此时按下CtrlC会直接把容器主进程终止导致容器被停止运行。而docker exec -it 容器名 bash是启动一个独立的 shell 进程在这个 shell 里做的任何操作都不会影响主进程运行退出时按exit或CtrlD只是退出这个 shell。新手容易犯的另一个问题是进容器后直接安装调试工具。适合生产调试的操作是尽量不更改容器内文件系统。你可以用docker exec执行一组临时命令来完成排查例如docker exec 容器名 cat /etc/os-release docker exec 容器名 env而不是进入容器后安装 vim、curl 等工具这会让容器层增加额外内容一旦重新构建镜像这些修改又会全部丢失等于白干。如果当前基础镜像确实缺少某些工具可以直接在宿主机上验证网络连通性或者使用docker run创建一个包含所需工具的新容器并挂载共享网络借助docker network来实现跨容器访问。2.5 在容器与宿主机之间拷贝文件docker cp用于在宿主机和容器之间复制文件或目录这个命令不需要容器处于运行状态。典型场景是把宿主机上的配置文件覆盖到容器内部docker cp /data/config.yml 容器名:/etc/app/config.yml反向操作是把容器内的日志文件拉取到宿主机分析docker cp 容器名:/var/log/app.log /data/logs/很多人把docker cp和挂载卷混为一谈。docker cp是临时的单向或双向复制挂载卷则是宿主机目录与容器目录实时同步。如果文件需要被容器长期使用并修改应该优先考虑挂载卷而不是每次手动拷贝。2.6 删除容器的基本操作删除容器使用docker rm 容器名如果容器正在运行需要先停止再删除或者加-f强制删除。docker rm -f会直接发送终止信号并删除容器。关于-f的使用我个人建议在开发环境随便用但在生产环境慎用因为强制删除会跳过优雅停机逻辑可能导致数据未落盘或持久化状态异常。批量删除所有未运行的容器docker container prune加上-f则跳过确认提示。如果你在清理后想去追查某个容器的历史日志那已经无法恢复了所以在清理前先确认这些容器确实不再需要。3. 日志、资源监控与故障排查的硬核手段3.1 用 docker logs 定位问题的关键参数docker logs用于查看容器日志。默认展示标准输出流加-f可以持续跟踪日志输出效果等同于tail -f。加--tail控制显示最近的行数比如--tail 100只显示最后 100 行日志。-t参数为每条日志增加时间戳这在排查请求顺序问题时非常有用。容器内应用日志输出到 stdout 的标准做法对 Docker 日志体系十分关键。如果你的应用把日志写入文件而不输出到 stdout那么docker logs往往只能看到容器启动信息根本看不到业务日志。这种时候就要检查应用日志配置或者用docker exec直接查看日志文件。还有一个容易踩坑的点容器日志会不断增长并占用宿主机磁盘空间。长期运行且输出大量日志的容器其日志文件可能膨胀到好几 GB。合理的做法是在创建容器时通过--log-opt max-size和--log-opt max-file限制单文件大小和保留文件数量例如docker run -d --name app --log-opt max-size50m --log-opt max-file3 nginx这样单个日志文件最大 50MB最多保留 3 份自动滚动覆盖避免日志无限增长。3.2 实时资源监控命令组合docker stats用来查看所有运行中容器的 CPU、内存、网络和磁盘占用情况不指定容器名称时会默认输出所有正在运行的容器。如果你只想看某几个容器可以直接在命令后面跟上容器名docker stats 容器A 容器B默认刷新频率是每秒一次加--no-stream可以让命令执行一次后立即退出适合脚本采集。docker top用于查看容器内主进程及相关子进程的信息等于把ps -ef限制在容器内部。如果发现容器内某个进程 CPU 飙高可以通过docker top 容器名快速定位进程 PID再决定是否进入容器调整。3.3 深度检查docker inspect 与 jq 配合docker inspect可以查看容器和镜像的详细配置信息输出格式是一大段 JSON。手动翻 JSON 效率比较低我通常与jq配合使用。比如快速查看容器的挂载信息docker inspect 容器名 | jq .[0].Mounts查看端口绑定情况docker inspect 容器名 | jq .[0].NetworkSettings.Ports查看容器的运行状态和启动时间docker inspect 容器名 | jq .[0].Statedocker inspect 输出的信息特别全面包括容器的 ID、创建时间、状态、重启策略、环境变量、挂载信息、网络配置、健康检查状态等。当需要确认某个容器到底设置了什么环境变量时可以这样查询docker inspect --format{{range .Config.Env}}{{println .}}{{end}} 容器名它在排查环境变量遗漏问题上会比进入容器逐条查看方便得多。3.4 实时事件流与变更追踪docker events用来监听 Docker 守护进程产生的事件流。当你怀疑某个容器被意外删除或重启时执行docker events后复现操作能看到类似container stop、container destroy等事件记录。这个命令不会输出历史事件只显示从执行时刻开始的实时事件。生产环境排查事故原因时它可以帮你还原操作时间轴辅助定位问题到底出现在手动误操作、定时任务还是自动化脚本上。如果需要保留事件记录可以结合其他日志方案把事件输出到文件但大多数时候直接在异常发生现场实时观察就足够了。3.5 常见排障命令组合下面这一组命令组合我几乎每周都会用到。先看容器状态docker ps -a | grep 容器名容器是运行中还是退出状态退出状态码是多少这些信息会直接决定下一步排查方向。再查看容器日志docker logs --tail 200 容器名如果容器启动后立即崩溃使用docker logs看最后的报错信息往往能直接发现启动参数错误或依赖缺失。再深入检查容器配置docker inspect 容器名 | jq .[0].Config, .[0].HostConfig会列出完整的环境变量、挂载目录和资源限制排查配置项是否填写完整。如果怀疑是容器内程序问题可以再执行docker exec -it 容器名 sh逐步验证容器内的进程和文件。4. 网络与数据卷容器之间的沟通方式和持久化方案4.1 理解 Docker 网络的核心模式Docker 容器默认使用 bridge 模式也就是通过虚拟网桥让同一宿主机上的容器相互通信。此外还有 host、none 和 container 等模式。大部分场景下bridge 网络就能满足需求。docker network ls可以查看当前存在的所有网络默认会有 bridge、host、none 三个。创建自定义网络是常用的操作docker network create app-net创建时加-d bridge指定驱动类型也可以使用--subnet和--gateway自定义网段但这属于高级玩法。日常开发直接使用默认网段即可不过在生产环境规划容器 IP 地址时建议提前规划好网段避免后期容器数量增加导致网段冲突。4.2 容器互联的核心方式容器之间通信有几种方式。最简单的是使用--link但这种方式现在已经不太推荐了。更现代、更可靠的方案是让容器加入同一个自定义网络然后通过容器名直接访问。例如先创建一个自定义网络 app-net然后用它启动两个容器docker network create app-net docker run -d --name web --network app-net nginx docker run -d --name api --network app-net node:20在 web 容器内可以直接通过api这个容器名访问 api 容器Docker 内置的 DNS 会自动解析。这种方式最大的优势是容器重启后只要名字不变IP 地址无论如何变化都能正确访问目标服务。如果某个容器启动时没有指定网络也可以用docker network connect后续加入docker network connect app-net 容器名同样地docker network disconnect可以移除容器与网络的连接。4.3 暴露端口与映射端口的区别-p参数负责把容器端口映射到宿主机端口例如-p 8080:80表示访问宿主机 8080 端口时会被转发到容器的 80 端口。-P则会随机分配宿主机的端口映射到容器暴露的端口用于调试阶段非常方便但生产环境基本不用。关于宿主机端口的选择需要提前确认端口没有被占用。docker run --name web -p 8080:80 nginx执行后如果端口被占用会直接报错。所以启动前建议先执行ss -lntp | grep 8080检查端口占用情况。多次遇到端口被占用的场景后你会发现这个检查步骤真的能免掉很多麻烦。4.4 数据卷的核心操作docker volume ls查看当前所有数据卷docker volume create 卷名创建数据卷docker volume rm 卷名删除数据卷。在容器中使用数据卷的推荐方式docker run -d --name app --mount sourceapp-data,target/usr/share/nginx/html nginx使用--mount语法比-v更加清晰易懂它让卷名、目标路径一目了然。如果需要用宿主机目录直接挂载可以这样写docker run -d --name app -v /data/app:/usr/share/nginx/html nginx这两者本质没有区别。但要注意-v在目录不存在时可能会自动创建而--mount对路径的要求更严格使用不当会直接报错。如果你要挂载宿主机目录建议提前把目录建好避免出现挂载路径不对的情况。数据卷相对目录挂载更推荐用在数据库容器上因为数据卷由 Docker 管理备份、迁移和恢复都比较方便。目录挂载则更适合挂载配置文件、日志目录等需要对宿主机文件直接操作的场景。4.5 将修改后的容器保存为镜像的注意事项docker commit可以把一个容器的当前状态打包成新镜像。这个命令在快速复制排查环境或者固定某个临时补丁时很好用但它有比较明显的劣势打包出来的镜像会包含容器运行时无意产生的临时文件、日志和历史命令记录所以它不应该是构建生产镜像的首选方式。正常的工作流应该是用 Dockerfile 来构建镜像。commit 只能算是应急方案比如某个容器里手工修改了很多配置想临时保存现场可以用docker commit 容器名 新镜像名:版本号此时新镜像会有多个层而且这些层中包含大量无意义修改记录导致镜像体积变大且难以复现构建过程。导出与导入镜像同样是一组重要操作。docker save可以把镜像保存为 tar 文件适合离线迁移镜像docker save -o nginx.tar nginx:1.25.3docker load用于导入 tar 包docker load -i nginx.tardocker export和docker import对应的则是容器级操作感兴趣可以研究一下和 save、load 的区别。核心区别在于 save 保存的是镜像的完整分层记录而 export 保存的是容器当时的文件系统快照会丢失镜像历史和标签。5. Docker Compose多容器编排的日常操作5.1 为什么后端开发一定要掌握 ComposeDocker 指令单条操作比较细碎一旦涉及多个容器协同工作比如一个服务需要数据库、缓存和消息队列一条条执行docker run不仅繁琐还容易漏配置。docker-compose 的价值就是把多容器编排定义成声明式配置然后通过一组简洁的指令完成启动、停止、重建和查看等操作。docker-compose 的核心是一个 yaml 配置文件通常命名为 docker-compose.yml 或 compose.yaml。一个简单的服务编排示例services: web: image: nginx:1.25.3 ports: - 8080:80 volumes: - ./html:/usr/share/nginx/html redis: image: redis:7然后执行docker compose up -d就能把两个服务一并启动这就是 Compose 最基本的用法。5.2 高频 Compose 指令逐个拆解docker compose up -d的作用是按照配置文件创建并启动所有服务加-d表示后台运行。如果你改动了 yaml 文件并想应用变更直接重新执行docker compose up -d即可它只会增量更新有变化的服务不会影响其他服务运行。docker compose ps查看当前项目所有服务的状态显示每个服务对应容器是运行中还是已退出。docker compose logs -f --tail 200查看多个服务的聚合日志并且自动跟随输出这是排查多服务链路问题的重要帮手。docker compose exec 服务名 命令用于进入某个服务的容器内执行命令值得注意的是它直接跟随的是服务名而不是容器名这与docker exec存在区别。比如docker compose exec redis redis-cli ping会直接在 redis 服务对应的容器中执行 redis-cli 命令。docker compose stop与docker compose down很容易弄混淆。stop只是停止所有服务的容器但容器和网络仍然保留执行start可以恢复运行。down则会把服务相关的容器、网络一并删除默认情况下不会删除数据卷不过加-v会连同匿名数据卷一起删除这个参数在使用时需要格外谨慎。在数据库容器场景下如果盲目执行docker compose down -v数据库里的数据会出现严重问题所以这个命令一定要看清楚后再用。docker compose build用于重新构建项目中定义了构建上下文的服务镜像通常在修改 Dockerfile 或应用代码后执行。如果你在up之前改了 Dockerfile直接执行docker compose up -d --build会更方便一步完成重新构建并启动。5.3 Compose 文件里值得注意的细节版本号在现在的 Compose 规范里不用再显式写version字段早期版本才需要。如果你在网上看到旧教程里写version: 3也能用只是新规范已经建议不再声明。服务名就是 Docker 内置的 DNS 名称其他服务可以直接通过服务名访问它对应的容器 IP。例如在 web 服务里连接 redis连接地址写redis:6379不需要再关心 IP 是多少。这利用了 Compose 自动创建网络的优势让服务间通信变得非常简洁。环境变量可以在 yaml 中使用environment也可以使用env_file引用外部环境变量文件。如果配置里包含密码、密钥等敏感信息建议用.env文件管理并在该文件中做注释说明同时记得把该文件加入版本管理忽略规则避免密钥入库。5.4 Compose 生产环境的实用组合操作发布新版时最常规的组合是git pull docker compose build docker compose up -d --remove-orphans--remove-orphans参数会清理掉不再被 Compose 文件定义但仍在运行的旧容器避免遗留孤儿容器占用端口或资源。但在执行之前建议先确认这些孤儿容器确实不是其他服务依赖的否则会出现误删。如果发现某个服务出现异常需要单独重启docker compose restart 服务名单独查看某个服务日志docker compose logs -f 服务名需要单独扩展服务实例数量时可以使用docker compose up -d --scale web3注意要确保 web 服务没有绑定宿主端口否则会因端口冲突而无法完成扩展创建这时应配合负载均衡来做流量分发。6. 效率技巧与高频报错速查6.1 给常用指令配置别名Docker 默认命令比较长每天高频输入难免繁琐。我在 shell 配置里加了几条别名操作效率提升明显。alias dpsdocker ps --format table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}} alias dlogsdocker logs --tail 100 -f alias dexdocker exec -it alias dcupdocker compose up -d alias dcdowndocker compose down alias drestartdocker restart配置完执行source ~/.bashrc或对应的 shell 配置文件命令就能立即生效。有了这些别名后平时输入量少了一小半特别是在频繁查看状态和日志的时候体感非常明显。6.2 一条命令完成容器全量清理开发环境中容器、镜像和网络会快速堆积清理时要分批执行。可以选择组合命令一次搞定docker container prune -f docker image prune -f docker network prune -f docker builder prune -f这个组合会删除所有已停止的容器、未被引用的镜像、未被使用的网络以及构建缓存。有一点要说明docker image prune -f默认不带-a只会清理悬空镜像也就是没有标签的镜像所以不会把本地已打好标签的镜像删除。如果你需要连未被容器引用的镜像一并清理才需要加-a。执行这套清理前务必确认没有正在运行的容器依赖这些镜像或网络。命令行没有任何二次确认机制误删后数据是无法找回的。6.3 高频报错与快速定位容器端口被占用是最常见的问题。报错信息通常会直接提示端口已被占用。快速排查方法ss -lntp | grep 端口号找到占用进程后要么停止该进程要么换一个宿主端口。容器启动后立即退出的原因很多常见的有启动命令错误、环境变量缺失、依赖服务未就绪。排查思路是先用docker logs看最后输出再检查启动命令是否能独立运行。还可以先以docker run --rm -it 镜像名 启动命令的方式在前台运行观察完整的输出过程比直接后台启动更容易定位问题。镜像拉取失败常见原因是网络不通或镜像仓库地址配置错误。先确认本地是否有该镜像再检查指定的镜像名和 tag 是否存在。经常有人把仓库地址和命名空间搞错导致收到 not found 提示这时检查官方仓库或私有仓库的命名规则能快速解决问题。容器删除失败提示正在使用时表面上容器的状态是 stopped但仍然存在引用关系。最直接的方案是加-f删除但如果是数据卷还在被使用就还要先清理数据卷引用。6.4 编写 Docker 指令时的几个个人建议在整理完这么多指令后我想额外补充几个实践心得。第一给容器命名。不用--name的容器会获得一个随机 ID后续操作必须通过 ID 定位极其不方便而且容器多了之后几乎无法通过输入前几位 ID 来区分目标容器。所以每次都建议顺手加--name。第二模板化输出。docker ps和docker inspect的默认输出够用但不聚焦。多用--format自定义输出用 jq 解析 JSON这样在容器数量多的场景下定位效率会大大提高。第三谨慎对待-v的自动创建目录行为。如果你在-v /data/db:/var/lib/mysql挂载数据库目录宿主机-v指定的目录在不存在时会自动创建而且新目录权限往往是 root 所有。如果容器内进程以普通用户身份运行可能会出现无法写入该目录的情况导致数据库容器反复启动失败。这时候用--mount并提前建好目录、设置好属主能规避这个问题。第四分清持久层和临时层。在容器里做的一切修改在容器删除后都会消失这是 Docker 设计逻辑的核心特征。想要持久化必须提前规划好用数据卷还是目录挂载而不是等容器跑了几天后再去倒腾数据那样不仅容易丢数据还会增加很多不必要的操作成本。7. 最后一页一些值得长期养成的使用习惯整篇内容走到这里Docker 的常用指令基本已经覆盖到位。最后分享几个我在实际工作中反复落地、确实回报率很高的习惯。每次创建容器前尽量先写出完整的启动命令确认参数后执行。特别是-v和-p这两个参数一旦写错后期修改的成本远高于一开始多花一分钟检查。端口映射如果一开始弄错需要删除容器重新创建才能修正而删除容器本身就会导致容器内的临时数据丢失。日志和容器的保留期限要有明确预期。开发环境无所谓数据随便造容器随手删。但生产环境日志保留策略要提前规划好容器退出后是否需要保留现场、日志是否需要上传到集中日志平台这些最好提前设计好。你每次执行docker rm或docker volume rm之前先问自己一句这个容器或数据卷是否真的不再需要了这简单一步能避免很多不可逆的误操作。这套命令看起来多但真正高频使用的其实就集中在镜像构建、容器生命周期、日志查看、网络与数据卷管理这四块。你只要把这一份整合的指令真正用熟日常开发工作中的绝大多数容器场景都能应付自如。之后再遇到极端特殊的问题再来查官方文档就会有明确的问题定位能力而不是从头到尾大海捞针。