1
0
0

04-Docker 常见问题排查:守护进程、权限与镜像拉取

2026-10-22
2026-10-22

📝 笔记摘要:Docker 常见问题排查,守护进程、权限与镜像拉取

Docker 的报错有个特点:消息很短,但指向的问题完全不是字面意思。「Cannot connect to the Docker daemon」听着像 Docker 挂了,其实守护进程好好的,只是你连的不是一个地方。「permission denied」看着像权限不够,其实更可能是你根本没加进那个组。

这篇把最高频的几类问题按报错原文拆开,每一条都给到「怎么确认」和「怎么修」,而不是让你一条条试。

Docker 系列 共 4 篇,这是第 4 篇
  01-Docker 基础 安装、概念与容器操作
  02-Docker 镜像与数据卷 分层结构、挂载与 Dockerfile
  03-Docker 网络与 Compose 容器互访与多容器编排
  04-Docker 常见问题排查 守护进程、权限与镜像拉取 ← 本篇

1. 连不上守护进程

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

这条报错在很多场景下出现,但根因至少有三个,消息本身不区分。得先分清是哪一种。

Docker 调用链示意图:普通用户通过 docker CLI 向 /var/run/docker.sock 这个 Unix socket 发请求,socket 权限为 srw-rw---- root docker,守护进程 dockerd 以 root 运行;下方对比用户在 docker 组内能连上与不在组内被拒的两种结果

先看 socket 到底存不存在
  ls -l /var/run/docker.sock
  文件都没有 → 守护进程压根没起来
  文件在但连不上 → 路径不对
守护进程没起来的两种原因
  服务没启动 sudo systemctl start docker
  启动失败了 sudo systemctl status docker 看状态,journalctl -u docker -n 50 --no-pager 看日志
  最常见的是 daemon.json 写错了,JSON 少个逗号就起不来
  改完配置起不来,先把文件语法验一遍
  python3 -m json.tool /etc/docker/daemon.json
路径不对的两种情况
  环境变量指到了别处 echo $DOCKER_HOST 有输出就是它,改配置或者 unset 掉
  用的是 rootless 模式 socket 在 ~/.docker/run/docker.sock,不是 /var/run
  Windows / Mac 上的 Docker Desktop 路径又不一样
用 docker context 一次看清当前连的是哪
  docker context ls 列所有上下文
  docker context use default 切回默认
服务器重启过之后出现这个
  多半是忘了 systemctl enable docker,开机没自动拉起来
  sudo systemctl enable docker 补上,以后就不用管了

2. 权限不够:permission denied

Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock:
Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/version": dial unix /var/run/docker.sock: connect: permission denied

这条和上一条的区别很清楚:上一条是「找不到」,这一条是「找到了但不让你连」。守护进程在跑,socket 也在,就是你的用户没权限。

sudo gpasswd -a $USER docker
newgrp docker
docker ps

三条命令的作用分别是
  把用户加进 docker 组 gpasswd -a 用户名 组名,$USER 会自动填当前用户
  刷新当前 shell 的组信息 newgrp docker
  验证 docker ps 不再报错就是好了
忘了 newgrp 这步的现象是「命令还是报同样的错」
  很多人以为第一条命令没生效,其实它生效了,只是当前 shell 不知道
  重新登录一次也行
也可以用 usermod
  sudo usermod -aG docker $USER
  同样要重登或 newgrp 才生效
报错里那个 v1.24 说明你的客户端很老
  那是 Docker 19.03 时代的 API 版本,现在的客户端早就不报这个号了
  看到 v1.24 就说明该升级客户端了
不要用 chmod 666 这条路
  sudo chmod 666 /var/run/docker.sock 能临时糊过去
  但那是把整个 Docker 守护进程对全机开放,任何本地用户都能起特权容器
docker 组基本等于免 sudo
  组员能通过挂 socket 起特权容器把宿主机根目录挂进去,实际效果和拿到 root 差不多
  只把确实要用 Docker 的账号加进去
加完组还报错,检查 socket 的属组
  ls -l /var/run/docker.sock
  属组不是 docker 就是配错了,重新装一次服务会重建它

3. 镜像拉不下来

这一类的报错原文差别很大,分开看。

超时、TLS handshake timeout、EOF
  Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: TLS handshake timeout
  网络问题,走加速,配 registry-mirrors,见 Docker 基础 那篇
  先测连通性 curl -I https://registry-1.docker.io/v2/,卡住就是网络
manifest unknown
  manifest for openjdk:8 not found: manifest unknown
  这个标签真的不存在了,不是网络问题
  官方 openjdk 镜像已废弃,8 / 11 / 17 这些稳定标签全被移除,只剩 EA 预览版
  换 eclipse-temurin,见 Docker 镜像与数据卷 那篇
toomanyrequests
  Docker Hub 对匿名拉取有频率限制,同一个 IP 六小时内的次数是有限的
  配加速源能绕开,或者登录一个账号提高额度
no space left on device
  磁盘满了,跟第 5 节是一回事
标签写得对但还是拉不到
  注意镜像名的完整格式:仓库/镜像:标签
  Docker Hub 官方镜像要写 library/nginx,写 nginx 是简写形式
  临时拉一个镜像不想改配置,就在地址前面加加速域名
  docker pull docker.m.daocloud.io/library/nginx:alpine
  这台机器没 root 权限时也能这么用

4. 容器起来就退

容器跟着主进程走
  主进程一退出容器就停,这是设计
  命令跑完就结束 比如 CMD echo "hello"
  容器里没有常驻服务 拿 centos 当底子,退出 bash 容器就死
  服务自己崩了 端口冲突、配置缺失、连不上数据库
排查顺序
  docker ps -a        确认状态和退出码
  docker logs 容器名    看最后几行报错
  docker inspect 容器名  看 State.ExitCode 和 State.Error
退出码的含义
  0 正常结束(对容器来说这仍然是「退出」)
  1 命令自己报错退出
  137 被 SIGKILL 干掉,多半是内存超了被 OOM Killer 杀的
  139 段错误
  143 被 SIGTERM 终止,正常停止就是它
要它别停就加 --restart
  --restart=always 一直重启,Docker 守护进程起来也会拉
  --restart=unless-stopped 跟 always 差不多,但手动 stop 之后不自动拉起
真的需要一个长驻容器
  把命令改成不退出,比如 tail -f /dev/null,然后用 docker exec 进去干活

5. 磁盘被撑满

服务器磁盘告警,十有八九跟 Docker 有关。先看它占了多少:

docker system df
docker system df -v

占地方的三大块
  镜像 包括没在用的那些,docker images -a 能看到悬空镜像
  容器日志 不会自动清理,会一直涨
  卷 prune 不会删,得自己确认
日志是最容易被忽略的一块
  容器写 stdout / stderr,Docker 存成 json 文件在 /var/lib/docker/containers 下
  它不会自动轮转,跑上几个月的服务涨几十 G 是常事
  查某个容器的日志文件在哪:
  docker inspect --format '{{.LogPath}}' 容器名
在 daemon.json 里给日志加上限
  { "log-driver": "json-file", "log-opts": { "max-size": "100m", "max-file": "3" } }
  单个容器最大 300 MB,超了就轮转
  这个设置只对新建的容器生效,老容器要删掉重建才会带上
清理
  docker system prune     删停止的容器、悬空镜像、无用网络
  docker system prune -a   连没在用的镜像一起删
  docker volume prune    删没在用的卷,数据不可恢复
  执行前先 docker system df 看清楚能省多少
prune 不删具名卷
  数据库的数据在具名卷里,prune 不会碰
  要删得手动 docker volume rm,删之前先确认里面不是要留的数据
数据目录可以整体搬走
  Docker 支持改 data-root 到别的盘
  但必须停服务再搬,不能在线改

6. 排查顺序

遇到 Docker 不知道哪错了,按这个顺序走一遍,大部分问题到第三步就能定位。

第一步:看守护进程在不在
  systemctl status docker
  不在就 journalctl -u docker -n 50 --no-pager 看日志
  起不来八成是 daemon.json 语法错
第二步:看连接对不对
  docker context ls 当前上下文对不对
  ls -l /var/run/docker.sock socket 在不在、属组对不对
  报 permission denied 就是没进 docker 组
第三步:看网络
  docker info | grep -A 5 "Registry Mirrors" 加速配了没
  curl -I https://registry-1.docker.io/v2/ 出网通不通
第四步:看具体资源
  docker ps -a    容器状态和退出码
  docker logs 容器名 具体报错
  docker system df  磁盘还剩多少
第五步:查配置有没有被改过
  cat /etc/docker/daemon.json
  改配置这件事,最怕的是忘了改的是什么
  改之前先备份一份,出问题好回滚

💡 补充几个容易忽略的:
报错信息要读全
  同一个「连不上」后面跟的是不同的话,根因完全不同
  no such file or directory 是找不到,permission denied 是不让连
「服务端正常但客户端报错」要想到上下文
  docker context 这个东西很多人不知道
  它能解释「为什么 SSH 上去就不行了」这类问题——上下文可能指到别的机器上去了
Docker 守护进程挂了容器会一起受影响
  容器是托管在守护进程上的进程,守护进程一重启,容器全得靠 --restart 策略拉回来
  没配 restart 策略的,重启守护进程就等于容器全停
日志是排查的唯一线索来源
  容器出问题了先看日志,别急着重建
  重建一次,线索就全没了
镜像拉不动和镜像拉错了是两回事
  manifest unknown 是标签没了,加加速源没用
  多试几个官方镜像的老标签会浪费时间,去仓库页面看现在还剩哪些标签
别在生产机上用 docker system prune -a 手滑
  它会删掉「现在没容器在跑但你还想留」的镜像
  养成先 docker system df 的习惯
生产环境要配的 daemon.json 项
  log-opts 限日志大小
  registry-mirrors 加速拉取
  storage-driver: overlay2 明确指定存储驱动
  改完 daemon.json 一定 systemctl daemon-reload 再 restart
相关问题可以对照着看
  CentOS 7 防火墙 里提到 Docker 可能绕过 firewalld,端口通不通别只看防火墙
  Docker 基础 讲了守护进程和权限的正常状态应该是什么样
  Docker 镜像与数据卷 讲了镜像结构,磁盘占满了先看哪块那节有讲

🔥 一句话总结:「Cannot connect to the Docker daemon」和「permission denied」是两回事——前者先查守护进程起没起(daemon.json 语法错是头号原因)、再查 socket 路径和 docker context,后者是用户没进 docker 组,加完组一定要 newgrp docker 否则现象一样;docker 组基本等于免 sudo,别图省事 chmod 666;镜像拉不动先看报错原文,manifest unknown 是标签没了(openjdk:8 就是这么废的),超时才是网络问题;容器秒退先看 docker logs,退出码 137 是被 OOM 杀的;磁盘满的头号原因是容器日志不轮转,在 daemon.json 里加 log-opts 限一下。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或者给予支持!