很多人学 Docker,第一件事就是docker run hello-world,跑出那句 “Hello from Docker!” 就觉得自己入门了。实际上,后面还有docker ps和docker ps -a的区别没搞清、exec和attach混着用、网络不通时完全不知道从哪下手。我过去一年多里给团队搭过环境、部署过微服务、也排过不少容器网络问题,这篇把日常最常碰到的 Docker 命令知识点按真实使用场景重新过了一遍。
内容围绕镜像和容器的日常管理、网络与端口排查、数据持久化、Compose 批量部署,以及最后一块避坑心得展开。适合刚装好 Docker Desktop、对着命令行头疼的新手,也适合已经能把容器跑起来、但遇到网络不通和挂载丢失时一脸懵的人。我不会把每个参数都抄一遍,只讲那些真正影响你能不能把环境跑起来的点。
1. 镜像与容器:最常用的基础命令记忆法
1.1 镜像管理:拉取、查看、删除与构建
Docker 里镜像这个概念可以理解成“安装包”,容器就是“运行中的程序”。docker pull负责下载镜像,但你得先知道要下载哪个。去 Docker Hub 搜时别只看名字,还要看 Tag,也就是版本号。
docker pull mysql:8.0 docker pull nginx:latest这里有个关键习惯:生产环境尽量不要用latest。latest不是真正的版本,它只是个引用,作者哪天把新版本推上去,你下次docker pull拉下来的东西就可能和线上环境不一样。同一个镜像标签,昨天跑没问题,今天重新部署就挂了,这种情况我见得太多了。所以定版本号要带明确 Tag,比如mysql:8.0.36,或者至少精确到8.0。其实严格来说8.0也算可变标签,但比latest可控得多。
docker images是另一个高频命令,列出本地所有镜像:
docker images docker images --filter "dangling=true" docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"dangling=true能找出那些“悬空镜像”,也就是没有仓库名、没有标签的镜像,一般是重新构建之后留下的中间产物,清理时可以优先处理它们。--format可以自定义输出列,脚本化运维时很有用。
删除镜像用docker rmi,但有个顺序问题:如果某个容器还在用这个镜像,你直接删会报错。得先删容器,再删镜像。强制删镜像用-f,不过我不太推荐你养成-f的习惯。
docker rmi 镜像ID docker rmi 镜像名:标签docker tag很多人觉得没用,其实非常实用。比如你本地构建了一个myapp:1.0.0,想把它改名推到私有仓库:
docker tag myapp:1.0.0 registry.example.com/myapp:1.0.0 docker push registry.example.com/myapp:1.0.0最后构建镜像时用docker build。新手最容易踩的坑是最后一个“上下文路径”。比如你执行:
docker build -t myapp:1.0 .那个.不是随便写写,它代表把当前目录作为“构建上下文”打包发送给 Docker 守护进程。如果当前目录里有个node_modules或者.git目录,几十万个文件会被一股脑打包,构建速度慢到怀疑人生。所以项目里通常要配.dockerignore文件,把不需要的文件排除掉,类似.gitignore的思路。
1.2 容器生命周期:run、start、stop、rm 的差别
容器是对镜像的一次实例化运行,你可以同时从同一个镜像启动好几个容器。docker run是最核心的命令,但我建议你别只背参数,先理解这个命令的完整结构:
docker run [各种参数] 镜像名 [容器内启动命令]常用参数拆开说:
-d:后台运行。不加这个,容器会占住当前终端,输出全打在屏幕上。-p 宿主机端口:容器端口:端口映射。比如-p 8080:80表示把容器的 80 端口对应到宿主机的 8080 端口。-v 宿主机目录:容器目录:目录挂载,把宿主机路径映射进容器。--name:给容器起名,否则 Docker 会随机生成一个“发疯版”名字。--restart=always:容器挂了或宿主机重启后自动拉起,生产部署常用。-it:交互模式。一般配合/bin/bash进入容器内部操作。--rm:容器停止后自动删除,适合临时测试。
这几个参数组合起来,就是一个完整的 Web 服务启动方式:
docker run -d \ --name nginx-test \ -p 8080:80 \ --restart=always \ -v /opt/html:/usr/share/nginx/html \ nginx:1.25启动之后,通过docker ps查看运行中的容器:
docker ps docker ps -a docker ps -ldocker ps -a是查看所有容器,包括已经退出的。-l只看最近创建的。这点非常重要,因为很多容器启动几秒就崩了,你只敲docker ps根本看不出来,得用-a才能看到那个 Exited 状态。
停止和删除是两件事:
docker stop 容器名 docker start 容器名 docker restart 容器名 docker rm 容器名stop是优雅关闭容器,给容器内主进程发送停止信号,让它自己收尾。kill是直接强杀,不推荐常规使用。还有个常见需求是批量清理已停止的容器:
docker rm $(docker ps -aq) docker container prune这条命令很实用,尤其是开发机上一堆 Exited 状态的残骸。它不会删还在运行的容器,所以相对安全,但如果容器里存了数据且没挂载数据卷,删除后数据就一起没了,后面我会专门讲数据持久化。
1.3 进入容器与日志查看:exec、attach、logs 的正确用法
进入正在运行的容器,命令行有两种方式,新手最容易搞混。
第一种是exec:
docker exec -it 容器名 /bin/bash意思是在这个容器里新开一个进程执行命令。因为加了-it,你获得了一个交互式终端,可以在里面跑ls、cd、装工具等等。退出用exit,但不会影响容器本身,容器照常运行。
第二种是attach:
docker attach 容器名attach是把自己连接到容器的主进程上,相当于直接接入这个容器的标准输入输出。如果是 Nginx、MySQL 这类前台进程,你attach进去之后执行exit,会把主进程也结束掉,容器就停了。所以我的建议很直接:日常排查一律用exec,别用attach。
如果容器里没有 bash,比如一些镜像很精简,只装了 sh,可以退而求其次:
docker exec -it 容器名 /bin/sh还有一种情况是容器里连 shell 都没有,比如编译后的静态二进制镜像,那你就只能靠日志和 cp 命令了。查看日志用docker logs,这个命令的实用程度非常高:
docker logs 容器名 docker logs -f 容器名 docker logs --tail 200 容器名 docker logs --since 30m 容器名-f是持续跟踪日志输出,效果类似tail -f。容器起不来的时候,第一件事就是跑docker logs --tail 100 容器名,看它的报错信息。注意,如果镜像里配置的日志输出到了文件而不是标准输出,docker logs可能什么都看不到,这时候只能exec进去看/var/log目录下的文件。
2. 网络与端口映射:容器网络不通的排障思路
2.1 端口映射是怎么回事:-p 参数背后的逻辑
先得搞清一个问题:容器默认是有自己独立 IP 的,和宿主机不是同一个网络栈。你在容器里启动了一个 Redis,监听 6379,宿主机并不能直接用localhost:6379访问它,因为 6379 在容器的网络命名空间里,不是在宿主机上。
-p 6379:6379干的事情就是一条端口转发规则:宿主机上所有发往 6379 端口的数据包,被 Docker 的 iptables 转发到容器的 6379 端口。所以宿主机上跑docker run -p 8080:80 nginx之后,你用浏览器访问localhost:8080,流量就进到了容器内的 80 端口。
如果你不指定宿主机端口,只写容器端口,Docker 会自动分配一个随机端口:
docker run -d -P nginx大写-P会对镜像里所有暴露的端口做随机映射。运行docker port 容器名可以查具体映射情况:
docker port nginx-test这条命令输出类似:
80/tcp -> 0.0.0.0:8080排障时看到这个输出,就能确认宿主机端口到底映射对了没有。比如你明明-p 8080:80,但docker port显示只映射到了127.0.0.1:8080,说明是只绑定在本地回环,外网机器访问不到。
2.2 docker network 命令:自定义网络解决容器互通
Docker 默认有三种网络模式:bridge、host、none。
bridge是默认模式,容器都接到一个叫docker0的网桥上,每个容器分配一个内网 IP。宿主机上执行ip addr show docker0能看到这个网桥的地址,通常是172.17.0.1。容器之间在同一个 bridge 网络里可以互通,但没法直接用容器名互相访问,只能靠 IP。这就带来一个很恼火的问题:容器重启以后 IP 可能变化,改个 IP 就得跟着改配置。
解决方法是创建自定义 bridge 网络:
docker network create mynet docker run -d --network mynet --name app1 myapp docker run -d --network mynet --name app2 myapp在自定义网络里,Docker 自带了 DNS 解析。app2 里可以直接ping app1,或者让程序通过app1:8080访问。这个能力在生产环境极其实用,因为你的后端服务不可能在配置文件里写死 IP,都是写服务名的。
host模式则是让容器直接共享宿主机的网络栈,没有独立 IP。好处是网络性能好,坏处是端口管理混乱,容器直接占用宿主机端口。本地测试时偶尔用,生产环境一般不用。
常用网络命令:
docker network ls docker network inspect mynet docker network connect mynet 容器名 docker network disconnect mynet 容器名inspect可以看这个网络下挂了哪些容器、网关是什么、子网范围是多少。当你发现两个容器互相访问不通,第一反应应该是检查它们是不是同一个网络。其他网络里的容器要加进来,就用docker network connect,不需要重建容器。
2.3 网络不通的六个排查步骤
容器网络问题可以说是 Docker 使用中最大的坑。我总结了一套排查顺序,照着做能省很多时间。
第一步,看容器状态:
docker ps -a状态必须是Up,如果是Exited,先去看日志。
第二步,看端口映射:
docker port 容器名确认宿主机端口和容器端口是否对应上了。
第三步,进到容器内部测试:
docker exec -it 容器名 /bin/bash curl http://localhost:8080 ping 对方容器名如果容器内 curl 自己都连不通,说明服务本身没起来。如果 ping 不通另一个容器,说明网络隔离了。
第四步,在宿主机测试端口连通性。Windows 上可以用 telnet 命令:
telnet 宿主机IP 宿主机端口比如telnet 192.168.1.100 8080,能连上会进入一个黑窗口,连不上就直接提示失败。telnet的退出方式对新手不太友好,连上后按Ctrl + ],再输入quit回车。
第五步,看容器日志:
docker logs --tail 200 容器名很多时候不是网络不通,是服务启动时绑定地址错了。好多服务默认只监听127.0.0.1,这在容器里意味着只有容器自己本机回环能访问,宿主机转发进来的请求全都会被拒。解决办法是让服务监听0.0.0.0,这样容器内所有接口都能接收到。
第六步,检查宿主机防火墙。这是最容易被忽略的。Docker 的端口映射是通了,但宿主机防火墙把端口挡了,外面照样访问不了。先确认防火墙状态,再把对应端口加白名单。
我整理一个常见的对照表:
| 现象 | 常见原因 | 排查方向 |
|---|---|---|
| 容器正常但外部访问不了 | 服务监听 127.0.0.1 | 改绑 0.0.0.0 |
| 两个容器互相不通 | 不在同一自定义网络 | 用docker network connect |
docker port没输出 | 容器没做端口映射 | 检查-p参数 |
| 宿主机能访问,外网不行 | 防火墙规则 | 放行对应端口 |
| 容器重启后 IP 变了 | 用的默认 bridge | 改用自定义网络加容器名 |
3. 数据持久化:Volume、Bind Mount 和文件拷贝
3.1 容器删了数据就没了?——Volume 的基本原理
容器本质上是一个可读写的临时层。镜像提供只读的程序文件,容器运行后产生的修改都写在容器自己的可写层。一旦你把容器删了,这个可写层也跟着销毁,里面所有数据都没了。
我第一次帮别人搞 MySQL 容器时就踩过这个坑:容器运行得好好的,数据库文件也在写,结果一次误操作把容器删掉,整个库直接清零。后来才明白,容器里的数据必须放到容器之外,也就是“数据卷”或者“挂载目录”里。
Docker 提供三种持久化方案:
| 方案 | 数据存放位置 | 适合场景 |
|---|---|---|
| 命名卷(named volume) | Docker 管理的主机目录 | 数据库数据,官方推荐 |
| 绑定挂载(bind mount) | 宿主机指定目录 | 配置文件、开发代码 |
| tmpfs 挂载 | 内存 | 临时数据,重启即失 |
命名卷的好处是 Docker 自己负责路径管理,你只需要给卷起个名字。绑定挂载则是你明确指定宿主机路径,比如/opt/mysql-data:/var/lib/mysql。
3.2 -v 与 --mount:两种挂载写法怎么选
老版本 Docker 里最常用的是-v,写法简洁:
docker run -d -v mysql_data:/var/lib/mysql mysql:8.0 docker run -d -v /opt/html:/usr/share/nginx/html nginx:1.25这里有个非常容易搞混的点:冒号左边到底是卷名还是路径。如果第一个字符是/,那 Docker 就认为是宿主机绝对路径,做绑定挂载;否则当成命名卷。命名卷不在宿主机项目目录下,而是 Docker 数据目录里,所以你把mysql_data当卷名后,想在宿主机直接找数据文件反而不好找。可以用docker volume inspect mysql_data查看它的真实路径。
--mount是更正式的写法,参数更清晰:
docker run -d \ --mount type=volume,source=mysql_data,target=/var/lib/mysql \ mysql:8.0 docker run -d \ --mount type=bind,source=/opt/html,target=/usr/share/nginx/html \ nginx:1.25--mount还支持只读挂载,比如把配置文件只读挂进容器,防止容器内程序改乱:
docker run -d \ --mount type=bind,source=/opt/app/config.yml,target=/app/config.yml,readonly \ myapp我的建议是:数据库这类需要可靠持久化的,用命名卷;需要直接编辑宿主机文件的,用绑定挂载。-v在交互式命令行里写起来方便,--mount在脚本和 Compose 文件里可读性更好。
3.3 实操:挂载 MySQL 8.0 的数据目录
MySQL 8.0 的官方镜像会把数据写在/var/lib/mysql。如果不用数据卷,容器删除后整个库就没了。所以正确的启动方式是:
docker volume create mysql_data docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=你的密码 \ -v mysql_data:/var/lib/mysql \ mysql:8.0启动之后,用docker volume inspect mysql_data能看到卷的挂载点:
docker volume inspect mysql_data输出里有"Mountpoint": "/var/lib/docker/volumes/mysql_data/_data",宿主机上的真实数据就在这个目录里。如果你是用 Docker Desktop,这个路径其实在虚拟机的 Linux 环境里,Windows 的 PowerShell 直接访问不到,所以还是老老实实用docker exec进容器操作,或者用docker cp导出文件。
还有个常见的需求是迁移数据。把旧容器里的数据目录打包复制到新环境:
docker run --rm \ -v mysql_data:/source \ -v /opt/backup:/backup \ alpine tar czf /backup/mysql_data.tar.gz -C /source .这条命令临时起了一个 Alpine 容器,把mysql_data卷挂到/source,把宿主机/opt/backup挂到/backup,然后执行 tar 打包。--rm保证跑完就删,不会留下垃圾容器。
恢复类似,把打包文件解压回卷里就行。
3.4 docker cp:临时文件拷贝的正确姿势
有时候你需要在容器和宿主机之间拷贝单个文件,比如把容器里的日志捞出来,或者把本地配置文件送进去。用docker cp是最直接的:
docker cp 容器名:/app/logs/app.log ./app.log docker cp ./config.yml 容器名:/app/config.ymldocker cp不需要容器在运行,只要容器存在就能操作。它适合小文件和临时操作,不适合做正式的数据同步。备份数据库这种任务,正规做法是进容器用 MySQL 自带的导出工具:
docker exec -it mysql8 mysqldump -uroot -p --all-databases > backup.sql然后把导出的backup.sql再拷贝回宿主机并妥善保存。另外提醒一句,拷贝宿主机的目录进容器时,注意目录属主和权限问题,很多容器内的进程是用普通用户跑的,宿主机的文件权限如果太宽松,容器内读起来可能报 permission denied。
4. Docker Compose:多容器部署的一键编排
4.1 从 docker run 到 docker-compose.yml
当你只有一两个容器时,手敲docker run还能接受。但一旦涉及 MySQL、Redis、Nginx、后端服务、前端页面,五个八个容器一起跑,再靠命令行逐一启动就乱套了。Compose 的作用就是把这些运行参数写进一个 YAML 文件里,用一条命令完成启动和停止。
Compose 文件的核心是services段,每一个服务对应一个镜像和一组容器运行参数。写出来的内容比 docker run 直观很多:
services: db: image: mysql:8.0 container_name: mysql8 restart: always environment: MYSQL_ROOT_PASSWORD: root123 ports: - "3306:3306" volumes: - db_data:/var/lib/mysql这个services.db就相当于执行了:
docker run -d --name mysql8 --restart=always -e MYSQL_ROOT_PASSWORD=root123 -p 3306:3306 -v db_data:/var/lib/mysql mysql:8.0注意,新版 Docker Compose 不再强制要求version字段,直接以services开头就行。写的时候用两个空格缩进,不要用 Tab,YAML 对缩进非常敏感。
4.2 常用 compose 命令与参数
启动和停止:
docker compose up -d docker compose downup -d的作用是创建并启动所有服务,-d表示后台运行。如果你改了配置文件,重新执行docker compose up -d会检测到变化并重建相关容器,所以日常更新配置后就跑这一条。
down则是停止并删除所有容器和网络。注意docker compose down默认不会删除命名卷,所以数据库数据还在。想要连带卷一起删除,得加-v:
docker compose down -v这条命令会把数据卷一并清掉,执行前一定要确认你真的不想要那些数据了。我自己就吃过一次亏,本来只想清理容器,手一抖把-v也带上了,整个开发库直接归零。
查看和管理服务:
docker compose ps docker compose logs -f docker compose exec db bash docker compose top docker compose configdocker compose config会把你写的 compose 文件解析成最终有效的配置,同时校验 YAML 语法。写完文件后先跑一遍这个命令能避免很多低级错误。config -q则只检查语法,不输出内容,适合放在脚本里做校验。
4.3 一个可以直接抄的 MySQL + Redis 主从部署示例
热词里经常有人搜“docker 安装 redis 主从”,我直接给一个能落地的 Compose 配置。Redis 主从的原理很简单:从节点连上主节点,然后同步数据。
services: redis-master: image: redis:7 container_name: redis-master restart: always ports: - "6379:6379" command: redis-server --appendonly yes redis-slave: image: redis:7 container_name: redis-slave restart: always depends_on: - redis-master ports: - "6380:6379" command: redis-server --replicaof redis-master 6379这里有一个重要的网络细节:从节点用--replicaof redis-master 6379,里面写的是服务名redis-master,而不是 IP。Compose 会自动创建自定义网络,服务之间默认可以通过服务名互相访问。如果你用--replicaof 127.0.0.1 6379,从节点连的就是自己,主从配置直接失败。
启动后可以验证主从状态:
docker exec -it redis-master redis-cli info replication docker exec -it redis-slave redis-cli info replication能看到role:master和role:slave,并且 slave 那侧的master_link_status:up就说明主从正常。
depends_on只是控制启动顺序,不保证主节点已经可用。如果主节点启动慢,从节点一开始连着失败,可能会重试。更稳妥的做法是在从节点的启动命令里加--replicaof ... --replica-announce-ip ...,或者用 healthcheck 做健康检查。简单场景先靠 Redis 自己的重试机制即可,生产环境再上 healthcheck。
再把 MySQL 也加进来,就是一个完整的多容器编排:
services: db: image: mysql:8.0 container_name: mysql8 restart: always environment: MYSQL_ROOT_PASSWORD: root123 TZ: Asia/Shanghai ports: - "3306:3306" volumes: - db_data:/var/lib/mysql redis-master: image: redis:7 container_name: redis-master restart: always ports: - "6379:6379" command: redis-server --appendonly yes redis-slave: image: redis:7 container_name: redis-slave restart: always depends_on: - redis-master ports: - "6380:6379" command: redis-server --replicaof redis-master 6379 volumes: db_data:4.4 微服务部署中的经验与坑
用 Docker 部署微服务时,最典型的问题有三个。
第一个是端口冲突。Compose 文件里一不小心写了两个服务映射同一个宿主机端口,比如两个服务都写"8080:8080",第二个服务启动会失败,报port is already allocated。排障时先docker compose ps看看哪个起不来,再用netstat -ano | findstr 8080查一下宿主机端口被谁占了。
第二个是环境变量混乱。微服务之间互相依赖,配置集中在环境变量里。env_file可以一次性把一批变量注进去,但要注意变量名冲突。同一个 Compose 文件里,environment和env_file同时设置时,environment优先级更高。这个细节有时会把配置覆盖掉,导致服务连错数据库。
第三个是启动顺序。服务 B 依赖服务 A,但 A 的启动时间很长,B 起来时 A 还没就绪,导致连接失败。depends_on只能保证 A 先开始启动,不能保证 A 已经就绪。解决方式是在 B 的启动参数里加一个等待脚本,或者给 A 配置healthcheck:
services: db: image: mysql:8.0 healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 10s timeout: 5s retries: 5然后其他服务可以通过condition: service_healthy来等待:
app: image: myapp depends_on: db: condition: service_healthy这个写法要求 Compose 用 v2 以上版本,但一般现在的 Docker Desktop 都支持。
5. 日常维护与避坑记录
5.1 资源监控:docker stats 与 docker top
容器部署上线之后,不是就万事大吉了。内存泄露、CPU 飙高、磁盘写爆,这些事迟早会遇到。docker stats是最直接的监控入口:
docker stats docker stats --no-stream不加--no-stream会持续刷新,类似top。加了只输出一次当前状态。输出里有 CONTAINER ID、CPU 百分比、内存使用、NET I/O、PIDS 等。如果某个容器内存占用一直涨,说明程序可能有内存泄漏,先把容器重启顶上,再进日志查具体原因。
docker top 容器名可以查看容器内正在运行的进程,效果相当于在宿主机上执行ps -ef并过滤出该容器的进程。比如排障时想确认容器里的 Java 进程有没有活着,可以:
docker top myapp5.2 清理磁盘:docker system df 与 prune
docker system df用于查看各类资源占用:
docker system df TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 12 4 3.2GB 1.8GB (56%) Containers 8 3 120MB 80MB (66%) Local Volumes 5 3 2.1GB 800MB (38%) Build Cache 0 0 0B 0B看到有大片可回收空间时,可以用各种prune命令清理:
docker container prune docker image prune docker volume prune docker system prune -adocker system prune -a会把所有未使用的镜像、容器、网络一次清掉,看起来很爽,但风险也不小:如果某个镜像你暂时不用,它会被直接清掉,下次启动要重新下载。加--volumes更危险,会连没被使用的命名卷一起删掉。我在生产服务器上默认只执行docker image prune -f,把悬空镜像清掉就够了。
日志占用是另一个隐形杀手。Docker 默认把所有容器日志写在一个 json 文件里,不做限制的话会一直涨,直到把磁盘塞满。最好的办法是启动容器时限制日志大小:
docker run -d \ --log-opt max-size=10m \ --log-opt max-file=3 \ myapp在 Compose 文件里对应写下:
logging: driver: json-file options: max-size: "10m" max-file: "3"5.3 几个容易忽略的细节
第一个是时区问题。很多官方镜像默认时区是 UTC,容器里的日志时间比北京时间慢 8 小时。排查问题时看到日志时间和你实际出问题的时间对不上,会非常困惑。解决办法有两种:
environment: TZ: Asia/Shanghai或者把宿主机的时区文件挂进去:
volumes: - /etc/localtime:/etc/localtime:ro第二个是挂载目录的权限问题。使用 bind mount 时,容器内的用户和宿主机用户的 uid 可能不一致。典型的例子:宿主机的/opt/mysql-data属主是 root,容器里 MySQL 进程用的是 mysql 用户,启动时没有权限写数据目录,直接报错。解决办法是把目录权限调好,或者在docker run时通过--user $(id -u):$(id -g)指定用户。这个坑在 Linux 上特别容易遇到,Windows 和 macOS 上不明显是因为文件共享层做了转换。
第三个是 Docker Desktop 在 Windows 上启动失败的问题。常见提示是Docker Desktop failed to start because virtualisation support wasn't detected。这基本上是因为电脑的虚拟化功能没有开启,需要去 BIOS 里打开 VT-x 或 AMD-V,并且在 Windows 功能里启用 Hyper-V 和“虚拟机平台”。这是安装环节最容易卡住的地方,我身边至少有三个人栽在这里。再配合一句:装完 Docker Desktop 之后,确认 WSL2 已开启,用wsl --status查,不然 Docker 也起不来。这个不算 Docker 命令,但属于高频问题,值得记一下。
第四个,docker inspect是万能的调试工具。想查容器的 IP、挂载卷、环境变量、网络模式、启动参数,一条命令全能看到:
docker inspect 容器名 docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 容器名 docker inspect --format '{{json .Config.Env}}' 容器名我不会背所有参数,遇到问题就用docker inspect把容器完整配置导出来,配合末尾--format只提取需要的字段,排查效率能高出一大截。
最后说一点我的使用习惯:能写 compose 就不敲 run。就算是单个容器,我也顺手写个 compose 文件挂在那里,因为下一次你再来维护,打开文件就知道当初是怎么启动的。相比在一堆历史命令里翻找,YAML 文件才是真正可靠的记忆。命令本身不是重点,重点是你知道每个环节的数据落到哪里、网络从哪里进、日志从哪里看、服务靠什么互相找。把这几条想明白,再复杂的容器环境也不会把你难倒。