
开头先给结论在Ubuntu上想把系统里到底有几个Docker彻底搞清楚答案不是一条命令就能解决的。有人想知道装了几套Docker环境有人想知道跑着几个容器还有人其实是在排查为什么docker命令时好时坏。这篇文章就围绕这个话题从Docker自带命令、系统底层进程、服务与文件、再到多套Docker共存的复杂场景一层层垫高把家底摸清楚。无论你是刚在Ubuntu上装完Docker的新手还是正在折腾服务器环境的运维跟着这篇文章走一遍至少能少走很多弯路。1. 先搞清楚几个docker到底是在问什么1.1 Docker不是单个程序而是一整套体系刚开始接触Docker的人很容易被名字绕晕以为docker就是一条命令、一个软件。实际上Docker是一个典型的C/S架构系统简单拆开来看docker命令行客户端CLI就是你敲docker ps、docker run时用的那个工具它本身只负责发号施令。dockerd守护进程Daemon真正干活的角色负责管理镜像、容器、网络和存储。客户端发来的命令最终都由它执行。containerd运行时dockerd底层的容器生命周期管理器负责真正启动和停止容器进程。镜像与容器镜像是打包好的只读模板容器是镜像运行后的实例。你可能会拉取几十个镜像、启动多个容器。这个结构想说明什么当你问系统里有几个docker时严格来说你是在问有几个dockerd守护进程在运行或者有几个Docker环境配置而不是数一数命令行工具的个数。就像你家里装了微信手机上有一个App、电脑上还有一个客户端你能说有两个微信也可以说只是一个账号在两台设备上登录——关键取决于你站在哪个角度看。1.2 不同需求下的三种理解方式根据我接触到的实际情况几个docker大概对应三种截然不同的需求下面用表格拆开看问题类型真实需求最直接的排查方法想知道系统总共跑着多少容器、镜像资源盘点、磁盘占用排查docker ps、docker images、docker system df想知道是不是装了好几套Docker引擎环境混乱、客户端连不上引擎查dockerd进程数量、查socket文件、docker info想知道是不是装过多个来源的Docker包升级失败、残留服务冲突dpkg -l | grep docker、systemctl list-unit-files有一回我帮人看一台Ubuntu服务器他信誓旦旦说我明明启动过docker怎么又没了跑了一眼才发现他之前用apt装了docker.io后来按网上教程又装了docker-ce两个引擎的systemd服务还都启用了他以为自己在操作同一个Docker实际上命令走的是其中一个数据目录却是另一个的。这种情况在社区里太常见了所以先把概念理清再往下看具体命令才有意义。2. 用Docker自带命令快速摸底2.1 docker version先分清客户端和服务端如果你只想快速确认系统里有没有装Docker、装了能不能用我一般建议先执行docker version注意看输出它分成了两部分Client客户端和Server守护进程。如果Server部分能正常显示版本号说明当前这个客户端能成功连上一个引擎。如果只看到Client、Server下面报错通常是引擎没启动、socket文件权限不对或者DOCKER_HOST环境变量指错了地方。以前遇到过新手把docker version输出里的两串版本号当成系统里有两个docker的证据其实人家是同一套环境的前后台信息而已。真正判断引擎数量要看Server部分是否出现多套、或者后面我们要讲的进程和socket排查。2.2 docker info一条命令看全部家底docker version只是开胃菜真正把Docker家底一次性看清楚的命令是docker infodocker info输出里几个关键字段值得逐行看Containers当前引擎管理的容器总数包括各种状态的。Running正在运行的容器数量。Paused暂停状态的容器数量。Stopped已停止的容器数量。Images这个引擎里存放的镜像总数。Server Version引擎版本号多套引擎对比时特别有用。Storage Driver存储驱动类型Ubuntu上常见的是overlay2。Docker Root Dir数据存放目录默认通常是/var/lib/docker。如果你怀疑自己连着的是哪一套引擎先看Docker Root Dir。好几台机器我都靠这一项确认用户到底用的是snap包装的Docker还是传统apt装的Docker因为前者的数据目录在/var/snap/docker下面后者才是/var/lib/docker。2.3 数容器和镜像docker ps与docker images数系统里跑着几个容器标准答案是docker ps这个命令默认只显示正在运行的容器。想看包括已经退出的所有容器要加参数docker ps -a输出里有几列需要注意CONTAINER ID是容器的唯一编号IMAGE来自哪个镜像STATUS表示当前状态。Up 2 hours代表连续运行了两个小时Exited (0)表示容器正常退出Exited (137)往往是内存被杀掉的信号Paused表示暂停。至于镜像数量直接docker images这里会列出仓库名、标签、镜像ID、创建时间和大小。注意REPOSITORY显示为none、TAG也显示none的是悬空镜像通常是反复构建镜像旧版本留下的白白占磁盘后续可以用docker image prune清理。2.4 磁盘体检docker system df如果系统盘空间紧张想看看是不是Docker占了大头用这个docker system df它把镜像、容器、本地卷、构建缓存几个维度的占用都统计出来了。SIZE代表可回收大小RECLAIMABLE表示其中多少是可以清理的。这个命令配合docker system df -v还能看到每一个镜像和容器具体占了多大比单纯用du去翻数据目录高效得多。我有一次排查一台测试机df显示磁盘使用率95%就是靠这个命令定位到某同事反复构建镜像构建缓存吃掉了接近30G空间。一条docker builder prune -f清理下来世界清净了。3. 绕开Docker命令从系统层面查个底朝天3.1 进程视角ps查dockerd和containerdDocker命令偶尔会失灵比如socket文件被误删、引擎崩溃、甚至有人手动杀掉了dockerd进程。这时候再依赖docker info就查不出东西了必须绕到系统进程层面去看ps aux | grep -E dockerd|containerd正常一套引擎环境下你会看到类似这样的进程/usr/bin/dockerd或者/usr/bin/dockerd --hostfd:///usr/bin/containerd一堆containerd-shim开头的进程这些其实是每个容器对应的垫片进程。看到几行dockerd路径基本就能确定跑着几套引擎。比如同时出现/usr/bin/dockerd和/usr/bin/docker这两个可执行文件路径不一样要额外留意后面第四部分展开讲。还有个细节grep的时候注意别把grep自己算进去。稳妥一点的做法是ps -C dockerd -o pid,cmd ps -C containerd -o pid,cmd3.2 服务视角systemd里躺着几个docker相关服务Ubuntu上通过apt或snap安装的Docker都会注册systemd服务。查服务清单的通用命令是systemctl list-unit-files | grep -i docker常见的服务名有docker.service主引擎服务对应dockerd。docker.socketsocket激活服务很多发行版用这个来做按需启动。containerd.service容器运行时服务。docker-desktop.service装了Docker Desktop才会有。这里有个坑如果docker.service显示enabled但docker.socket也显示enabled两者同时开着并不代表两个Docker它们本来就是同一套体系的组成部分。真正需要警惕的是同时出现docker.service和snap.docker.dockerd.service那基本意味着你同时装过apt版本和snap版本两套东西都在系统里躺着。查看某个服务的具体状态systemctl status docker.service能看到进程ID、内存占用、以及最近几十条日志排查启动失败问题时非常有用。3.3 文件视角socket、二进制、数据目录不看命令行输出直接从文件系统上判断Docker的存在痕迹是排查问题的终极手段。最关键的文件是socket默认路径在/var/run/docker.sock。这个文件是客户端和守护进程通信的通道你可以理解成服务器上开的一扇门。查它ls -l /var/run/docker.sock正常情况下会看到srw-rw----之类的权限属主是root属组是docker。如果这个文件不存在说明引擎没起来或者被手动删了。再看二进制本身which docker ls -l /usr/bin/docker /usr/local/bin/docker 2/dev/null多装了几个来源的Docker很多时候就是/usr/bin/docker和/usr/local/bin/docker同时存在PATH环境变量决定你默认敲docker时执行的是哪一个。我见过有人的PATH里/usr/local/bin排在/usr/bin前面结果apt更新了Docker版本他却还在用老旧的二进制折腾半天才找到原因。数据目录也不能忽略du -sh /var/lib/docker如果这个目录不存在而/var/snap/docker存在那说明你用的是snap版。3.4 网络视角看监听端口Docker引擎默认监听Unix socket但如果配了远程访问会额外监听TCP端口。查一下ss -lntp | grep -E 2375|23762375是明文端口2376是加密端口。如果系统里同时监听多个IP的2375端口或者出现两个不同端口的监听加上前面几个视角的排查结果基本就能拼凑出系统里有几套Docker引擎了。这个视角很容易被忽略但真实环境中靠它抓到过不少幽灵引擎案例——比如有人为了远程调试手动把dockerd的监听端口改成了别的结果另外的服务也在监听同一端口Docker启动不了。4. Ubuntu上多套Docker的真实场景与排查4.1 docker.io与docker-ce的孽缘Ubuntu官方源里的包叫docker.ioDocker官方源里的包叫docker-ce。很多人跟着不同教程各装了一遍系统里就会出现两套可执行文件和服务。先看装了哪些包dpkg -l | grep docker如果同时出现docker.io和docker-ce、docker-ce-cli、containerd.io等那基本可以断定环境被折腾过。处理办法是选定一套保留另一套彻底移除。我个人推荐保留docker-ce因为它更新的频率更高功能更跟得上。移除时注意docker.io可能和docker-ce存在文件冲突直接apt purge报错的话先手动删掉冲突的二进制再重新安装你想要的那套。4.2 Docker Desktop介入后的局面Docker Desktop在Linux上越来越常见它和传统Docker Engine共存时局面就更微妙了。Docker Desktop有自己的一套引擎、自己的socket路径通常不再是/var/run/docker.sock那种直接可用的路径。很多新手装了Docker Desktop后再敲docker ps发现连不上其实是你的shell还在请求原来的socket而原来的引擎没启动。区分方法很简单ls -l /var/run/docker.sock systemctl status docker如果socket正常、服务正常但docker ps就是报错那就检查一下环境变量env | grep DOCKER_HOST4.3 snap包裹的Docker坑得最深Ubuntu对snap推广应用力度很大很多人图省事直接snap install docker这样装的Docker外壳和命令能用但数据目录在/var/snap/docker配置文件、日志路径都和apt版完全不同。最直观的坑是你按网上教程修改/etc/docker/daemon.json怎么改都不生效因为snap版根本不用这个路径。其次snap版自带docker compose以及其他插件但路径和传统版本有微妙差异导致脚本迁移时莫名其妙找不到命令。判断是否snap版snap list | grep docker在实际情况里我遇到过有人先装了snap版后来又装了apt版两条路径上的dockerd都被启用了真正是两个docker同时运行。排查方法就是前面说的ss看socket监听、ps看dockerd进程、systemctl看服务清单三步合起来铁证如山。4.4 用DOCKER_HOST切换引擎多套环境下环境变量DOCKER_HOST起着指路牌的作用。它的常见取值unix:///var/run/docker.sock连默认引擎。unix:///var/run/docker-desktop.sock连Docker Desktop的引擎具体路径以实际安装为准。tcp://ip:2375连远程引擎。所以说如果你的shell里设置了DOCKER_HOST指向A引擎即使系统里默认引擎是B你敲docker ps看到的也是A的容器列表。判断当前连着哪套用echo $DOCKER_HOST如果输出是空的说明走默认socket如果输出了明确路径那就要小心了。清理僵尸设置的办法是unset DOCKER_HOST排查服务器环境时我只要发现用户怎么都连不上docker第一件事就是看这个环境变量。很多所谓多套docker困惑最后都发现只是一个指路牌指错了地方。5. 实战排查三个常见场景的处理过程5.1 场景一docker命令报了command not found这个报错出现后不要急着重装系统。按顺序排查which docker # 看能不能找到可执行文件 ls -l /usr/bin/docker # 看二进制是否存在 apt list --installed | grep docker # 看apt包情况 snap list | grep docker # 看snap包情况如果是apt包已装但which docker为空十有八九是PATH配置问题。如果是snap包已装但不在PATH里重启一次终端或者重新登录会话就能解决。如果两边都没装那就踏踏实实选一条官方安装路线重装。重装时我强烈建议先清干净旧痕迹再装不然下一轮排查又开始循环。删除命令参考apt purge docker.io docker-ce docker-ce-cli containerd.io snap remove docker rm -rf /var/lib/docker /var/snap/docker注意删数据目录前想清楚这些目录里存着所有镜像、容器、卷删了不可恢复。5.2 场景二权限不足docker.sock被拒Ubuntu下新手最容易碰到这类报错permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock原因是/var/run/docker.sock属主是root普通用户默认没权限访问。正规做法是把当前用户加进docker组sudo usermod -aG docker $USER newgrp docker注意usermod之后需要重新登录一次会话才彻底生效否则当前终端还是旧权限。经常有人卡在这一步加完组发现还是无权限就直接去chmod 777 /var/run/docker.sock这是我最不推荐的做法会让任何用户都能操作Docker等于把服务器root钥匙发给了所有人。5.3 场景三设置过DOCKER_HOST导致连不上现象是docker ps报Cannot connect to the Docker daemon at tcp://xxx.xxx.xxx.xxx:2375. Is the docker daemon running?第一反应查环境变量echo $DOCKER_HOST如果输出是tcp://一串地址确认这个地址到底通不通curl telnet://xxx.xxx.xxx.xxx:2375或者直接清掉环境变量再试unset DOCKER_HOST多数情况下这个环境变量是之前某次远程调试残留的清掉之后立刻恢复正常。如果确实需要远程连另一台机器的Docker别用明文2375至少做一层TLS加密生产环境建议通过SSH隧道或者专门的远程管理方案来连。5.4 会不会真有两个docker同时在跑最后回扣主题怎么确认系统里到底有没有同时运行两份独立的Docker引擎我的判断清单是ps -C dockerd -o pid,cmd出现几行不同的dockerd启动命令。ss -lx | grep docker出现几个不同的docker socket。systemctl list-unit-files | grep docker出现几套互相独立的服务。docker info里Docker Root Dir指向不同路径。如果两条以上证据指向不同的引擎那就是真的多套共存。如果只有一个dockerd、一个socket、一个数据目录那不管你看网上教程多复杂你的系统其实就一套Docker只是可能同时装了多个客户端入口而已。举个我排查过的实例某台机器上docker ps能看到A项目容器但换了个用户登录后docker ps看到的是B项目容器两边数据完全对不上。查下来就是root用户的环境变量指向了一个snap引擎普通用户的shell没设环境变量走的是apt引擎两个跑的其实不是一套东西。理顺之后各用户统一指向同一套引擎问题直接消失。最后说点个人体会这个几个docker的问题看着简单背后其实是服务器排查的基本功永远不要只看一条命令的输出而是把进程、服务、socket、二进制、环境变量、数据目录全部串起来看。我这些年处理过不少类似案例九成以上最后都发现不是真的装了两套引擎而是用户视角错乱了。真正确认多套共存的情况往往出现在apt版、snap版、Docker Desktop三个来源混装的机器上。再分享一个我自己的习惯我会在~/.bashrc里放一个函数一行命令把Docker全景信息打出来dockerview() { echo CLI ; which docker; docker version --format {{.Client.Version}} 2/dev/null echo Daemon ; ps -C dockerd -o pid,cmd echo Sockets ; ss -lx | grep docker echo Services ; systemctl list-unit-files | grep -i docker echo Data Root ; docker info --format {{.DockerRootDir}} 2/dev/null echo DOCKER_HOST ; echo ${DOCKER_HOST:-unset} }以后谁再问我系统里有几个docker我就让他在终端敲一下这个几秒钟把底交得明明白白。你也试试习惯了之后会觉得排查环境问题从来不是难事难的是思路乱。