我见过太多这样的场景:照着安装教程装好了Docker Desktop,然后光标停在终端里发呆,不知道下一步该干嘛——或者更惨,连hello-world都没跑起来就卡在virtualization support not detected这类报错上。Docker的使用指南网上一搜一大堆,但大部分是官方文档节选或者纯粹的“命令大全”,很少有人把“为什么要这么做”“报错到底在说啥”讲透。这篇内容不是知识搬运,是我这些年装Docker、跑容器、搭服务、调网络、被各种奇怪报错折磨完之后的实操记录。适合刚接触容器化的人,也适合已经用了一阵子、但遇到问题只能靠搜答案的朋友。看完你至少能明白三件事:Docker安装时那些坎真正的突破点在哪、日常最常用的命令背后的逻辑是什么、网络不通和权限报错到底该怎么一步步定位。
1. 先弄明白Docker到底解决什么问题,再决定装不装
很多新手容易把Docker当成一个“高级虚拟机”,装了之后发现跟VMware差不多,于是陷入一个误区:什么都想往Docker里塞,塞完又觉得这玩意儿也没啥了不起。不带偏见地说,如果你没理解Docker解决的问题,你所有命令都是照葫芦画瓢,遇到问题还是会懵。
1.1 环境不一致的窘境,我替你先踩过
我第一次被Docker打动,是因为一次生产事故排查。当时测试环境跑得好好的服务,到了生产环境就是起不来,最后发现是基础依赖版本不一致:测试机上的OpenSSL是老版本,生产机上被安全策略强制更新到了新版本,C库版本直接决定了一个加密模块能不能加载。一台机器上装多个版本的服务互相覆盖,也是家常便饭——你装MySQL 5.7的时候好好的,后来为了跑另一个项目装了个MySQL 8,结果5.7的服务直接被挤得启动不了,数据目录被初始化脚本搞乱,那叫一个酸爽。
Docker解决的就是“环境不一致”和“多版本共存”这两个核心痛点。它把应用本身、应用的依赖、应用运行所需的基础设配(比如Python版本、Java版本、库文件、环境变量)统统打包成一个可以被重复启动的单元。换了一台机器,不用重新配置环境,直接启动同一个镜像就能得到几乎一致的行为。说白了,它不是帮你省内存的,是帮你消灭“在我机器上是好的”这种诅咒的。
1.2 镜像、容器、仓库:用快递物流来类比
很多人一上来就被镜像、容器、仓库这三个词绕晕。我一般用快递解释:镜像是一个菜谱加一份半成品的标准包,里面把做菜需要的所有原料、调料、步骤都固定下来了;容器是你按照这份标准包实际做出来的一盘菜,可以端上桌吃,吃的过程可以加香菜、可以少放盐,修改只影响这一盘菜,不影响标准包;仓库是存放这些标准包的公共货架,你可以从货架上拿一份标准包回家(拉镜像),也可以把自己研发的新菜谱打包放到货架上(推送镜像)。
同一个镜拉起多少个容器都互不影响,你要测试新版逻辑,可以用新代码构建一个新镜像,丢到另一个容器里跑。旧容器继续服务老逻辑,等验证完了切换一下端口或者负载均衡策略就行。理解了这个三角关系,后续的命令操作逻辑就不会乱。
1.3 Docker和虚拟机不是一回事,别混着理解
虚拟机通过Hypervisor模拟整台硬件设备,然后在这个虚拟硬件上跑一个完整的操作系统,所以虚拟机镜像通常好几个GB,启动也要等它完成完整的开机流程。Docker容器则是直接共享宿主机的Linux内核,利用命名空间(Namespace)做隔离,用控制组(Cgroups)做资源限制,容器里跑的是一个个隔离的用户空间进程,并没有自己的内核。这也是为什么Windows上跑Linux容器必须借助WSL2或者虚拟机技术——Windows内核和Linux内核不一样,需要一层虚拟化支持来提供Linux内核环境。
搞清楚这一点之后,你对很多报错就能产生正确的直觉。比如“Docker Desktop failed to start because virtualization support not detected”,本质就是Docker帮你跑Linux容器的那个虚拟化层没准备好,不是你装的Docker软件坏了。
2. 安装这一关:WSL2、虚拟化检测和镜像加速源
安装模块是劝退新手最严重的重灾区。Docker本体其实很好装,麻烦的是它依赖的一系列运行环境:Windows上需要WSL2、需要开启虚拟化,Linux上需要处理系统源和权限。热词里那一大串“docker desktop安装教程”“virtualization support not detected”“win11 docker安装”“ubuntu安装docker”,基本都卡在这几条路上。
2.1 Desktop版还是Engine版,取决于你在哪台机器上用
先做选择题:桌面开发机,推荐直接装Docker Desktop,因为它自带图形界面、容器管理面板、Compose插件、Kubernetes集成,对日常调试最友好。服务器上则装Docker Engine(也就是社区版引擎),不装图形界面,用命令行管理,占用更小更稳定。
但注意,Docker Desktop在Windows上目前默认走WSL2后端,这意味着你要先给系统装好WSL2,而不是直接下载Desktop安装包就完事。很多人的失败就发生在这一步:Desktop是装上了,但底层WSL2没就绪,启动必然报虚拟化相关错误。
2.2 Windows安装中两个高频失败现场怎么破
第一个高频现场:启动Docker Desktop直接弹“virtualization support not detected”或者类似“Docker Desktop failed to start because virtualization support is not detected”。很多人一看“虚拟化未检测到”,第一反应是重启进BIOS开VT-x,但实际情况往往是系统层面没装全配套组件。先打开“控制面板-程序-启用或关闭Windows功能”,确认三个东西的状态:适用于Linux的Windows子系统(WSL)、虚拟机平台、Hyper-V(如果用的非专业版系统没有Hyper-V,至少前两个必须有)。勾选后重启,然后在管理员PowerShell里执行一句wsl --status看看WSL版本,如果是1的话再执行wsl --update升级到2,最后用wsl --set-default-version 2固定版本。
第二个高频现场:WSL2装了、虚拟化也开了,Desktop仍然报“failed to connect to the docker api at npipe:////./pipe/dockerDesktopLinux”。这个npipe错误翻译过来就是“docker CLI想通过Windows命名管道找Docker引擎,但引擎根本没起来”。处理思路不是卸载重装,而是按顺序排查:先在任务栏右下角确认Docker Desktop是否真的启动完成,再执行wsl --shutdown把WSL彻底停掉,之后重新打开Distro让WSL重新就绪,最后再启动Docker Desktop。如果还不行,去“设置-网络”里把WSL的镜像网络模式开关切换一下,这一步解决了很多Windows 11用户管道连不上的问题。
2.3 Linux安装命令与镜像加速源配置
Ubuntu系的安装路径很固定——先更新索引,再安装一些前置依赖,然后添加Docker官方GPG密钥和仓库,最后安装docker-ce和docker-compose-plugin。我自己的习惯是尽量避免复制一长串官方脚本到生产机器上直接执行,拆成自己明确知道每一步在干嘛的命令做,出问题好排查。CentOS同理,但要注意CentOS 7自带旧版Docker包,别直接用yum install docker,那装出来的是老得掉渣的版本,热词里“centos7升级docker”说的就是这种情况,正确操作是先卸载掉系统自带的旧包,再从仓库装新版。
装完之后立刻验证:sudo docker info。如果输出末尾的Registry Mirrors是空,就手动创建/etc/docker/daemon.json,写入镜像加速源配置。加速源这里我给不了你永久固定的地址,因为各家云厂商都在调整自己的加速器服务,最稳妥的办法是登录你使用的那家云厂商容器镜像服务控制台,找到专属加速地址填进去。配置完执行sudo systemctl restart docker,再跑docker pull nginx:alpine做验证,正常情况下速度会有一个质的飞跃。
2.4 装完之后建议立刻验证的三个命令
安装完成不代表万事大吉。我建议每次装完Docker都顺手执行三个命令:docker version看客户端和服务端版本是否都能正常显示,docker info看存储驱动、镜像加速、资源限制是否正常,docker run --rm hello-world看能否真正拉起一个容器。第三个命令如果卡住不动,大概率就是镜像拉取速度问题;如果报了权限错误,把当前用户加进docker用户组(sudo usermod -aG docker $USER,然后重新登录),生产环境图省事可以再加一句newgrp docker立即生效,不用真的登出重新登录。
3. 看懂run命令的参数逻辑,跑起第一个容器
很多教程教完安装直接甩给你一堆常用命令表格,但这种做法效率极低。你不知道为什么要有-d、为什么要有-p、为什么容器要--name,后面所有命令都记不稳。我第一次用Docker的时候也疯狂复制粘贴,结果第二天自己都看不懂自己贴的是什么。后来把参数分门别类理解之后,才真正开始“用”Docker。
3.1 docker run参数拆解:名字、端口、数据卷从哪下手
一条完整的docker run命令,拆开就是几块积木:你想以什么名字运行(--name)、希望容器在后台跑还是前台跑(-d还是前台)、把容器哪个端口映射到宿主机的哪个端口(-p)、需要哪些环境变量(-e)、需要把宿主机哪些目录挂进去或者把容器哪些数据持久化出来(-v)、容器挂了要不要自动重启(--restart)。
举个例子,启动一个MySQL:
docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=123456 \ -e TZ=Asia/Shanghai \ -v /data/mysql8:/var/lib/mysql \ mysql:8.0-d让容器在后台跑,不会占着当前终端。--name mysql8是给容器起个固定名字,否则Docker会给它随机生成一个叫“naughty_keller”之类的名字,后面想操作它你根本记不住。-p 3306:3306意思是把宿主机3306端口转发到容器3306端口,这样主机上的客户端才能通过localhost:3306访问到容器里的MySQL服务。-e是往容器环境变量里塞配置,MySQL官方镜像用MYSQL_ROOT_PASSWORD这个环境变量来决定root用户初始密码。-v /data/mysql8:/var/lib/mysql是把容器里MySQL目录映射到宿主机目录,不然容器一删,数据跟着一起没。
3.2 镜像与容器的常见生命周期操作
容器跑起来之后,常见的操作就是:查看所有运行中的容器用docker ps,想看所有容器包括已经停掉的加-a;停止容器用docker stop 容器名;启动一个已存在的停止容器用docker start 容器名;不再需要了才用docker rm 容器名强制删掉。镜像那边:查看本地镜像docker images,删除没用的镜像docker rmi 镜像ID,清理那些悬空的、没有容器在用的镜像是docker image prune,更激进一点把没启动的容器、无用网络、悬空镜像一口气清掉是docker system prune -a。这套操作里最容易混淆的是stop和rm:stop只是把容器停下来状态冻结,容器还在;rm才是连死尸一起从磁盘清走,一删解千愁但同时数据也无了,所以挂载卷务必提前想清楚。
3.3 进入容器和查看日志的正确姿势
调试阶段最有用的三个命令是logs、exec和cp。docker logs -f 容器名是看实时日志,服务启动失败或者进程崩了,第一个动作永远是看这个输出,而不是扒窗口公告。要进到容器终端里看环境变量、检查配置、手动执行命令,用docker exec -it 容器名 bash,进去之后就是在容器内开了一个shell。注意基础镜像分两类,Debian/Ubuntu系列的容器里有bash,但很多精简镜像比如Alpine系只有sh,所以执行docker exec -it 容器名 sh更通用。还有一个用途被低估的命令是docker cp:从容器里把配置文件或者日志拷出来docker cp 容器名:/etc/nginx/nginx.conf ./nginx.conf,在宿主机上改完再拷回去,很多时候比进容器装vim高效得多。
4. 用Dockerfile打造自己的镜像:Python和PHP两个实战
用现成镜像跑别人服务只是一半,另一半是把自己的项目打包成镜像。热词里“ubuntu安装docker并运行python环境”“php使用docker打包镜像”“idea 打包docker镜像”都属于这个方向。学会Dockerfile之后,你会发现“部署一个项目”变成了“跑一个镜像”,上手门槛被压得很低。
4.1 构建镜像的核心逻辑:分层、缓存与顺序
Dockerfile每一条指令都会生成一层镜像,这层镜像可以被缓存复用。基础镜像发生变化、或者某条指令的上下文变了,从那一层开始往后的缓存全部失效。这个机制直接决定了Dockerfile的书写顺序:把不会频繁变动的指令写在前面,把经常改动的源代码复制写在后面。比较常见的血泪教训是:有人在Dockerfile里先把项目源代码COPY进去,再RUN安装依赖,结果每次改动一行代码,整个依赖安装过程都要重新来一遍,构建时间从一分钟膨胀到二十分钟。正确姿势是先COPY package.json这类只与依赖相关的文件,执行依赖安装,再COPY其余源码,这样依赖层稳稳命中缓存。
4.2 一个可以直接用的Python环境Dockerfile
就以最常见的Python Flask或者FastAPI项目为例:
FROM python:3.11-slim WORKDIR /app ENV PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 8000 CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]逐行看:python:3.11-slim是官方精简Python镜像,比full镜像小一大截,生产环境够用;WORKDIR /app设置容器内工作目录,后面执行命令和路径都以此为基准;PYTHONDONTWRITEBYTECODE=1防止生成pyc缓存文件,PYTHONUNBUFFERED=1让Python日志不经过缓冲直接输出,这样docker logs能看到实时日志。COPY requirements.txt .只先拷贝依赖清单,RUN pip install安装依赖,再COPY . .拷贝源代码。最后CMD是容器启动时执行的命令,这里用uvicorn跑FastAPI项目。
构建命令:
docker build -t mypyapp:latest . docker run -d --name mypyapp -p 8000:8000 mypyapp:latest4.3 PHP项目打包的常见姿势
PHP项目打包镜像有一个容易踩的细节:传统PHP-FPM容器里面没有Nginx,跑PHP项目一般得两个容器配合,一个跑PHP-FPM解释执行PHP代码,一个跑Nginx处理静态文件和反代动态请求。Dockerfile通常基于官方php:8.2-fpm镜像,先装扩展:
FROM php:8.2-fpm RUN apt-get update && apt-get install -y \ libzip-dev \ libpq-dev \ && docker-php-ext-install pdo_mysql zip WORKDIR /var/www/html COPY . . EXPOSE 9000 CMD ["php-fpm"]这里有个知识点:官方php镜像自带docker-php-ext-install这个命令,安装PHP扩展直接用它,比手动改php.ini靠谱得多。容器启动后,Nginx容器把自己公开目录挂到同一个卷上,并把.php请求转发到php-fpm容器的9000端口。这套组合是热词里“php使用docker打包镜像”问得最多的情况,建议直接用docker-compose编排,下面第5章会讲。
4.4 构建上下文的坑,我为此吃过亏
构建镜像时最后的.指的是构建上下文——Docker CLI会把当前目录整个打包发送给Docker守护进程。很多人项目里塞了node_modules、vendor、.git这些巨无霸目录,一条docker build命令能把发送上下文这一步卡到怀疑人生。解决办法是在项目根目录建一个.dockerignore文件,语法跟.gitignore类似,把node_modules、vendor、*.log、.git全部排除掉,构建速度会改善非常多。另一个坑是别把整个宿主机的文件路径直接COPY进镜像,COPY /root/style.css /app/能成功是能成功,但会破坏镜像的上下文一致性,换台机器构建直接失败,正确做法是把需要打包的文件复制到项目目录下再COPY。
5. 实战组合:MySQL 8、Redis主从与Compose编排
基础知识过完,我们来点能直接落地的。热词里“docker安装mysql8.0并使用”“docker安装redis主从”“gitlab 社区版docker部署”“docker部署微服务项目”都属于这一层。我把最常见的几个服务编排场景走一遍,顺便把那些“看着没问题但一跑就挂”的细节挑明。
5.1 MySQL 8容器部署:目录、时区、编码一个都不能少
MySQL 8部署比MySQL 5.7要多注意两点:一是时区默认是UTC,你存进去的NOW()会比北京时间慢8个小时;二是字符集如果只设默认值,排序规则可能出现奇怪的问题。我惯用的启动命令是:
docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=YourPass123 \ -e MYSQL_DATABASE=appdb \ -e TZ=Asia/Shanghai \ -v /data/mysql8:/var/lib/mysql \ -v /data/mysql8-conf:/etc/mysql/conf.d \ --restart unless-stopped \ mysql:8.0注意第一个-v把数据目录挂出来了,这个必须有,不然容器误删就是数据灾难;第二个-v可以把自定义的my.cnf片段放进去,比如强制设置character-set-server=utf8mb4和collation-server=utf8mb4_unicode_ci。这里提醒一句:MySQL 8默认认证插件是caching_sha2_password,老客户端或部分旧版PHP连接器不兼容,如果连不上先看报错,遇到认证问题,就在SQL里执行ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '密码';把认证方式降级。
5.2 Redis主从部署,一条命令就够
Redis主从在纯物理机部署时要做一堆配置同步,在Docker里反而简单得不像话。先拉起主节点:
docker run -d --name redis-master -p 6379:6379 redis:7再拉起从节点,通过--link连到主节点并指定主从关系:
docker run -d --name redis-slave -p 6380:6379 \ --link redis-master:master \ redis:7 redis-server --replicaof master 6379验证就进从节点执行redis-cli info replication,看到role:slave和master_link_status:up就说明关系建立。这里有个关键细节:旧版Redis从节点配置用--slaveof参数,Redis 5以后改成了--replicaof,很多跑在旧教程上的人在这翻车。另外,--link是Docker的老式容器间通信方式,现在更推荐的做法是让两个容器加入同一个自定义网络,见第6章。真正生产环境主从起码要加密码,别说只用单机演练的主从不需要,习惯了裸奔迟早要出事。
5.3 用docker-compose把整套环境固化下来
一条条docker run敲久了会烦,尤其是每次重启服务器都要重新理一遍启动顺序。docker-compose的价值在于把“一套多容器的环境”用YAML文件固化下来。举个例子,把上面MySQL和Redis以及一个Java微服务后端全部编排在一起:
version: "3.8" services: mysql8: image: mysql:8.0 container_name: mysql8 ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: "YourPass123" MYSQL_DATABASE: "appdb" TZ: "Asia/Shanghai" volumes: - ./mysql-data:/var/lib/mysql restart: unless-stopped redis: image: redis:7 container_name: redis ports: - "6379:6379" restart: unless-stopped backend: build: ./backend container_name: backend ports: - "8080:8080" environment: SPRING_DATASOURCE_URL: "jdbc:mysql://mysql8:3306/appdb?useSSL=false" SPRING_REDIS_HOST: "redis" depends_on: - mysql8 - redis restart: unless-stopped这个文件里最重要的叫服务发现:在同一Compose网络里,微服务连接MySQL可以直接用服务名mysql8当主机名,Docker内置DNS会解析成对应容器的内网IP。这也是很多新手老困惑的“我在容器里访问另一个容器该用IP还是用什么”的答案。执行docker-compose up -d一套环境全部起来,执行docker-compose down全部停掉。换台新部署机只要把这个目录拷过去,构建加启动一条命令搞定。
5.4 GitLab社区版部署时的内存与端口处理
热词里“gitlab 社区版docker部署”也是高频操作。GitLab官方镜像很重,部署时很容易踩两个坑:一个是内存不足,GitLab官方建议至少4GB内存,RN内存只有2GB的AWS免费实例上跑GitLab会频繁OOM;另一个是端口冲突,容器内默认80端口,宿主机如果80被占,映射端口的时候就要小心,-p 8089:80之后,gitlab.rb里external_url也要改成对应端口。轻量备用方案是直接用极狐GitLab镜像,配置项基本一致,只是镜像源路径不同。这里不再赘述完整部署,只提醒一句:GitLab容器启动到web界面可用,通常需要三到五分钟,别一秒钟没见页面就以为失败了。
6. 网络排查与高频报错的完整修复记录
终于到了很多人最头疼的部分:容器网络。热词里“docker网络不通”占了很大比例,而且往往搜不到一条能直接对上的答案。我用自己的排查经验复盘一遍,不是给一条命令,而是给你一个定位问题的链路。
6.1 容器间连不上的第一步:网络定界
遇到“网络不通”先别乱试,先问三个问题:是容器访问外网不通,还是容器访问宿主机服务不通,还是容器之间的通信不通?方向定了,手段完全不同。容器不通外网的常见原因是宿主机本身网络不通、DNS配置异常、或者用了host以外的网络模式但宿主机转发没开。容器访问宿主机服务时,宿主机上要确保服务监听的是0.0.0.0而不是127.0.0.1——这坑特别隐蔽,容器通过网关IP访问宿主机的服务,如果服务只监听回环地址,连接必然被拒。容器之间访问,默认情况下不同容器各自有独立网络,对方IP你不知道也不稳定,最靠谱的做法是把它们放进同一个自定义网络。
一条命令创建自定义网络:
docker network create mynet在启动容器时加--network mynet,容器之间就可以直接用容器名互相访问。这一点在Compose文件里是自动的,但纯docker run手动跑容器时特别容易漏。查网络本身的状态,用docker network inspect 网络名看容器的IP分配和连通关系,里面的输出会给出很多线索。
6.2 端口映射没生效的常见原因
宿主机访问不到容器端口,第一反应查docker ps确认端口绑定列里是不是0.0.0.0:3306->3306/tcp。如果是127.0.0.1:3306->3306/tcp,说明只有本机能访问,外部机器连不上是预期行为。第二个常见原因是系统防火墙没有放行:sudo ufw status看看3306端口有没有被拦。第三个原因尤其容易被忽略——容器里服务监听的地址。很多应用默认监听127.0.0.1,比如Nginx容器里如果listen 127.0.0.1:80,端口映射做了也白搭,因为Docker会把外部流量送到容器内的所有网卡,但容器内进程只蹲在回环地址上。所以容器内启动服务时,监听地址务必是0.0.0.0。
6.3 “Permission denied”和启动失败的处理
权限问题几乎每个Linux用户都会遇到一次:安装完Docker,执行docker ps直接报permission denied while trying to connect to the docker daemon socket。原因很简单,Docker守护进程的socket文件默认属主是root用户和docker组,普通用户不在docker组里就没有权限访问。解决:
sudo usermod -aG docker $USER newgrp docker然后重新执行docker ps。注意newgrp docker只是把当前shell会话的组身份切过去,下次登录就自然拥有了权限。要是改完还报错,检查当前用户是不是真的在docker组里:groups命令输出里没有docker,那就重新登录一次。
至于“docker服务启动失败”,我的建议是不要在暗黑里瞎猜,直接看日志。systemd管理的系统执行sudo systemctl status docker看状态摘要,再执行sudo journalctl -u docker -n 50 --no-pager看最近的详细日志。最常见的启动失败原因无非几个:daemon.json语法错误,多写了一个逗号或者用了注释符号;/var/lib/docker目录所在的磁盘满了;网桥设备冲突。之前有个同事排查了一天,最后发现daemon.json里写了加速地址但地址包含多余空格,JSON解析失败,服务起不来。这种报错信息里其实都有提示,只是大部分人没耐心一行行读。
6.4 其他高频报错与我的修复顺序
我把自己压箱底的高频报错整理成了一张表,按出现频率排序,你可以直接照着对症状查:
| 报错现象 | 大概率原因 | 首选处理 |
|---|---|---|
docker: Error response from daemon: Conflict... | 同名容器已存在 | docker rm -f 容器名或者换一个名字 |
Error response from daemon: Get ... no basic auth credentials | 镜像仓库登录态过期 | 先执行仓库登录命令再拉镜像 |
failed to connect to the docker api at npipe | Docker引擎没起来 | 重启Docker Desktop,wsl --shutdown后重开WSL |
virtualization support not detected | WSL2/虚拟机平台组件缺失 | 启用Windows功能里的WSL和虚拟机平台,重启 |
Cannot connect to the Docker daemon at unix:///var/run/docker.sock | 服务未启动或权限不够 | systemctl start docker或检查用户组 |
no space left on device | docker目录所在分区满了 | docker system prune -af清理无用资源 |
docker: invalid reference format | 镜像名写法错误 | 检查镜像名是否多了空格、缺了仓库前缀 |
修复顺序上我有一条底线:先做影响面最小、可回退的操作,再往重里来。比如容器报错,先看日志,其次看配置,实在不行再删容器重建;一旦涉及-v挂载的数据目录,永远先确认备份或确认数据映射的宿主机目录还在,再动手删任何东西。很多人反而习惯删了容器重来,结果数据目录没挂出来,一删全没了,这种教训我是亲眼见过不少。
最后一个技巧,也许是最值得记住的:每一次“莫名其妙的报错”,最后都能在日志或者最基础的配置检查里找到答案,Docker的坑不是玄学,是文档阅读量不够加侥幸心理太强。我到现在排查问题还是那三板斧——看日志、看状态、看配置,但顺序不能乱。这份指南没有覆盖每个命令的每个参数,但把装、跑、包、排这几个环节的逻辑打通了,剩下的细节查文档就行。