
Docker命令知识点1把镜像、容器和网络这条逻辑链打通我一直跟团队里的新人说Docker命令背下来没用你得把它的逻辑链打通。镜像怎么来的、容器怎么跑的、网络怎么通的、数据怎么存的这几件事在脑子里串成一条线之后你会发现那些看起来眼花缭乱的docker命令其实就那么几类每一类都有自己清晰的套路。这篇文章就是围绕这个目标来写的适合刚装好Docker Desktop、正准备跑第一个容器的初学者也适合用了几个月但全靠复制粘贴、遇到问题就懵的开发者。我把日常最高频的docker命令按场景拆开讲清楚每条命令背后的原理和踩过的坑保证你读完能自己排查问题而不是继续到处搜答案。1. 先把核心概念和命令逻辑理顺1.1 镜像和容器的关系以及命令参数的基本规律理解Docker命令之前必须先搞清楚镜像和容器到底是什么关系。我的类比一直是镜像就是安装包或者模板容器就是安装包运行起来之后的那个进程实例。你用同一个镜像可以启动十个容器它们彼此隔离互不影响就像你用同一个Word模板创建了十份不同的文档一样。这个关系一旦建立起来很多命令的命名逻辑就自然记住了——凡是操作镜像的命令动词后面跟的是镜像名凡是操作容器的命令动词后面跟的是容器ID或名字。Docker命令的通用格式是docker [全局参数] 对象类型动词 [对象名] [参数]。比如docker run nginx里面run是动词nginx是镜像名实际操作的是镜像和容器的交界处——它先检查本地有没有nginx镜像没有就去仓库拉取然后基于这个镜像创建并启动一个容器。理解了这套结构你看到docker pull、docker push、docker rm、docker rmi的时候就不会搞混rm和rmi了——rm是remove容器rmi是remove镜像多一个字母i指代image。还有一个容易忽略的点docker命令的帮助系统。docker --help告诉你有哪些子命令docker run --help告诉你这个子命令支持哪些参数docker help run跟它等价。我见过太多人卡在某个参数上直接搜百度其实先跑一下帮助命令往往几秒钟就解决了。Docker的命令行帮助写得非常完整每个参数都有说明和默认值这应该成为你的第一求助对象而不是搜索引擎。1.2 命令体系的分类记忆法Docker命令虽然多但按操作对象分就三类镜像操作、容器操作、系统与网络操作。再把动词按动作分增删改查、启停、交互。这样交叉下来其实每类命令不会超过十几个。我建议初学者不要一上来就背docker run的一大堆参数而是先掌握一个最小闭环docker pull拉镜像docker run跑容器docker ps看容器docker exec进容器docker stop停容器docker rm删容器。这七个命令撑起了日常80%的工作。等你对这几个命令已经很熟悉了再往run命令里逐步添加端口映射、数据卷、环境变量这些参数会轻松很多因为这些参数本质上是在回答容器跑起来之后它跟外面怎么通信、数据存哪里、用什么样的配置这些问题。2. 镜像管理命令从拉取到清理的完整操作手册2.1 镜像仓库地址三段式和拉取细节docker pull是从镜像仓库拉取镜像的命令。这里有一个非常关键但很多人没搞懂的概念镜像的完整名称其实是[仓库地址]/[命名空间]/[镜像名]:[标签]三段式。我们平时敲的docker pull nginx其实是简写默认的仓库地址是Docker Hub官方仓库默认的标签是latest默认的命名空间是官方库的library。这个三段式意味着什么意味着你可以从任意一个registry仓库拉取镜像只要地址正确。很多企业内部的镜像仓库拉取命令是docker pull registry.internal.example.com:5000/teamname/appname:v1.2.3这种长名字在docker images列表里也会完整显示。新手最容易犯的错是把镜像名里的冒号当成端口号其实冒号后面是版本标签。如果漏写了冒号和标签默认拉取latest而生产环境强烈不建议依赖latest因为它指向的版本可能是会漂移的。拉取镜像的时候还经常遇到网络问题。Docker Hub在国内的访问速度时好时坏常规的做法是给Docker配置镜像加速器。Docker Desktop的设置里找到Docker Engine修改registry-mirrors配置即可。但要注意某些公共加速器后来关停了配置完记得用docker pull拉一个实际镜像验证效果不要配了就以为万事大吉。验证方法很简单docker info的输出里会显示Registry Mirrors列表确认你配置的地址在里面然后实测拉取速度。2.2 镜像的查看、标记、删除与导入导出docker images列出本地已有的镜像列表带-a参数可以看到所有层级的镜像带--digests可以看摘要信息。这个命令的重点不是列出来而是读懂输出REPOSITORY列是镜像名TAG列是版本IMAGE ID列是镜像ID的前12位SIZE列是镜像解压后的大小。镜像ID是SHA256的短哈希同一个镜像即使被打了不同标签镜像ID是一样的这说明它们底层共享同一份数据。docker tag是给镜像打标签的命令。它的本质不是复制镜像而是给同一个镜像ID添加一个别名引用。理解了这点你就明白为什么docker tag nginx nginx:backup之后用docker images会看到两行记录但IMAGE ID相同磁盘占用没有翻倍。tag命令的全格式是docker tag 源镜像名:源标签 目标镜像名:目标标签常用于把本地镜像打上私有仓库的完整地址为docker push做准备。删除镜像用docker rmi注意这个命令只能删除没有被容器使用的镜像。如果你启动过某个镜像的容器但没删容器docker rmi会报错image is being used by stopped container这时候你得先docker rm删掉那个容器或者用docker rmi -f强制删除——但我不推荐强制删因为容易留下悬空镜像。镜像导入导出用docker save和docker load这组命令用于离线环境迁移镜像docker save -o nginx.tar nginx:latest把镜像保存成tar文件docker load -i nginx.tar再导入。save/load和export/import是两套容易混淆的命令前者操作镜像、保留历史层和元数据后者操作容器文件系统、丢弃历史、体积更小打包的是容器快照而不是镜像这俩用错场景会出问题——比如export出来的包无法用docker tag重新打标签也无法push到仓库。清理本地不用的镜像和时间悬空的数据卷我一般用docker image prune -a加docker volume prune配合。但这两个命令都要谨慎-a会把没有被容器使用的镜像全部删掉包括那些你事先想保留的。所以执行prune之前先docker images确认一遍要保留的镜像是否在跑。我在生产服务器上踩过一次坑本来想清理临时构建的中间层镜像结果docker system prune -af把所有没在运行的容器和没被使用的镜像全清了连回滚用的旧版本镜像都没了从那以后我清理命令都会看清楚参数再执行。2.3 镜像背后的分层存储原理镜像的一个核心特性是分层存储。每一条构建指令对应一个只读层docker pull的时候如果本地已经有某些层只会下载缺失的层这就是为什么同一个基础镜像拉多个应用镜像时速度较快。docker history 镜像名可以查看镜像的历史构建记录能看到每一层执行了什么指令、大小多少。排查镜像体积过大问题时这个命令特别有用——你能直观地看到是哪一层塞进了不该有的文件。另一个相关的因素是容器内删除文件不会缩减镜像大小因为新增的层记录了删除操作但下面那一层的数据还在这叫写时复制机制下的层不可变理解了这一点就不会对镜像越用越大感到奇怪了。3. 容器生命周期run、ps、exec这些命令的真实用法3.1 docker run的核心参数拆解docker run是整个Docker命令行里最复杂、最常见的命令因为它后面可以挂几十个参数。但我不建议死记硬背只需要明白run的参数是在回答这个容器应该怎么跑起来这个问题。我把常用参数按职责分成了五组。第一组是运行模式-d后台运行-it交互式前台运行OpenStdin TTY。为什么老是看到docker run -it这个组合因为你要在容器里操作终端就必须加-i保持标准输入打开和-t分配一个伪终端只用其中一个会导致操作异常。第二组是端口映射-p 宿主机端口:容器端口这里要注意映射的方向是外面到里面比如-p 8080:80表示宿主机的8080端口转发到容器的80端口。第三组是数据持久化-v 宿主机目录:容器目录或者用更规范的--mount typebind,source...,target...语法。第四组是资源限制-m限制内存--cpus限制CPU核数不设限制的话容器可以吃掉宿主机全部资源等于是个隐患。第五组是环境变量-e 键值很多镜像靠环境变量来配置比如MySQL的MYSQL_ROOT_PASSWORD。以一个最常见的MySQL容器为例完整的启动命令是docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDyourpassword \ -e TZAsia/Shanghai \ -v /data/mysql:/var/lib/mysql \ mysql:8.0这条命令的意思是用后台模式启动一个叫mysql8的容器宿主机3306端口映射到容器3306设置了root密码为yourpassword、时区为上海容器里的数据目录挂载到宿主机的/data/mysql使用mysql 8.0版本镜像。这里面最容易出问题的是挂载目录和权限宿主机的/data/mysql目录如果不存在Docker会帮你创建但创建出来的目录属主可能不是容器内MySQL进程的uid启动时可能报权限错误。这种情况下一个常见的解决思路是手动chown调整目录权限或者指定一个已准备好的属主一致的目录。关于docker run和docker start的区别也值得强调一下docker run是创建新容器并启动docker start是启动一个已经存在的容器。如果你以为docker run nginx能重新启动之前那个容器就错了它会再创建一个全新的容器这也是新手看到一堆同名容器堆积的原因之一。3.2 ps、logs、exec、attach和容器的状态流转docker ps查看当前正在运行的容器列表-a参数查看所有状态的容器包括已退出和已创建的-q只显示容器ID这个参数在批量操作时非常有用比如docker stop $(docker ps -q)一键停掉所有运行中的容器。--filter参数可以按条件过滤最常用的是--filter namemysql按名字筛选--filter statusexited查看已经停止的容器。容器状态流转是一条清晰的路径Created已创建未启动、Running运行中、Paused已暂停、Exited已退出、Dead死亡。docker stop是优雅停止先给容器内主进程发SIGTERM信号等待超时才发SIGKILLdocker kill是直接发SIGKILL强杀。在需要快速释放端口、但进程卡死不退的场景下kill比stop更好用。docker restart等价于先stop再start。docker logs查看容器日志最常用的参数是-f跟踪输出、--tail 100只看最后100行、-t带时间戳。查看MySQL容器启动失败的原因、查看应用崩没崩全靠它。注意docker logs显示的是容器内PID 1进程的标准输出应用必须把日志写到stdout而不是文件里否则logs什么都看不到。进入运行中的容器有两条常用命令docker exec -it 容器名 bash和docker attach 容器名。这两个的差别很关键exec是在容器里新建一个进程你在这个进程里做的操作不会影响容器主进程退出exec也不会让容器停掉attach是连接到容器的主进程你输入的内容会直接发给它退出attach往往会让容器跟着停掉。所以日常调试一律用exec别用attach。还有一个高频错误是exec的参数顺序docker exec -it 容器名 bash是先参数后容器名再命令很多人写成docker exec 容器名 -it bash会报错误。原因在于Docker命令行工具的解析方式——它把第一个非选项参数当作容器名后面的参数原样传给容器内要执行的命令。最后说下删除容器docker rm只能删已停止的容器运行中的容器会提示冲突需要docker rm -f强制删除等价于先kill再rm或者先docker stop再docker rm。批量清理已退出的容器用docker container prune这个命令会删除所有处于Exited状态的容器不会动运行中的相对安全。4. 网络与数据卷容器之间到底怎么通信4.1 三种网络模式和自定义网络的实际应用docker网络连接这块常见的问题我从docker network命令讲起。安装Docker后默认有三个网络bridge桥接、host主机、none无网络。默认创建的容器都挂在bridge网络下容器通过NAT方式访问外网宿主机通过端口映射访问容器。网络模式在docker run中通过--network参数指定。host模式是容器直接使用宿主机网络栈没有隔离端口也不需要映射性能最好但安全性差、容易端口冲突none模式是完全没有网络用于某些安全要求高的场景自定义bridge网络则是最推荐的生产环境方案因为它自带了DNS解析功能——你在自定义网络里可以通过容器名直接访问其他容器而不需要查IP。自定义网络的创建和使用docker network create my-net docker run -d --name nginx-demo --network my-net nginx docker run -it --rm --network my-net curlimages/curl curl http://nginx-demo第二个容器通过容器名nginx-demo访问到了第一个容器里的nginx服务。这在没自定义网络时是不可行的——默认bridge网络下容器间只能通过IP访问但容器重启后IP会变写死IP等于埋雷。所以凡是需要容器间通信的场景比如nginx反代后端应用、微服务调用都应该把相关容器放进同一个自定义网络。排查网络不通的高频步骤我一般按这个顺序走先docker network ls看容器挂在哪个网络再docker inspect 容器名的NetworkSettings部分看IP和网络详情然后进入容器执行ping或telnet测连通性比如docker exec 容器名 telnet 目标IP 端口看端口通不通最后检查是否跨了不同的自定义网络。跨自定义网络默认是不通的解决方式是把容器加入另一个网络docker network connect my-net 容器名这个命令可以给已经在运行的容器额外加网卡不需要重启。4.2 数据卷的本质不销毁、可共享、能备份容器是临时性的删除容器后里面的数据也一起没了所以必须用数据卷。docker命令行处理数据持久化的方式有三种bind mount绑定挂载、volume数据卷、tmpfs内存挂载。bind mount就是把宿主机的某个目录直接映射到容器内目录宿主机改文件容器立刻能看到适合开发调试场景但可移植性差换个机器路径就变了。volume是由docker管理的目录存放位置在/var/lib/docker/volumes/下创建方式docker volume create mydata挂载时-v mydata:/data不占宿主机具体路径、迁移方便、支持docker volume backup这类工具备份数据生产环境首选。tmpfs是直接写内存的容器停了数据就没速度极快适合存临时缓存。在docker run里挂载数据卷时我强烈建议用--mount语法而不是-vdocker run -d \ --name mysql8 \ --mount typevolume,sourcemysql-data,target/var/lib/mysql \ mysql:8.0为什么推荐--mount因为它的键值对清晰source、target、type一目了然特别是目录路径带空格或特殊字符时-v的斜杠拆解很容易出错。--mount语法还有一个隐藏好处如果你指定的volume不存在它会自动创建这一点对搭建环境来说省心不少。查看数据卷用docker volume ls清理无主数据卷用docker volume prune。特别注意删除容器时docker rm containerName不会删除关联的数据卷需要用docker rm -v或者在确认数据已备份后手动删volume这也意味着你在测试时反复创建容器数据卷会一直攒着时间久了占不少磁盘。我见过一台开发机被几十个孤立的mysql数据卷撑爆磁盘的案例。4.3 docker cp容器和宿主机之间的文件传输开发调试的时候经常需要在容器和宿主机之间拷贝文件这就要用docker cp。用法很简单宿主机文件拷进容器是docker cp ./app.jar 容器名:/app/app.jar容器文件拷出来是docker cp 容器名:/etc/nginx/nginx.conf ./nginx.conf.bak。注意docker cp的制作方向它不管容器是运行中还是已停止都能操作因为它是直接操作容器的文件系统层不需要容器进程参与。这个命令适合少量文件的临时拷贝不适合大数据量的持久同步后者应该用挂载解决。拷贝大文件时如果碰到Permission Denied多半是容器内目标路径的属主和权限问题可以加--follow-link参数处理符号链接场景或者进入容器查看目标目录的权限设置。5. 一学就会的容器编排进阶Dockerfile和Compose5.1 Dockerfile核心指令的完整拆解docker build从Dockerfile构建镜像这条命令把构建上下文中的所有文件打包发送给Docker守护进程然后逐条执行Dockerfile里的指令。这里有个构建上下文的概念docker build .中的点指的不是Dockerfile所在路径那么简单而是整个目录会被当作构建上下文目录越大打包上传越慢。所以大型项目一定要写.dockerignore文件把node_modules、target、.git这些大目录排除在外否则构建时间长到怀疑人生。Dockerfile的指令按执行顺序我觉得最常用的是这几个。FROM指定基础镜像必须是第一条非注释指令选基础镜像的关键是体积和安全性——尽量选alpine或slim版本一个ubuntu基础镜像200MB起步alpine才几十MB。WORKDIR切换工作目录这是一个容易被忽略但很重要的指令它相当于cd建议每条RUN、COPY、CMD之前都明确指定WORKDIR避免路径混乱。COPY把构建上下文中的文件复制进镜像ADD在COPY的基础上支持解压tar包和远程URL但官方建议优先用COPY因为ADD的行为隐式较多、可预期性差。RUN在构建阶段执行命令是安装依赖、编译代码的地方。EXPOSE声明容器运行时监听的端口注意它只是元数据声明真正让端口可访问还是要靠运行时的-p参数。CMD和ENTRYPOINT定义容器启动时执行的命令它们的关系可以这样理解ENTRYPOINT是主程序入口CMD是默认参数。如果Dockerfile里写了CMD [nginx, -g, daemon off;]docker run 镜像名 -t会用-t覆盖掉CMD的默认参数而ENTRYPOINT就没那么容易覆盖。多阶段构建是控制镜像体积的实战利器。比如Java项目构建第一个阶段用maven镜像编译出jar包第二个阶段用jre镜像只拷贝jar包运行这样最终的镜像不包含任何编译工具链体积能小一半以上。实现方式是Dockerfile里写多个FROM每个FROM开启一个新构建阶段最后一个阶段默认是最终镜像。5.2 docker compose用文件声明代替交互输入docker compose是把多个容器的配置写进一个docker-compose.yml文件、一条命令完成创建和启动的工具。它解决的问题是一个项目往往涉及多个服务mysql、redis、nginx、应用如果全用docker run命令去拼命令又长又容易出错而且多个服务之间的依赖、网络、数据卷关系无从管理。compose文件的核心结构是 services、networks、volumes 三段。services下面定义每个服务字段基本对应docker run的参数——image对应镜像、ports对应端口映射、environment对应环境变量、volumes对应挂载、depends_on对应依赖顺序。写一个最简单的应用加数据库配置version: 3.8 services: app: build: . ports: - 8080:8080 environment: SPRING_PROFILES_ACTIVE: prod DB_HOST: mysql depends_on: - mysql networks: - app-net mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: rootpass MYSQL_DATABASE: appdb volumes: - mysql-data:/var/lib/mysql networks: - app-net networks: app-net: volumes: mysql-data:这个文件里最关键的一点是DB_HOST直接写成了mysql——因为compose会自动为服务创建共享网络服务名即主机名应用容器里不需要写IP就能访问到mysql服务。这跟我前面说的自定义网络DNS解析是同一套原理只不过compose替你把网络建好了。常用的compose命令不多docker compose up -d后台启动所有服务docker compose down停止并删除所有服务容器docker compose logs -f跟踪日志docker compose ps查看服务状态docker compose exec 服务名 命令进入某个服务容器。注意新版compose命令已经不需要中间的连字符是docker compose而不是docker-compose老版本插件方式已经逐步淘汰了。修改配置后重新加载用docker compose up -d就够了它会自动比对配置变化并重建有改动的容器不需要每次down再up——down再up会丢掉容器的运行状态数据但数据卷里的数据不会丢。6. 高频问题诊断那些年我踩过的Docker命令坑6.1 启动失败与网络不通的排查步骤docker run之后容器秒退大概是让最多人崩溃的问题了。这个现象的本质是容器的主进程执行完就退出了容器没有前台进程可跑。而我看到很多新手用的镜像启动命令都是前台阻塞式的比如nginx的daemon off;MySQL的mysqld。如果你镜像本身没有问题但容器还是秒退正确排查方法是先别加-d直接前台运行看清楚报错信息docker run --rm 镜像名这时终端会直接显示启动日志。加上--rm是为了退出时自动清理容器避免调试过程中堆积垃圾容器。日志里常见的错误包括权限拒绝、端口占用、配置文件语法错误等看到具体报错再去搜解决方案比盲猜有效率得多。网络不通是另一个高频问题。有一回我用docker run -p 8080:80 nginx启动了一个nginx容器宿主机curl localhost:8080却一直超时。排查顺序是先docker ps确认容器状态是Up再docker logs 容器名确认nginx确实在监听然后docker port 容器名查看实际端口映射结果发现端口映射被正确映射到8080了最后查宿主机防火墙原来是防火墙拦住了8080端口。这个案例说明一个道理Docker端口映射只是做了NAT转发规则最终能不能访问还取决于宿主机防火墙是否放行这两个环节都要兼顾。6.2 磁盘占满、时区错误和其他疑难杂症Docker用久了最典型的症状是磁盘缓慢占满。罪魁祸首通常是三类无主镜像dangling images即none:none的中间层、停止的容器和孤立数据卷。这时候执行docker system df像磁盘体检报告一样列出各项占用然后再对症清理docker image prune清悬空镜像docker container prune清停止容器docker volume prune清孤立数据卷docker system df确认回收效果。注意prune系列默认只清理Docker闲置的资源不会动挂载的宿主机目录。时区问题也很常见容器默认用的UTC时间和北京时间差8小时。日志时间怎么看都对不上特别干扰排查。解决的通用方案是在docker run时加-e TZAsia/Shanghai。多数主流镜像支持这个环境变量部分镜像如果用的不是glibc而是精简的发行版可能需要额外安装tzdata。如果配置了TZ依然无效检查镜像本身的/etc/localtime和/etc/timezone是否真的是Asia/Shanghai有时候在Dockerfile里加一条RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime更直接。还有一类问题是docker exec进入容器后发现没有vim、没有ping、没有telnet。精简镜像里本来就不带这些工具因为容器哲学是一个容器只跑一个进程。这时候可以在容器里执行apt update apt install -y vim基于Debian的镜像或apk add vim基于Alpine的镜像临时装工具调试也可以直接用宿主机的命令配合docker exec参数达到目的。从外面测试容器服务时其实不一定非要进容器docker exec 容器名 curl http://127.0.0.1:8080或者宿主机上telnet 127.0.0.1 映射出来的端口。下面我把高频命令整理成速查表方便贴在手边操作命令拉取镜像docker pull nginx:1.24查看本地镜像docker images删除镜像docker rmi nginx:1.24运行容器前台交互docker run -it --rm ubuntu bash运行容器后台端口数据卷docker run -d -p 8080:80 -v /data:/usr/share/nginx/html nginx查看运行中的容器docker ps查看所有容器docker ps -a查看容器日志跟踪docker logs -f 容器名进入容器docker exec -it 容器名 bash停止/强制停止容器docker stop 容器名 / docker kill 容器名删除容器docker rm 容器名容器与宿主机互拷文件docker cp 源路径 目标路径构建镜像docker build -t 镜像名:标签 .查看容器/镜像详细信息docker inspect 容器名/镜像名查看网络列表/清理悬空资源docker network ls / docker system prune7. 批量操作与运行内存限制经验7.1 用组合命令处理多个容器单容器操作学会之后多容器管理是压测和本地调试最常见的场景。用命令行的组合技巧可以大幅提高效率。比如docker stop $(docker ps -q)能停掉所有运行中的容器docker rm $(docker ps -aq)能删掉所有容器包括已停止的docker rmi $(docker images -q)清掉本地全部镜像。这套组合逻辑的本质是先用查询命令拿到ID列表再交给操作命令执行。但执行之前一定三思特别是docker rmi $(docker images -q)这种指令一条下去本地所有镜像都没了重建环境要花大半天。真要批量清理我建议先docker ps -aq输出列表确认一下再执行删除或者用prune系列命令替代它们带安全过滤比组合命令稳妥得多。批量查看多个容器的状态和数据docker inspect配合--format参数能按模板输出指定字段。比如你想批量查看所有运行中容器的IP可以执行docker inspect --format {{.Name}} {{.NetworkSettings.IPAddress}} $(docker ps -q)。这个格式化输出的语法初看有点复杂但它是从docker命令里提取精确信息的最强工具比人眼在超长JSON里翻效率高太多。7.2 资源限制参数一定要写我遇到不止一次生产环境的崩溃最后查下来都是容器没写资源限制进程把宿主机内存吃光导致的。Docker默认不限制容器资源一个容器确实能占满整台机器。运维规范里跑任何正式容器都要加上内存和CPU限制docker run -d --memory512m --cpus1.0 nginx意思是最多用512MB内存和1个CPU核心。这个限制不仅保护宿主机也保护容器自身——单个容器内存暴涨时OOM机制会先杀那个容器而不是整个宿主机。查看资源使用量用docker stats它实时显示各容器的CPU、内存、网络IO类似宿主机上的top。在压测场景里我习惯开两个终端一个跑docker stats --no-stream定时采样另一个跑压测脚本这样能直观看到容器到底吃到多少资源给调优提供依据。--no-stream参数很实用它只输出当前时刻的状态而不是持续滚动刷新便于记录数据。8. 写在最后的一点经验这些Docker命令单独看都不难难的是把它们组合起来解决实际问题。我个人的习惯是每接触一个新镜像或新项目先自己写一遍完整的docker run命令确认每个参数的作用再把它改写成docker compose文件保存下来。这个过程重复上十几次命令就不再是需要查的知识点了而是像呼吸一样自然的东西。遇到报错别慌先docker logs看应用日志再docker inspect查配置状态这两板斧解决不了再搜具体的错误关键字。下一篇我会继续写Docker命令知识点2把镜像构建、Dockerfile优化和compose编排的经验展开细讲到时候可以结合这期的基础一起看。