04-Docker 常见问题排查:守护进程、权限与镜像拉取
📝 笔记摘要: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?
这条报错在很多场景下出现,但根因至少有三个,消息本身不区分。得先分清是哪一种。
先看 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.socksocket 在不在、属组对不对
报 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限一下。
