排查 Docker 守护程序问题
本页介绍了如何排查和调试守护程序,以防你遇到问题。
你可以开启守护程序的调试功能,以了解守护程序的运行时活动,并帮助你排查问题。如果守护程序无响应,你也可以 强制将所有线程的完整堆栈跟踪记录到守护程序日志中,方法是向 Docker 守护程序发送 SIGUSR
信号。
守护进程
无法连接到 Docker 守护程序
Cannot connect to the Docker daemon. Is 'docker daemon' running on this host?
此错误可能表明
- Docker 守护程序未在你的系统上运行。启动守护程序并再次尝试运行命令。
- 你的 Docker 客户端正在尝试连接到不同主机上的 Docker 守护程序,而该主机不可达。
检查 Docker 是否正在运行
检查 Docker 是否正在运行的与操作系统无关的方法是使用 docker info
命令询问 Docker。
你也可以使用操作系统实用程序,例如 sudo systemctl is-active docker
或 sudo status docker
或 sudo service docker status
,或者使用 Windows 实用程序检查服务状态。
最后,你可以在进程列表中检查 dockerd
进程,使用 ps
或 top
等命令。
检查你的客户端连接到的主机
要查看你的客户端连接到的主机,请检查环境中的 DOCKER_HOST
变量的值。
$ env | grep DOCKER_HOST
如果此命令返回一个值,则 Docker 客户端设置为连接到运行在该主机上的 Docker 守护程序。如果未设置,则 Docker 客户端设置为连接到运行在本地主机上的 Docker 守护程序。如果错误地设置了它,请使用以下命令将其取消设置
$ unset DOCKER_HOST
你可能需要在 ~/.bashrc
或 ~/.profile
等文件中编辑你的环境,以防止错误地设置 DOCKER_HOST
变量。
如果 DOCKER_HOST
按照预期设置,请验证 Docker 守护程序是否在远程主机上运行,以及防火墙或网络故障是否阻止你连接。
排查 daemon.json
和启动脚本之间的冲突
如果你使用 daemon.json
文件,并且还手动或使用启动脚本向 dockerd
命令传递选项,并且这些选项冲突,则 Docker 无法启动,并显示错误,例如
unable to configure the Docker daemon with file /etc/docker/daemon.json:
the following directives are specified both as a flag and in the configuration
file: hosts: (from flag: [unix:///var/run/docker.sock], from file: [tcp://127.0.0.1:2376])
如果你看到类似于此的错误,并且你正在手动使用标志启动守护程序,则可能需要调整你的标志或 daemon.json
以消除冲突。
注意
如果你看到有关
hosts
的此特定错误消息,请继续到 下一节 以了解解决方法。
如果你使用操作系统的 init 脚本启动 Docker,则可能需要以特定于操作系统的方式覆盖这些脚本中的默认设置。
使用 systemd 配置守护程序主机
一个值得注意的配置冲突示例是,当你想指定与默认值不同的守护程序地址时,这很难排查。Docker 默认监听套接字。在使用 systemd
的 Debian 和 Ubuntu 系统上,这意味着在启动 dockerd
时始终使用主机标志 -H
。如果你在 daemon.json
中指定 hosts
条目,则会导致配置冲突,并导致 Docker 守护程序无法启动。
要解决此问题,请创建一个名为 /etc/systemd/system/docker.service.d/docker.conf
的新文件,内容如下,以删除启动守护程序时默认使用的 -H
参数。
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd
在其他情况下,你可能需要使用 Docker 配置 systemd
,例如 配置 HTTP 或 HTTPS 代理。
注意
如果你覆盖此选项,但未在
daemon.json
中指定hosts
条目,或者在手动启动 Docker 时未指定-H
标志,则 Docker 无法启动。
在尝试启动 Docker 之前,运行 sudo systemctl daemon-reload
。如果 Docker 成功启动,它现在将监听 daemon.json
的 hosts
密钥中指定的 IP 地址,而不是套接字。
重要
在 Docker Desktop for Windows 或 Docker Desktop for Mac 上不支持在
daemon.json
中设置hosts
。
内存不足问题
如果你的容器尝试使用超过系统可用内存的内存,你可能会遇到内存不足 (OOM) 异常,并且容器或 Docker 守护程序可能会被内核 OOM 杀手停止。要防止这种情况发生,请确保你的应用程序在具有足够内存的主机上运行,并参阅 了解内存不足的风险。
内核兼容性
如果你的内核版本低于 3.10,或者缺少内核模块,则 Docker 无法正常运行。要检查内核兼容性,你可以下载并运行 check-config.sh
脚本。
$ curl https://raw.githubusercontent.com/docker/docker/master/contrib/check-config.sh > check-config.sh
$ bash ./check-config.sh
该脚本仅适用于 Linux。
内核 cgroup 交换限制功能
在 Ubuntu 或 Debian 主机上,你可能会在使用镜像时看到类似于以下的消息。
WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.
如果你不需要这些功能,可以忽略警告。
你可以按照以下说明在 Ubuntu 或 Debian 上开启这些功能。即使 Docker 未运行,内存和交换空间统计也会产生大约 1% 的可用内存开销和 10% 的整体性能下降。
以具有
sudo
权限的用户身份登录 Ubuntu 或 Debian 主机。编辑
/etc/default/grub
文件。添加或编辑GRUB_CMDLINE_LINUX
行,以添加以下两个键值对GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"
保存并关闭文件。
更新 GRUB 启动加载程序。
$ sudo update-grub
如果你的 GRUB 配置文件语法错误,则会发生错误。在这种情况下,请重复步骤 2 和 3。
这些更改将在你重启系统后生效。
网络
IP 转发问题
如果你使用 systemd-network
手动配置网络,并且系统使用 systemd 版本 219 或更高版本,则 Docker 容器可能无法访问你的网络。从 systemd 版本 220 开始,给定网络的转发设置 (net.ipv4.conf.<interface>.forwarding
) 默认设置为关闭。此设置将阻止 IP 转发。它还会与 Docker 在容器中启用 net.ipv4.conf.all.forwarding
设置的行为冲突。
要在 RHEL、CentOS 或 Fedora 上解决此问题,请编辑 Docker 主机上 /usr/lib/systemd/network/
中的 <interface>.network
文件,例如 /usr/lib/systemd/network/80-container-host0.network
。
在 [Network]
部分中添加以下代码块。
[Network]
...
IPForward=kernel
# OR
IPForward=true
此配置允许按预期从容器中进行 IP 转发。
DNS 解析器问题
DNS resolver found in resolv.conf and containers can't use it
Linux 桌面环境通常会运行一个网络管理器程序,该程序使用 dnsmasq
通过将 DNS 请求添加到 /etc/resolv.conf
来缓存 DNS 请求。dnsmasq
实例运行在回环地址上,例如 127.0.0.1
或 127.0.1.1
。它可以加速 DNS 查询并提供 DHCP 服务。这种配置在 Docker 容器中不起作用。Docker 容器使用自己的网络命名空间,并将回环地址(如 127.0.0.1
)解析到自身,并且它不太可能在其自己的回环地址上运行 DNS 服务器。
如果 Docker 检测到 `/etc/resolv.conf
` 中引用的 DNS 服务器不是完全正常的 DNS 服务器,则会出现以下警告
WARNING: Local (127.0.0.1) DNS resolver found in resolv.conf and containers
can't use it. Using default external servers : [8.8.8.8 8.8.4.4]
如果看到此警告,首先检查是否使用 `dnsmasq`
$ ps aux | grep dnsmasq
如果你的容器需要解析网络内部的主机,则公共名称服务器不足。你有两种选择
为 Docker 指定要使用的 DNS 服务器。
关闭 `dnsmasq`。
关闭 `dnsmasq` 会将实际 DNS 命名服务器的 IP 地址添加到 `
/etc/resolv.conf
` 中,并且你会失去 `dnsmasq` 的优势。
你只需要使用其中一种方法。
为 Docker 指定 DNS 服务器
配置文件的默认位置为 `/etc/docker/daemon.json
`。你可以使用 `--config-file` 守护进程标志更改配置文件的位置。以下说明假设配置文件的位置为 `/etc/docker/daemon.json
`。
创建或编辑 Docker 守护进程配置文件,该文件默认为 `
/etc/docker/daemon.json
` 文件,它控制 Docker 守护进程配置。$ sudo nano /etc/docker/daemon.json
添加一个 `dns` 键,该键的值为一个或多个 DNS 服务器 IP 地址。
{ "dns": ["8.8.8.8", "8.8.4.4"] }
如果文件已有内容,你只需要添加或编辑 `dns` 行。如果你的内部 DNS 服务器无法解析公共 IP 地址,请至少包含一个可以解析公共 IP 地址的 DNS 服务器。这样做允许你连接到 Docker Hub,以及你的容器解析互联网域名。
保存并关闭文件。
重新启动 Docker 守护进程。
$ sudo service docker restart
通过尝试拉取镜像来验证 Docker 是否可以解析外部 IP 地址
$ docker pull hello-world
如果需要,请验证 Docker 容器是否可以解析内部主机名,方法是 ping 该主机名。
$ docker run --rm -it alpine ping -c4 <my_internal_host> PING google.com (192.168.1.2): 56 data bytes 64 bytes from 192.168.1.2: seq=0 ttl=41 time=7.597 ms 64 bytes from 192.168.1.2: seq=1 ttl=41 time=7.635 ms 64 bytes from 192.168.1.2: seq=2 ttl=41 time=7.660 ms 64 bytes from 192.168.1.2: seq=3 ttl=41 time=7.677 ms
关闭 dnsmasq
如果你不想更改 Docker 守护进程的配置以使用特定的 IP 地址,请按照以下说明在 NetworkManager 中关闭 `dnsmasq`。
编辑 `
/etc/NetworkManager/NetworkManager.conf
` 文件。通过在行首添加 `#` 字符来注释掉 `dns=dnsmasq` 行。
# dns=dnsmasq
保存并关闭文件。
重新启动 NetworkManager 和 Docker。或者,你可以重新启动你的系统。
$ sudo systemctl restart network-manager $ sudo systemctl restart docker
要在 RHEL、CentOS 或 Fedora 上关闭 `dnsmasq`
关闭 `dnsmasq` 服务
$ sudo systemctl stop dnsmasq $ sudo systemctl disable dnsmasq
使用 Red Hat 文档 手动配置 DNS 服务器。
卷
无法删除文件系统
Error: Unable to remove filesystem
一些基于容器的实用程序,如 Google cAdvisor,将 Docker 系统目录(如 `/var/lib/docker/
`)挂载到容器中。例如,`cadvisor` 的文档指示你按如下方式运行 `cadvisor` 容器
$ sudo docker run \
--volume=/:/rootfs:ro \
--volume=/var/run:/var/run:rw \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--publish=8080:8080 \
--detach=true \
--name=cadvisor \
google/cadvisor:latest
当你绑定挂载 `/var/lib/docker/
` 时,这实际上将所有其他正在运行的容器的所有资源作为文件系统挂载到挂载了 `/var/lib/docker/
` 的容器中。当你尝试删除这些容器中的任何一个时,删除尝试可能会失败,并出现类似以下的错误
Error: Unable to remove filesystem for
74bef250361c7817bee19349c93139621b272bc8f654ae112dd4eb9652af9515:
remove /var/lib/docker/containers/74bef250361c7817bee19349c93139621b272bc8f654ae112dd4eb9652af9515/shm:
Device or resource busy
如果绑定挂载了 `/var/lib/docker/
` 的容器对 `/var/lib/docker/
` 内的文件系统句柄使用 `statfs` 或 `fstatfs` 并且没有关闭它们,就会出现此问题。
通常,我们建议不要以这种方式绑定挂载 `/var/lib/docker
`。但是,`cAdvisor` 需要这种绑定挂载来实现核心功能。
如果你不确定哪个进程导致错误中提到的路径繁忙并阻止其删除,可以使用 `lsof` 命令查找其进程。例如,对于上面的错误
$ sudo lsof /var/lib/docker/containers/74bef250361c7817bee19349c93139621b272bc8f654ae112dd4eb9652af9515/shm
要解决此问题,请停止绑定挂载 `/var/lib/docker
` 的容器,然后再次尝试删除其他容器。