1. 为什么“装Docker”这种简单事,偏偏天天有人翻车
Docker这个东西,凡是搞过部署、搞过开发环境的人应该都不陌生。很多人第一次接触它的原因特别朴素:在本地装上MySQL、Redis、Nacos、GitLab,再也不用忍受手动安装那一堆依赖和配置。但有意思的是,越是这种“先装个环境再说”的工具,越容易在第一道门槛上卡住。我经常看见有人在群里发报错截图,最高频的几类就是:Docker Desktop提示Virtualization support not detected、WSL2启动失败、装了Docker却找不到docker compose命令、镜像拉到一半就断流。这些问题的根源,几乎都不是Docker本身,而是宿主环境没有准备好。
所以要写这篇安装方案,我的思路不是丢给你两条命令就完事,而是把Windows和Linux两条路线分别拆开,讲清楚每一步为什么要这么做。顺带把装完之后的验证、镜像加速、权限配置、网络排查这些“后续动作”一并补齐。无论你是第一次装Docker的新手,还是已经在生产环境里折腾过的老手,这篇内容都能对应上你踩过或者将要踩的坑。
先说一个最重要的认知:Docker不是虚拟机。虚拟机是把整台机器虚拟化,里面跑一个完整的操作系统,资源开销非常大。Docker是共享宿主机内核,只隔离进程、文件系统、网络这些用户态的东西,所以启动一个容器几乎是毫秒级。但这个特性也带来一个硬性约束——它强依赖宿主机的内核特性,比如Linux的cgroups、namespaces,Windows上则依赖WSL2或者Hyper-V提供的虚拟化层。所以你会发现,Docker安装失败往往不是Docker本身出了问题,而是宿主机的CPU虚拟化没开、内核版本太老、WSL2没装好这类“环境病”。
在动手之前,你不妨先按下面这张表给自己定个位,避免走弯路:
| 你的系统 | 推荐方案 | 安装之前必须确认的条件 |
|---|---|---|
| Windows 10/11 | Docker Desktop + WSL2后端 | BIOS开启虚拟化,系统版本不低于Win10 2004,WSL2可用 |
| Ubuntu / Debian | 官方apt仓库 | 内核版本不低于3.10,能用systemd管理服务 |
| CentOS / RHEL | 官方yum仓库 | 内核建议3.10以上,老版本需考虑升级 |
| 已经跑在云服务器上的Linux | 官方仓库方式 | 确认发行版类型和CPU架构,避免装了不匹配的包 |
这张表其实就是我自己的选型逻辑。很多人一上来就问“Windows怎么装Docker”,其实Windows上最顺滑的路就是Docker Desktop配WSL2,不要去折腾老掉牙的Docker Toolbox;Linux上我也不推荐直接用一键脚本,虽然快,但出了问题不好排查,具体后面细说。
2. Windows安装路线:Docker Desktop与WSL2的那些纠缠
Windows系统装Docker,现在的标准答案就是Docker Desktop。但Docker Desktop本身只是个图形化管理器和CLI客户端,真正干活的引擎其实是跑在WSL2里的Linux虚拟机里。这个设计很多人不理解,为什么Docker Desktop非要绑定WSL2?答案很简单:Docker的容器技术天生是给Linux设计的,Windows原生并不支持直接跑Linux容器。WSL2提供了一个轻量级的真实Linux内核,Docker Desktop把引擎跑在里面,性能接近原生,文件IO也远好于一代WSL,你在Windows里敲docker ps,实际返回的是WSL2里那个Linux引擎的实时状态。
整个安装过程,我建议按下面的顺序走,每一步都有它的目的。
2.1 先把WSL2铺好,别急着装Docker Desktop
很多人的安装顺序是反的:先把Docker Desktop下载下来,安装完一启动,弹窗提示要启用WSL2或者虚拟化,然后才开始折腾底层。这个顺序浪费了不少时间。正确的顺序是先在Windows侧把WSL2准备到位。
以Windows 11为例,管理员身份打开PowerShell,执行:
wsl --install这条命令会自动安装WSL本身、VirtualMachinePlatform功能组件,并且默认安装一个Ubuntu发行版。装完后系统会提示重启。重启之后,再验证一下WSL是不是真的跑在2代上:
wsl -l -v输出结果会显示每个发行版的名称、状态和WSL版本,我记得如果WSL版本列显示的是1,说明还停留在老模式,需要手动升级:
wsl --set-version Ubuntu 2如果你不想在这个环节装任何Linux发行版也没关系,Docker Desktop在检测到WSL2存在但没发行版时,会自己创建一个专用的docker-desktop发行版来跑引擎。但个人建议还是装一个Ubuntu,因为后面你大概率会用到WSL里的Linux环境去处理容器内的问题,比如查日志、调试网络,有个自己熟悉的发行版会顺手很多。
这里有个特别常见的报错,就是热搜词里那条Virtualization support not detected。我在帮别人排查时发现,这个提示出现的原因大概有三层:第一层是BIOS里没开CPU虚拟化(Intel的VT-x或者AMD的SVM);第二层是Windows的虚拟机平台功能没启用;第三层是WSL2的核心组件没安装完整。排查路径也比较直接:
- 按下
Ctrl+Shift+Esc打开任务管理器,切到“性能”标签,看CPU那一栏有没有“虚拟化: 已启用”字样。 - 如果显示未启用,重启进BIOS,找到Intel Virtualization Technology或者AMD SVM Mode,设置为Enabled。
- 在“启用或关闭Windows功能”里,勾选“适用于Linux的Windows子系统”和“虚拟机平台”,重启后执行
wsl --set-default-version 2。 - 如果以上都做了还是不行,执行
wsl --update更新WSL内核,再跑一遍wsl -l -v确认状态正常。
2.2 安装Docker Desktop并切换到WSL2后端
WSL2就绪之后,去Docker官网下载Docker Desktop安装包,一路默认选项就行。唯一需要注意的是安装过程中弹出的“Use WSL 2 instead of Hyper-V”选项目前默认就是勾选的,保持默认即可。
安装完成打开Docker Desktop,在设置里找到Resources -> WSL Integration,这里会列出你机器上已有的WSL发行版,把Ubuntu那项打开。这一步的意义在于:开启集成之后,你在WSL的Ubuntu终端里直接敲docker命令,能直接连接到Docker Desktop管理的引擎,不需要在Windows和WSL之间来回切换上下文。
启动之后如果一切正常,托盘区的鲸鱼图标会变成绿色或者静止状态,打开终端执行:
docker version能看到Client和Server两个区块的版本信息,说明引擎已经跑起来了。如果Server部分是空的,说明Docker Desktop还没完全起来,等图标稳定了再试。
2.3 npipe连接失败的排查链路
有个搜索热词是failed to connect to the docker api at npipe:////./pipe/dockerDesktopLinuxEngine,这是Windows下最容易遇到的启动故障之一。它的意思很直白:Docker客户端尝试通过命名管道连接Docker引擎,但引擎没回应。
我遇到这个报错的经历挺有代表性。有一次是Windows系统更新之后,Docker Desktop服务和WSL2内核的版本对不上了,具体情况就是引擎起不来但托盘图标看着还在转。排查方案是这样的:重启Docker Desktop不行,重启WSL2还不行,最后是执行wsl --shutdown,确认WSL里所有发行版都停止后,再重新启动Docker Desktop才恢复。核心原因就是WSL2的某个实例残留了僵死状态,命名管道接口没有正常暴露出来。
如果上面这套重置操作做了还是报错,那就往更深一层排查:检查WSL发行版是否损坏。在PowerShell里执行wsl --unregister docker-desktop这类命令时要非常小心,这是删除Docker Desktop自己创建的WSL发行版,删了之后Docker Desktop会在下次启动时重新创建,不会影响你的用户数据,但如果你对这套机制还不熟,建议先把Docker Desktop完整关闭再操作,或者直接走“设置->疑难解答->Clear Docker Desktop data”的官方清理路径。
3. Linux安装路线:Ubuntu和CentOS的仓库玩法
Linux上装Docker,说实话比Windows顺多了,因为Docker本身就是从Linux生态长出来的。但也因为“太顺了”,很多人反而容易被网上那些一键脚本带偏。
3.1 为什么我坚持用官方apt仓库而不是curl脚本
Docker官方文档上给过一个快速安装方式,一句话命令:
curl -fsSL https://get.docker.com | bash这条命令确实省事,但我后来在几台服务器上用过之后,就不再推荐了。原因有三个:第一,脚本会从外网拉取二进制然后直接落到系统里,你很难判断它到底改了哪些文件、写了哪些配置,出了问题想卸载只能手动清理,非常麻烦;第二,脚本方式装的Docker不会自动注册到apt或者yum的软件源里,这意味着后续升级Docker版本时,你还是得重新执行脚本,无法用apt upgrade一键搞定;第三,在一些内网环境或者源被限速的场景下,脚本拉包的稳定性远不如配置好官方源之后走包管理器的增量下载。
所以我的标准做法是:添加官方软件源,然后用系统包管理器安装。这样装的Docker完全受包管理器管理,安装、升级、卸载都干干净净,排查依赖问题也容易。
3.2 Ubuntu全流程安装命令
以Ubuntu 22.04/24.04为例,整个过程分为“加源”和“装包”两个阶段。先把依赖和证书工具装上:
sudo apt update sudo apt install -y ca-certificates curl gnupg然后下载并安装Docker官方的GPG密钥,用来验证软件包签名:
sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc接着把Docker仓库写入apt源列表。这里有个细节:很多教程在写仓库地址时用的是$(lsb_release -cs)这个命令来获取系统代号,但如果你用的是某些基于Ubuntu的非官方发行版,或者系统的/etc/os-release里写的是自定义代号,就可能导致仓库地址解析错误。稳妥的做法是直接指定代号,比如22.04对应jammy,24.04对应noble:
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu jammy stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null更新索引并安装Docker引擎、CLI、容器运行时、Buildx插件以及Compose插件,一次装齐:
sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin装完先不要急着用,检查一下服务状态:
sudo systemctl status docker如果输出显示active (running),说明引擎已经起来了。再把开机自启打开:
sudo systemctl enable docker这里特别强调一点:一定要在安装命令里带上docker-compose-plugin。Docker从20.10版本开始把旧版的docker-compose独立二进制重构成CLI插件,命名也从docker-compose变成docker compose。如果你只装了docker-ce不带插件,执行docker compose version时会直接报错提示找不到命令,这个坑我在后文第4节还会专门展开。
3.3 CentOS和RHEL系列的安装差异
CentOS 7虽然比较老了,但在很多存量服务器上依然是主流。Docker官方对CentOS 7的支持方式是提供x86_64架构的rpm包源。安装步骤和Ubuntu类似,先把repo文件放到/etc/yum.repos.d/下:
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 docker-buildx-plugin docker-compose-plugin启动并设置开机自启:
sudo systemctl start docker sudo systemctl enable dockerCentOS 7的用户还有一个值得注意的问题:系统自带的yum源里Docker版本往往非常老,比如docker-io或者更早的docker-engine,这些老版本没有compose插件,也缺乏后面生态需要的特性。如果你之前用yum装过旧版Docker,建议先彻底卸载再装官方仓库版本,否则两套Docker的二进制和配置文件会打架。卸载命令要同时清掉旧包和数据目录:
sudo yum remove -y docker docker-common docker-selinux docker-engine如果你在CentOS 7上装完新版Docker之后发现docker compose依然不可用,先检查内核版本。CentOS 7默认的内核是3.10,跑新版Docker虽然能勉强工作,但容器网络、存储驱动这些方面容易出现兼容问题。热搜词里有一个是“centos7升级docker”,我理解很多人其实是被旧版本的客户端坑了,升级到官方源的新版docker-ce就能解决问题。
3.4 装完Linux版Docker之后的权限处理
刚在Linux服务器上装完Docker,第一个遇到的坑几乎都是这个:执行docker ps报权限错误,提示连接不上Docker守护进程的socket,或者干脆显示permission denied。
这背后的原理是:Docker的守护进程默认只监听在/var/run/docker.sock这个Unix socket上,而这个socket所属的组是docker。普通用户不在这个组里,自然没有权限和守护进程通信。解决办法不是用sudo去执行每条docker命令,而是把当前用户加入docker组:
sudo usermod -aG docker $USER执行完这条命令之后,必须重新登录终端或者重启会话让用户组变更生效。这里有个很多人没注意到的细节:如果你在SSH会话里操作,直接执行newgrp docker切换当前会话的组也很方便,不需要断开SSH重连。然后验证一下:
docker run --rm hello-world如果你看到Hello from Docker!的输出,说明权限和引擎都正常了。其实从架构角度来说,这个权限设计是合理的——能访问docker.socket就意味着能操作宿主机上的全部容器,相当于宿主机root权限,因为你可以把宿主机的任意目录挂载进容器再逃逸出来。所以加入docker组本质上等于授予了高权限,在多人共用的开发机上要谨慎管理docker组成员。安全要求高的话,更推荐的方式是配置Docker的TLS证书,让客户端通过HTTPS方式访问远程Docker API,而不是共享本地socket。
4. Docker Compose v2:它不是旧版那个“docker-compose”
Compose这个东西,熟悉Docker的人都知道,它解决的是“多个容器如何一键编排”的问题。以前定义一堆容器跑起来,得写好几行docker run,还要操心容器间的网络、挂载、依赖顺序,有了Compose文件之后,一个docker compose up -d就全搞定了。
但这里有个非常隐蔽的命令坑:无数人在新环境下敲docker-compose up -d,结果提示命令找不到,然后怀疑自己没装好。其实不是没装好,是Compose的形态变了。
4.1 独立二进制和CLI插件的区别
老一代的Compose是一个独立的Python二进制包,命令叫docker-compose,安装方式可以是pip install docker-compose,也可以是下载一个独立可执行文件放到/usr/local/bin下。那时候你得额外装Python依赖,版本还经常跟Docker引擎对不上,搞起来有点痛苦。
从Docker 20.10+开始,Compose被重构为Docker CLI的插件,命令变成了docker compose,注意中间没有横杠。它的安装方式也变了——不再独立运行,而是作为docker-compose-plugin这个包安装到Docker的插件目录里。Docker CLI在启动时会自动从插件目录加载docker-compose插件,所以当用户敲docker compose时,CLI发现这不是子命令,就去插件目录里找可执行文件,找到了就调用它。
这个变化的好处很明显:Compose和Docker CLI共用同一个版本管理和升级通道,你不用再单独维护一套Python环境或者手动下载二进制了,版本兼容性也好很多。坏处就是,如果你还在用旧的安装习惯,比如只装了docker引擎没装docker-compose-plugin,那敲docker compose就会得到一句冷冰冰的提示:
docker: unknown command: docker compose而这个报错,正好也是热搜词里出现频率很高的一条。它的本质就是:Docker CLI没找到对应的Compose插件,或者Docker版本太老(20.10之前),压根不支持插件机制。
4.2 怎么判断Compose插件装没装对
装完Docker之后,一定要跑一下这个验证命令:
docker compose version正常输出会包含类似Docker Compose version v2.32.4这样的版本信息。如果提示command not found或者unknown command,那就要按我前面说的,检查是不是漏装了docker-compose-plugin。
还有一种情况是,你确实装了,但装成了独立二进制的旧版Compose,那么docker compose version依然可能不识别。新旧两种格式的命令可以同时存在,但建议新环境只保留新的:
# 卸载旧版独立二进制式Compose sudo rm -f /usr/local/bin/docker-compose清理之后再验证一次。
4.3 老的compose文件还能不能用
很多人从旧版本迁移过来之前的项目时会有个疑问:以前写的docker-compose.yml现在还能不能直接用?答案基本可以,因为Compose文件的schema主体没有大变,最核心的services、volumes、networks这些定义都能沿用。但有几个细节值得注意。
第一,新版的Compose v2默认不再支持version: "3"这种顶层字段,你写上去的话它会给出一个警告,建议删除。这本身不影响运行,因为新Compose是自适应的,不靠version字段决定解析行为。
第二,depends_on的语义在新版里更聪明了。旧版只是控制服务启动顺序,新版在docker compose up时如果启用了--wait,会真正等待依赖服务的健康检查通过再启动下游服务,这是编排健壮性的明显提升。
第三,如果你以前的compose文件里写了docker-compose up加上-d的组合,新版本里完全等价。但有一些参数名称微调了,比如--no-recreate在新版本中可能需要用--no-recreate完整拼写,缩写行为不如旧版宽容,遇到参数不识别时先查版本差异。
4.4 在安装方案里为什么要把Compose一次装到位
我的观点是,现在这个时间节点,Docker和Compose已经强绑定了。不管你是“只部署一个小项目”还是“搭一套微服务测试环境”,Compose都是绕不开的。因为docker run命令虽然灵活,但每次创建容器都要手动指定端口映射、环境变量、挂载目录,命令一长就非常容易出错。把配置沉淀成compose.yml文件,至少有三个实打实的好处:一是可版本管理,二是不依赖记忆,三是环境可迁移,克隆一份compose文件就能在另一台机器上复现整套环境。
所以在这篇安装方案里,我把docker-compose-plugin直接放进了一开始的安装命令里,这是典型的“一次到位”思路,避免装完引擎再补刀。如果你已经按照前面Ubuntu那套命令走了,现在可以确认一下:
docker compose version有输出了,再看下面这个更实用的测试——随便建一个目录,写一个最简单的compose文件:
services: whoami: image: traefik/whoami:latest ports: - "8080:80"然后执行:
docker compose up -d docker compose ps curl localhost:8080能看到服务信息就说明Compose插件工作正常,这套组合拳已经能支撑你继续折腾后面任何复杂的编排文件了。
5. 装完先别急着拉镜像:验证、加速与配置
安装完成的标志不是肉眼看到“Docker Desktop图标变绿”或者“docker命令能敲了”,而是引擎真正能跑容器、镜像能正常拉取下来。这一步看着简单,但里面埋了不少配置层面的问题,最常见的两个就是镜像下载慢和日志文件无限增长。
5.1 hello-world只是最低标准
我见过很多人在服务器上跑完docker run hello-world之后,就觉得自己Docker装好了,然后开始拉MySQL、Redis,结果发现镜像源慢得离谱,一顿饭吃完还没拉完一个镜像。
docker run --rm hello-world这个镜像极小,它实际上只是验证引擎能创建容器、拉取镜像、执行二进制,并不代表你的网络和镜像源配置是好的。真正的安装验收,我建议是拉一个稍大一点的常用镜像,比如Nginx或者Redis:
docker pull nginx:alpine这个镜像体积小,又能覆盖镜像源、分层拉取、网络连通性这些关键链路。拉完之后顺手跑起来:
docker run -d -p 8080:80 --name test-nginx nginx:alpine curl localhost:8080能返回Nginx欢迎页,那才算安装验证真正通关。
5.2 镜像下载慢?资深的做法是配registry mirror
镜像源问题是国内用户绕不开的切肤之痛。Docker Hub在国外,直接从官方源拉取时间极长,优化方案就是配置镜像加速器,也就是registry mirror。原理不复杂:docker daemon在拉取镜像时,如果配置了mirror,会优先从mirror地址拉取,这个mirror通常是Docker Hub的只读缓存,能显著减少跨洲网络损耗。
配置方式在Linux和Windows上略有不同。Linux上直接编辑/etc/docker/daemon.json:
{ "registry-mirrors": [ "https://docker.m.daocloud.io", "https://dockerproxy.com", "https://docker.nju.edu.cn" ] }然后重启Docker服务:
sudo systemctl daemon-reload sudo systemctl restart dockerWindows的Docker Desktop则简单一些,在Settings -> Docker Engine里,直接编辑右下角的JSON配置框,填入同样的registry-mirrors字段,保存后Docker Desktop会自动应用并重启引擎。
用表格把几个目前还能用的公共mirror地址整理一下,你可以根据自己的网络环境尝试,国内不同运营商对不同的加速器体验差异还挺大的,没有绝对最优的,实测为准:
| 镜像加速地址 | 特点 | 适用场景 |
|---|---|---|
| https://docker.m.daocloud.io | 速度均衡,社区使用广泛 | 大多数家庭宽带和云服务器 |
| https://dockerproxy.com | 偶尔抽风,但高峰期尚可 | 备选方案之一 |
| https://docker.nju.edu.cn | 教育网优化,高校效果好 | 校园网、教育网络环境 |
| https://hub-mirror.c.163.com | 网易老牌镜像,稳定但更新偏慢 | 老项目拉取常用镜像 |
配置完成之后,怎么确认加速器真的生效了?拉一个镜像,然后在拉取日志里看一下输出地址是否包含了mirror的域名。如果输出还是从registry-1.docker.io下载,说明配置没生效,回到之前的步骤检查daemon.json是否放在了正确的路径、格式是否是合法的JSON。如果几个镜像地址都不通,也不要着急,可以过段时间再试,公共加速器偶发不可用是很正常的事情,最好的解法还是自建一个registry mirror,用Nginx反代Docker Hub的registry接口,限速和稳定性完全自主可控。不过这个话题展开又是一篇大文章,这里先不细说。
5.3 daemon.json里值得顺手配置好的几个参数
镜像加速只是daemon.json的基础功能。有过线上运维经验的人都知道,Docker默认配置里有个大坑:容器日志不限制大小。如果一个容器打印日志比较勤快,或者出现了异常刷日志,短短几天就能把磁盘写满。所以在配置daemon.json的时候,我会把日志文件的大小和数量一起限制好:
{ "log-driver": "json-file", "log-opts": { "max-size": "50m", "max-file": "3" } }这样每个容器最多保留3个日志文件,每个文件最大50MB,超过就轮转切割,磁盘安全得到了比较基础的保障。配置同样要重启Docker才生效,注意它只对新创建的容器生效,已经存在的容器需要重建才会应用新日志策略。
另一个值得在安装阶段就顺手做的事,是在/etc/docker/目录下维护好daemon.json的备份。因为docker的配置史越长,越容易出各种奇怪的合成问题,而daemon.json就是Docker引擎行为的总开关,不夸张地说,它决定了引擎的网络模式、存储驱动、镜像加速、日志策略、远程访问开关等一揽子行为。出问题时,直接恢复备份往往比花时间排查配置文件要高效得多。
5.4 小白的常用验证命令组
我不建议安装完成之后立刻进入“拉一大堆镜像跑起来”的状态,而是先花两分钟把这条命令链走一遍,确认每个环节都正常:
docker version # 看客户端和服务端版本是否都在线 docker info # 看存储驱动、镜像加速器、逻辑CPU等全局信息 docker run --rm hello-world # 验证基本容器创建能力 docker compose version # 验证Compose插件 docker ps -a # 确认没有异常残留的容器这套命令里,docker info的输出信息量最大,值得看一眼几个关键字段:Server Version、Storage Driver(一般是overlay2)、Cgroup Driver(新版本一般是systemd)、Registry Mirrors(如果配置了加速器,这里会列出来)。如果Cgroup Driver显示的是cgroupfs,且你的系统使用systemd管理服务,建议改成systemd,这能避免某些情况下Docker和systemd的cgroup资源管理发生冲突。
6. 装完就报错的常见坑:从API连接到网络不通的直接解法
到了这一步,大部分人的Docker环境已经能用了,但还有一批人会卡在各种千奇百怪的报错上。我把这些年看得最多的几类报错放在这里,每个都给到可以直接照做的排查链路。
6.1 Docker Desktop报npipe连接失败怎么办
前面在Windows小节已经讲了一段,这里补充一个更完整的排查路径。报错信息里出现的npipe:////./pipe/dockerDesktopLinuxEngine,本质上是Windows下Docker客户端和引擎之间的IPC通道。失败原因可能是引擎没起来、WSL2状态异常、或者命名管道服务被系统策略禁用。
按下列顺序做,成功率很高:
- 右键托盘鲸鱼图标,选择“Restart”,等待30秒再看
docker version。 - 若不行,PowerShell里执行
wsl --shutdown,等10秒重新打开Docker Desktop。 - 若还不行,关闭所有Docker相关进程(包括后台服务),然后执行
wsl --unregister docker-desktop重建Docker Desktop的WSL发行版。 - 最后的手段是在“设置->疑难解答->Clean / Purge data”里重置Docker Desktop,但这会清掉本地的所有镜像和容器,操作前确认没有需要保留的数据。
95%的情况下,前两步就能解决。如果你发现自己反复出现这个报错,多半是WSL2内核和Docker Desktop版本不匹配,执行wsl --update更新WSL内核,同时把Docker Desktop更新到最新版本,别让两个软件之间差太远。
6.2 我一敲docker compose就提示未知命令
在前面已经提过unknown command: docker compose的本质是Compose插件缺失。这里给一个完整的验证顺序:
docker version # 确认Docker CLI版本是否在20.10以上 docker compose version # 确认插件是否存在 ls /usr/libexec/docker/cli-plugins/ # 部分发行版插件放在这个目录 ls /usr/local/lib/docker/cli-plugins/ # 还有可能在这个目录如果你发现插件文件存在但命令还是提示未知,大概率是环境变量PATH里Docker插件目录没有被找到。可以在/etc/docker/daemon.json里显式指定CLI插件目录:
{ "cli-plugins-dir": "/usr/libexec/docker/cli-plugins" }重启shell之后再验证。但更常见的场景其实就是压根没装插件。不记得自己装没装过的话,直接执行:
sudo apt install -y docker-compose-plugin # 或者 sudo yum install -y docker-compose-plugin装完立刻验证,这个坑基本就填平了。
6.3 容器之间、容器和宿主机之间网络不通
“docker网络不通”这个热搜词,我怀疑不少人遇到的是同一个困惑:容器A能访问外网,但访问不了容器B;宿主机能docker ps,但访问不了某个映射了端口的服务。
这类问题的根源通常不是Docker装坏了,而是对网络模式的理解有偏差。Docker安装之后默认会创建一个bridge网络,所有用默认参数启动的容器都挂在这个网桥上,它们之间可以通过IP互访。但是容器重启之后IP会变,IP变了就可能导致你记录的访问地址失效。另外,如果分别用docker run -p 3306:3306和docker run -p 3307:3306启动两个MySQL容器,它们之间如果想要互相联调,走的是各自映射在宿主机上的端口,而不是容器内部的3306。
解法也很简单:自己创建一个自定义网络,然后把容器都放到这个网络下,Docker内置的DNS解析器会自动支持同一个自定义网络内的容器通过容器名互访:
docker network create app-net docker run -d --network app-net --name mysql8 mysql:8.0 docker run -d --network app-net --name redis redis:7 docker exec -it redis-container redis-cli -h mysql8 ping这样Redis容器里直接就能解析mysql8这个主机名,相当于把容器名变成了服务发现地址。在Compose文件里也是一样的逻辑,你定义的每个service名称,在自定义网络里天然就是可解析的主机名。
还有一个常见场景是容器能外网但宿主机访问不了容器映射的端口。这个要先查防火墙,Linux上记得放行映射端口,比如:
sudo ufw allow 8080/tcp如果你用的是云服务器,那还要检查云安全组是否放行了对应端口。端口映射本身没问题,但防火墙把流量拦住了,表现为外网访问超时,本地localhost访问正常。
6.4 我自己的“翻车排查五步法”
最后分享一下我处理Docker报错时用的固定套路,基本上能覆盖掉八成以上的问题。不管是什么报错,先按这个顺序走:
- 看状态:
docker ps -a、docker compose ps、systemctl status docker,确认是引擎问题还是容器问题。 - 看日志:
docker logs --tail 200 <container>,绝大多数容器问题都在日志里写得明明白白。 - 看端口:
ss -tlnp | grep <端口>,确认端口真的被监听了,再考虑防火墙和云安全组。 - 看资源:
free -h、df -h、docker system df,看看是不是内存、磁盘、镜像缓存耗尽了。日志爆盘、内存OOM导致容器被杀,都是运维里非常常见的事故。 - 重启降级:
docker compose restart或者docker restart,甚至极端情况下重启Docker守护进程,很多临时性的网络和文件句柄问题都能被这一招清掉。
这个套路没有什么高深的理论,但非常实用。排查问题最忌瞎试,按顺序确认每一步,基本都能定位到具体环节。这里顺带提醒一个非常冷门但常见的坑:某些Linux服务器上,Docker引擎启动之后docker ps命令能正常输出,但容器无法创建,报iptables相关错误。这往往是因为宿主机上的iptables规则被其他程序覆盖了,比如firewalld。此时可以把Docker的iptables操作能力关闭(在daemon.json里设置"iptables": false),但关闭之前要意识到这会影响端口映射和容器网络隔离,只适合在纯开发环境里这么干。生产环境还是要梳理好防火墙和Docker的共存关系。
装Docker这件事,说难不难,说简单也不简单。难点从来不在Docker本身,而在于你对宿主环境有没有足够的预判。我在实际部署中最大的体会是:安装方案的核心不是“敲几条命令”,而是“让引擎和宿主环境达成一致”。WSL2没配对、内核版本过老、Compose插件缺失、镜像源没配好、权限组没加入,任何一个环节没对上,后面都会以各种奇怪的形式反噬你。所以这篇安装方案里我特意把验证和排错放在了和安装同等重要的位置,在你准备把Docker塞进日常工具箱之前,先花十分钟把这些底子打好,之后整个世界都会清净很多。