ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Docker入门实战:镜像容器、数据持久化与Compose编排指南

2026/9/19 2:24:47 拓冰建站 浏览量
Docker入门实战:镜像容器、数据持久化与Compose编排指南 1. Docker到底是什么一个满足强迫症患者的“打包神器”我最早接触Docker的时候最大的困惑是这玩意儿和虚拟机到底有什么区别后来我用一个特别土的类比想通了——虚拟机是把整个房间都搬走不管你里面有没有用到的家具Docker是把一个集装箱打包好里面只装你要的东西搬到哪儿都能立刻拆箱使用。这个“打包”的动作官方叫法是“镜像”英文是Image。你把操作系统里装好的环境、依赖、配置文件、代码全部装进这个“集装箱”然后在任何一台装了Docker的机器上启动它就能得到一个运行中的“容器”英文叫Container。镜像和容器的关系可以理解成程序安装包和正在运行的程序安装包是静态的程序是动态的。那它到底解决了什么问题举个特别真实的例子以前新同事入职电脑上没有Java环境、没有Redis、没有MySQL光装环境就能折腾半天。用Docker以后给同事一个docker-compose.yml文件一条命令把整套开发环境拉起来二十分钟搞定。这背后就是Docker最核心的价值环境隔离、快速交付、一致体验。你的代码在本地怎么跑在服务器上就怎么跑因为运行环境本身就是和代码一起打包的。这篇指南适合谁零基础刚接触Docker的新手、准备把项目部署到服务器的开发者、还有被环境问题折磨到崩溃的运维小白。我会从概念讲到实操最后带上我踩过的一些坑保证你看完能上手用起来。1.1 隔离不是虚拟机是轻量级进程沙箱很多人觉得Docker个容器就是一个轻量级虚拟机这个理解不准确。虚拟机需要模拟整套硬件然后在上面跑一个完整的操作系统资源开销非常大。Docker没这么“重”它直接复用宿主机就是运行Docker的那台机器的内核只是通过Linux内核的Namespace和Cgroups这两个机制给进程划出一块独立的“地盘”和资源配额。Namespace负责隔离让容器里的进程只能看到自己那部分文件系统、网络栈、进程列表感觉像独占了一个小系统。Cgroups负责限额限制容器最多用多少CPU、多少内存防止某个容器把整台机器吃垮。形象点说虚拟机是每人一台独立的“电脑”大家物理隔离Docker是同一台电脑上开了几个“独立账号”各玩各的互不干扰但底层是同一个系统。所以Docker的优势很明显启动快秒级启动虚拟机通常要几十秒甚至几分钟资源占用小一个容器可能就几十到几百MB虚拟机动辄几个GB一台物理服务器能跑的容器数量远远多于虚拟机数量。缺点也有就是所有容器共享宿主机的内核如果宿主机是Windows或MacDocker实际上是在后台开一个轻量级的Linux虚拟机来跑容器这个细节后面安装Docker Desktop的时候会用到。1.2 镜像与容器的关系模具和蛋糕镜像和容器的关系用“模具和蛋糕”来理解特别合适。模具镜像是静态的你用它一次就能做出一块蛋糕容器想做多少块就做多少块每个蛋糕都是独立的。模具可以存起来也可以分享给别人别人拿过去就能做出一样的蛋糕。镜像本身是分层的。拉取一个镜像的时候你会看到类似Pull complete的一层层下载这就是docker的设计精妙之处——每一层都是只读的不同的镜像可以共享同一个基础层。比如你用的mysql:8.0和redis:7.0镜像底层可能都基于同一个Linux发行版层这部分内容不同镜像之间是共享的不需要重复下载。这也是为什么Docker镜像仓库能高效分发的原因之一。容器则是在镜像之上加了一层可写层。你进入容器装的软件、改的配置都写在可写层里。一旦容器被删除可写层跟着消失所有改动都没了。这是新手最容易踩的坑在容器里改了配置文件容器一删啥都不剩。解决办法后面章节会细讲核心就是用数据卷把“需要持久化保存的内容”和“容器的生命周期”解耦。1.3 一次构建处处运行背后的三个关键词Docker口号式的核心优势有三个关键词Build构建、Ship交付、Run运行。英文念起来押韵翻译过来就是构建一次交付到任何地方都能直接运行。Build指的是把应用和环境一起打包进镜像。Ship指的是通过镜像仓库分发——你可以推送到公网的Docker Hub也可以推送到内网自建的Registry仓库。Run指的是在任何安装了Docker的机器上通过docker run命令把镜像跑起来。这三个动作说完Docker的核心工作流就完整了。理解了这点你就能明白为什么Docker在DevOps和微服务领域这么流行。以前发一个Java服务要准备JDK、Tomcat、环境变量现在直接交付一个镜像里面什么都带好了。以前升级一个组件要小心翼翼担心影响其他服务现在每个服务跑在自己的容器里互相隔离升级就是一个“删旧容器、拉新镜像、起新容器”的过程。这套思维打通了后面所有的实操学起来都会顺很多。2. 环境准备先把Docker装到自己的电脑上这一章我尽量讲得细一点因为安装这关如果过不去后面全是纸上谈兵。我自己踩过的坑包括Windows虚拟化没开启、老旧系统内核版本不够、企业内网代理拦着拉不了镜像等等我都会提到的。Windows和Mac用户最省事的方式是安装Docker Desktop这是官方出品的带图形界面的客户端集成了Docker引擎、命令行工具、Compose插件装完以后打开就能用。Linux用户则通常用命令行安装用软件包管理器操作没有图形界面那么花哨但更直接、更稳。2.1 Windows系统装Docker Desktop和两个前置条件Windows上安装Docker最麻烦的根本不是安装包下载而是两个前置条件CPU虚拟化必须开启和系统必须支持并启用WSL2Windows Subsystem for Linux。这两个条件不满足装上Docker Desktop会直接启动失败。先说虚拟化。进BIOS/UEFI设置找到类似Intel Virtualization Technology或AMD SVM Mode的选项确保是Enabled。怎么看自己电脑开没开虚拟化打开任务管理器切换到“性能”标签点CPU右下角能看到“虚拟化: 已启用”或“已禁用”。如果显示已禁用必须重启进BIOS打开。这一步卡住的非常多尤其是老笔记本BIOS里选项藏得很深甚至有些品牌机默认不显示虚拟化选项需要找攻略去解锁隐藏菜单。第二个前置条件是WSL2。Docker Desktop从某个版本开始默认用WSL2后端来跑Linux容器这比之前的Hyper-V方案更轻快。确认方式是在PowerShell里执行wsl --status如果没安装或版本不对就执行wsl --update更新。这里推荐直接把Ubuntu子系统也装上后面操作Docker的时候和Linux对得上学起来没有认知落差。装完后需要重启一次系统再启动Docker Desktop正常情况下托盘图标很快就会变成绿色表示引擎已经在运行。注意同事的机器曾经出现Docker Desktop启动时报“virtualization support not detected”或“virtualisation support wasn‘t detected”结果BIOS里虚拟化是关的。检查完BIOS之后这类问题基本能解决。如果确认BIOS打开后还是报错可以把Hyper-V相关的Windows功能也开启两个方案二选一即可。2.2 Linux系统Ubuntu和CentOS两条路线Linux安装Docker比Windows省心没有虚拟化那套前置条件但有一个关键前提内核版本够不够新。Docker官方要求内核版本在3.10以上版本越老能用的功能越少。用uname -r先看内核版本如果太低建议先升级系统再装Docker。Ubuntu系包括Debian安装我习惯用官方提供的安装脚本一条命令搞定curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh脚本会自动配置官方源并安装docker-ce、docker-ce-cli、containerd.io这些组件装完自动设置开机自启。CentOS/RHEL系需要先装yum-utils配置仓库再安装sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum install -y docker-ce docker-ce-cli containerd.io sudo systemctl enable --now dockerCentOS 7的老系统容易遇到一个坑默认的iptables规则会和Docker冲突导致容器网络不通。如果遇到了检查一下/etc/sysconfig/iptables里的规则必要时放行Docker网桥对应的网段。另外CentOS 7升级Docker的话一定要先停服务再移除旧版本直接yum upgrade容易把依赖搞坏。装完验证一下docker version docker run hello-world能正常输出Hello from Docker!就说明环境没问题。2.3 配置镜像加速国内拉镜像不变的必备操作镜像下载慢是新手劝退的第一大原因。拉一个几百MB的镜像默认源卡在几千字节每秒确实崩溃。解决办法是配置镜像加速器。现在的加速器通常需要登录后获取专属地址之前很多公开的加速地址陆续失效了你可以在自己的容器镜像服务控制台里找到“镜像加速器”页面那里会给一个https://xxx.mirror.aliyuncs.com的专属地址速度比较稳定。Docker Desktop用户在设置里找到Docker Engine选项把加速地址加到registry-mirrors数组里{ registry-mirrors: [https://你的加速地址.mirror.aliyuncs.com] }Linux用户编辑/etc/docker/daemon.json没有这个文件就新建一个内容一样然后执行sudo systemctl restart docker重启。配置完可以拉个镜像试一下速度明显有提升才算生效。3. Docker常用命令实战从0到1跑起第一个容器命令多记不住没关系Docker命令的套路非常固定核心就是“对象操作”。对象就是镜像、容器、网络、数据卷这几类操作就是增删改查。我把使用频率最高的命令串成一条实际操作线照着敲一遍基本就形成肌肉记忆了。3.1 镜像管理拉取、查看、构建、删除先从镜像拉取开始。以MySQL 8.0为例docker pull mysql:8.0mysql是镜像名8.0是标签Tag用来区分版本。不写标签默认拉取latest也就是最新版。这里提醒一下生产环境尽量别用latest因为构建镜像的人不定时更新标签拉下来的内容每天都在变排查问题的时候会非常酸爽。最好指定明确的版本号。查看本地有哪些镜像docker images输出会列出仓库名、标签、镜像ID、创建时间和大小。构建镜像用的是Dockerfile这是把应用打包进镜像的核心文件。最简单的Dockerfile长这样FROM openjdk:17 COPY target/my-app.jar /app.jar EXPOSE 8080 ENTRYPOINT [java, -jar, /app.jar]FROM指定基础镜像COPY把编译好的文件拷进去EXPOSE声明容器对外暴露的端口ENTRYPOINT指定容器启动时执行的命令。然后在项目目录下执行docker build -t my-app:1.0 .-t给镜像起名字和标签最后的点表示构建上下文在当前目录。删除不需要的镜像用docker rmi 镜像ID或名字。遇到被容器占用的镜像会删除失败提示image is being used by需要先删容器再删镜像。磁盘空间紧张的时候可以执行docker system prune清理所有悬空镜像和停止状态的容器但慎用它会无差别清理。3.2 容器生命周期管理run、start、stop、rm启动一个容器最常用的是docker run我给你一个完整的例子docker run -d --name mysql8 -p 3306:3306 -e MYSQL_ROOT_PASSWORD123456 -v mysql-data:/var/lib/mysql mysql:8.0拆开看每个参数的含义-d表示后台运行detach模式不占住终端--name mysql8给容器起名字方便后面操作-p 3306:3306把宿主机的3306端口映射到容器的3306端口等于外部访问宿主机3306你就能连到容器里的MySQL-e MYSQL_ROOT_PASSWORD123456是设置环境变量MySQL镜像就是靠这个变量初始化root密码的-v mysql-data:/var/lib/mysql是数据卷挂载MySQL的数据实际写到宿主机上的mysql-data卷里容器删了数据还在。有数据卷挂载有个特别重要的坑容器里MySQL的默认数据目录不同版本的MySQL或者不同的镜像提供了不同的路径具体要看镜像文档。写错路径的话数据照样丢。常用操作还有docker ps # 查看运行中的容器 docker ps -a # 查看所有容器含已停止的 docker start mysql8 # 启动已存在的容器 docker stop mysql8 # 停止容器 docker restart mysql8 # 重启容器 docker rm mysql8 # 删除容器需先停止docker rm如果加了-f参数可以强制删除正在运行的容器但这样做很容易导致数据没落盘就丢失不适合生产环境。3.3 进入容器和查看日志排查问题的基础操作容器启动后想进去看里面的情况用docker exec -it mysql8 bash-it表示交互模式bash是进入容器后要执行的shell。很多精简版镜像没有bash只有sh进不去就换docker exec -it mysql8 sh试试。在容器里敲exit退出时容器本身不会停止这跟直接连接容器或者说attach的机制不太一样exec只是临时开了个进程进去操作。查看容器日志这是排查问题最重要的命令docker logs mysql8 docker logs -f mysql8 # 持续跟踪日志输出类似tail -f docker logs --tail 100 mysql8 # 只看最后100行容器启动就秒退了第一件事就是docker logs 容器名看看报错了什么。有一次我部署的Nginx容器怎么也起不来查日志发现是端口被宿主机另一个进程占了把那个进程停掉就正常了。日志里经常藏着问题和答案养成出问题先查日志的习惯能解决80%的报错。4. 数据持久化容器可以随便删数据绝对不能丢我见过不少新手在生产环境干过这种事MySQL跑在容器里数据没做持久化某天手一抖docker rm -f mysql8整个数据库灰飞烟灭。这个事故的本质就是没理解容器是一种“短命”的设施容器本身可以被随时替换但里面产生的数据必须另找地方安放。Docker提供了两种主要的持久化方式数据卷Volume和绑定挂载Bind Mount。理解这两者基本就掌握了容器数据管理的核心。4.1 数据卷最推荐的方式数据卷是Docker自己管理的一块存储空间物理位置在宿主机的/var/lib/docker/volumes/下面平时不用管它在哪直接用卷名操作就好。它的好处是和宿主机的文件系统解耦备份迁移方便跨容器共享也容易。创建和使用数据卷docker volume create mydata docker run -d --name app1 -v mydata:/app/data my-image:1.0如果卷不存在Docker会自动帮你创建所以直接-v mydata:/app/data也是可以的。推荐在命令里显式指定卷名这样后面备份的时候知道是哪个卷。绑定挂载是把宿主机的某个路径直接映射进容器docker run -d --name app2 -v /home/user/app-config:/etc/app my-image:1.0我习惯把配置文件用绑定挂载管理代码部署目录也常用这种方式因为它能直接看到宿主机文件改一下立刻同步到容器里调试起来很方便。缺点是宿主机路径如果变了容器就找不到数据了可移植性比数据卷差一些。4.2 一个实战场景MySQL数据落盘方案以MySQL为例推荐的做法是在docker run命令里指定数据卷把MySQL原生的数据目录挂出来docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDmy-secret-pw \ -e MYSQL_DATABASEtestdb \ -v mysql-data:/var/lib/mysql \ mysql:8.0这样MySQL往/var/lib/mysql写入的数据都会落到名为mysql-data的数据卷里。后续用docker stop和docker rm删掉容器数据卷还在重新执行一次同样的run命令挂上同一个卷数据就全部回来了。对数据进行备份也很简单docker run --rm -v mysql-data:/data -v /backup:/backup alpine tar czf /backup/mysql-data-$(date %Y%m%d).tar.gz -C /data .这条命令借用了一个临时的alpine容器把mysql-data卷打包成tar.gz放到宿主机的/backup目录打完就退出。这个思路很Docker工具型任务用临时容器完成用完即走。4.3 容器网络模式与端口映射原理网络这一块新手容易混乱。默认情况下Docker会创建一个名为bridge的虚拟网桥所有容器只要不指定--network都会被连到同一个默认网桥上容器之间可以通过IP互通但IP不固定。同一台机器上多个容器互相访问更好的方式是用容器名做DNS解析这个功能Docker内置支持前提是容器在同一个自定义网络上。创建一个自定义网络然后指定容器加入docker network create my-net docker run -d --name mysql8 --network my-net -e MYSQL_ROOT_PASSWORD123456 mysql:8.0 docker run -d --name app --network my-net -p 8080:8080 my-app:1.0上面app容器里直接访问mysql8:3306就能连上数据库不需要知道MySQL容器的IP。端口映射方面-p 3306:3306是把容器端口暴露到宿主机不带-p的容器之间通过内部网络访问同样没问题。-p参数的格式是宿主机端口:容器端口如果有多个端口就写多个-p。宿主机端口如果被占用容器会启动失败日志会提示地址已被占用。生产环境中我习惯把所有端口映射统一记录在一个文档或Compose文件里方便排查网络问题。5. 从单容器到多容器用Docker Compose编排一套完整环境当项目需要多个容器协同工作的时候一条条docker run执行会很痛苦。比如一个典型的Web应用需要Nginx、Java后端、MySQL、Redis这么几个容器每次启动都要敲好几条命令、记N个参数。Docker Compose就是干这个的用一个YAML文件描述整个服务栈一条命令全部拉起。5.1 compose文件核心结构docker-compose.yml的基本结构长这样version: 3 services: mysql: image: mysql:8.0 container_name: mysql8 ports: - 3306:3306 environment: MYSQL_ROOT_PASSWORD: 123456 volumes: - mysql-data:/var/lib/mysql networks: - my-net redis: image: redis:7.0 container_name: redis7 ports: - 6379:6379 networks: - my-net app: build: ./ container_name: myapp ports: - 8080:8080 depends_on: - mysql - redis networks: - my-net networks: my-net: volumes: mysql-data:services下面定义每个服务image指定用哪个镜像build指定通过当前目录的Dockerfile构建ports做端口映射environment传环境变量volumes挂载数据networks把服务加入自定义网络。最后两段声明了网络和数据卷。启动的命令是docker compose up -d-d还是后台运行。停止并清理docker compose downdown会停止所有容器并移除由Compose创建的网络。数据卷默认不会被删如果要连数据一起清掉加-v参数慎重使用它会连数据库数据一起删除。5.2 用Compose部署一套MySQLRedisNginx写一个实际场景想在本机快速搭建一套带Nginx反向代理、MySQL数据库和Redis缓存的开发环境。把上面的YAML文件保存为docker-compose.yml然后再加一个Nginx服务nginx: image: nginx:1.27 container_name: nginx ports: - 80:80 - 443:443 volumes: - ./nginx/conf.d/:/etc/nginx/conf.d/:ro - ./nginx/html:/usr/share/nginx/html depends_on: - app./nginx/conf.d/:/etc/nginx/conf.d/:ro是绑定挂载加ro只读模式宿主机上的Nginx配置直接生效不用进容器改文件。然后把Nginx配置写在./nginx/conf.d/default.conf里编写端口转发规则时把请求转发到app:8080这里的app就是Compose里的服务名Docker会自动解析成对应容器的IP。执行docker compose up -d再执行docker compose ps查看所有服务状态只要显示Up就成功了。这套配置复制到任何一台装有Docker和Compose的机器上都能一键拉起开发环境和生产环境的差异被压缩到了最低。5.3 依赖管理和启动顺序要注意什么Compose里的depends_on控制的是“启动顺序”但仅仅是“先启动依赖服务”并不保证依赖服务“可用”。举个例子appdepends_on: mysqlCompose会先启动MySQL容器但MySQL在容器启动后还需要几秒钟做初始化此时app如果立刻尝试连接数据库可能连接失败。解决这个问题有两个办法一是应用端做重试逻辑连不上就等几秒再重试二是镜像里自带健康检查或者你在Compose里配置healthcheck。比如MySQL的mysql: image: mysql:8.0 healthcheck: test: [CMD, mysqladmin, ping, -h, localhost] interval: 5s timeout: 3s retries: 10然后在app的depends_on里写depends_on: mysql: condition: service_healthy这样app会等MySQL通过健康检查后再启动。这个特性在容器编排的时候特别有用尤其是多个服务之间有强依赖关系的时候。6. 进阶实践搭建内网私有镜像仓库事情做大了之后你一定会碰到一个需求——把镜像分发到内网环境或者推送到自己团队维护的仓库。虽然公共Docker Hub很方便但公司内网部署、涉及私有代码的镜像一般不会放到公网上去。自建一个Registry仓库是Docker进阶的必经之路。6.1 Docker Registry部署官方的registry镜像可以直接用来搭建私有仓库docker run -d \ --name registry \ -p 5000:5000 \ -v /data/registry:/var/lib/registry \ --restartalways \ registry:2这就在本机的5000端口起了一个Registry仓库服务数据保存在宿主机的/data/registry目录。--restartalways是很有用的参数容器意外退出或者机器重启后会自动拉起适合常驻服务。推送镜像到该仓库docker tag my-app:1.0 192.168.1.100:5000/my-app:1.0 docker push 192.168.1.100:5000/my-app:1.0这个IP:端口的名字是必需的因为Docker推送镜像时会把仓库地址作为前缀。默认情况下Registry走HTTPDocker客户端出于安全原因只允许推送到HTTPS仓库或者本机的localhost。真要用HTTP和远程IP需要修改Docker守护进程的配置{ insecure-registries: [192.168.1.100:5000] }然后把Docker重启才能正常推送拉取。生产环境强烈建议给Registry配上HTTPS证书项目做大了这步逃不掉。6.2 配置Registry的存储和认证registry:2镜像默认把镜像数据存在容器内的/var/lib/registry这跟普通容器一样容器删了数据就没了所以必须挂载到宿主机目录。我见过有人忘了挂载这行重启容器后仓库里所有镜像消失非常尴尬。前面-v /data/registry:/var/lib/registry已经配置好了建议不要省掉两个字“持久化”。私有仓库如果要对访问做控制可以配置简单的HTTP基本认证。方法是用htpasswd生成密码文件然后通过环境变量传给Registry容器docker run -d \ -p 5000:5000 \ --name registry \ -v /data/registry:/var/lib/registry \ -v /auth:/auth \ -e REGISTRY_AUTHhtpasswd \ -e REGISTRY_AUTH_HTPASSWD_REALMRegistry Realm \ -e REGISTRY_AUTH_HTPASSWD_PATH/auth/htpasswd \ registry:2客户端登录docker login 192.168.1.100:5000输入账号密码即可。这套方案的优点是简单缺点是安全级别不高适合内网团队使用暴露到公网务必加TLS和其它防护措施。7. 常见问题排查与避坑实录Docker用久了会发现真正的坑往往不是Docker本身而是环境、网络、权限这些周边问题。这一章我把自己动手整理过的错误汇总一下按频率从高到低排列。7.1 Windows虚拟化报错与WSL2问题常见的报错信息是Docker Desktop failed to start because virtualisation support wasn‘t detected或者virtualization support not detected。去BIOS里找虚拟化开关Intel VT-x或AMD SVM开启后重启。注意某些安全软件也会把虚拟化功能禁用掉需要在软件设置里解除限制。WSL2相关的报错是please enable the Virtual Machine Platform或failed to connect to the docker api at npipe:////./pipe/docker_desktop_linux。处理方式# 以管理员身份在PowerShell里执行 dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart wsl --set-default-version 2然后重启系统。如果wsl --status显示内核版本太旧执行wsl --update更新内核。7.2 镜像下载慢、超时和无权限镜像拉取慢的根源是网络连接Docker官方仓库很慢。最有效的办法是配置镜像加速器。加速器只对Docker Hub拉取生效对某些第三方仓库不一定有效。如果某个镜像老超时可以换个标签版本拉取试试不同标签可能对应不同的manifest列表大小。另外docker push到Docker Hub遇到denied: requested access to the resource is denied大概率是没登录或没权限执行docker login之后重试。团队协作时镜像命名规范也很重要统一前缀和版本标签规则能省去很多“这个镜像是谁传的、入口是啥”的麻烦。7.3 Linux权限报错和Docker服务起不来新安装完Docker执行命令直接报permission denied while trying to connect to the Docker daemon socket——用普通用户执行Docker命令但当前用户不在docker用户组里。解决办法sudo usermod -aG docker $USER newgrp docker退出重新登录一下就能生效。这种方式让普通用户能用Docker命令方便开发调试但在安全敏感的生产环境建议谨慎毕竟拥有docker组权限相当于能操作宿主机上的特权容器。CentOS上systemctl start docker失败先用journalctl -u docker看日志常见原因是容器网络与系统iptables策略冲突或者selinux权限拦截适当调整策略后服务能正常起来。7.4 容器动不动就退出、磁盘还说不够很多新手会发现容器启动后立刻退出查看日志发现应用自己崩了。这通常是容器里进程的启动命令不对或者依赖没装上。挨个排查用docker logs看最后一次输出用docker start 容器名 docker exec -it 容器名 bash进入容器手动执行启动命令看报错。以我的经验大部分“容器秒退”是进程前台化的问题——容器里必须有前台进程占据入口你命令跑完退出容器就跟着退出。另一个高频坑是磁盘空间。Docker使用久了/var/lib/docker越来越大镜像、容器、日志、数据卷全堆在里面。我习惯定期执行docker system df # 查看各类型的空间占用 docker container prune # 清理已停止的容器 docker image prune # 清理悬空镜像 docker system prune -a --volumes # 全量清理慎用如果只想清理某个容器的日志可以定位到该容器的日志文件通常是/var/lib/docker/containers/容器ID/*-json.log直接清空文件内容。生产机器要避免直接把日志文件删掉需要停容器才行物理文件的句柄占用会导致空间不释放。最后总结一下我的真实体验Docker这个东西刚接触可能觉得概念抽象、命令又多但只要亲手跑通一个带MySQL的Web应用所有点就串联起来了。我个人的建议是先装好环境跟着文章把常用命令敲一遍再从Docker Compose入手编排一个应用栈等熟悉了再去啃Dockerfile和镜像构建的细节比直接闷头读文档要有用得多。这套工具链一旦习惯你会发现以前那些“在我电脑上是好的”之类的问题真的会少很多。