Docker 守护进程故障排除
本页面介绍在遇到问题时,如何对守护进程进行故障排除和调试。
您可以开启守护进程的调试功能,以了解守护进程的运行时活动并辅助故障排除。如果守护进程无响应,您还可以通过向 Docker 守护进程发送 SIGUSR 信号,强制记录完整的堆栈跟踪(包括所有线程)到守护进程日志中。
守护进程 (Daemon)
无法连接到 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 实用程序中检查服务状态。
最后,您可以使用 ps 或 top 等命令在进程列表中检查 dockerd 进程。
检查客户端连接到的主机
要查看客户端连接到的主机,请检查环境变量 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 以消除冲突。
Note如果您看到关于
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 代理。
Note如果您覆盖此选项而未在
daemon.json中指定hosts条目,或在手动启动 Docker 时未指定-H标志,Docker 将无法启动。
在尝试启动 Docker 之前运行 sudo systemctl daemon-reload。如果 Docker 成功启动,它现在将监听 daemon.json 中 hosts 键指定的 IP 地址,而不是套接字。
Important在 Windows 版 Docker Desktop 或 Mac 版 Docker Desktop 中,不支持在
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 上开启这些能力。内存和交换记账会产生约总可用内存 1% 的开销,以及整体性能下降 10%,即使 Docker 未运行时也是如此。
-
以具有
sudo权限的用户身份登录到 Ubuntu 或 Debian 主机。 -
编辑
/etc/default/grub文件。添加或编辑GRUB_CMDLINE_LINUX行以添加以下两个键值对:GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"保存并关闭文件。
-
更新 GRUB 引导加载程序。
$ sudo update-grub如果您的 GRUB 配置文件语法不正确,会发生错误。在这种情况下,重复步骤 2 和 3。
更改将在您重新启动系统后生效。
网络 (Networking)
IP 转发问题
如果您使用 systemd 版本 219 或更高版本通过 systemd-network 手动配置网络,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
# 或
IPForward=true此配置允许按预期从容器进行 IP 转发。
DNS 解析器问题
DNS resolver found in resolv.conf and containers can't use it
Linux 桌面环境通常运行一个网络管理器程序,该程序使用 dnsmasq 通过将其添加到 /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 地址,请至少包含一个可以解析的 DNS 服务器。这样做可以让您连接到 Docker Hub,并让您的容器解析互联网域名。保存并关闭文件。
-
重启 Docker 守护进程。
$ sudo service docker restart -
通过尝试拉取镜像来验证 Docker 是否可以解析外部 IP 地址:
$ docker pull hello-world -
如有必要,通过 ping 内部主机名来验证 Docker 容器是否可以解析它。
$ 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 服务器。
Docker 网络消失
如果 Docker 网络(例如 docker0 网桥或自定义网络)随机消失或以其他方式显示为工作不正常,可能是因为另一个服务正在干扰或修改 Docker 接口。已知管理主机上网络接口的工具有时也会不适当地修改 Docker 接口。
请参阅以下部分,了解如何根据主机上存在的网络管理工具配置您的网络管理器以将 Docker 接口设置为非托管状态:
- 如果安装了
netscript,请考虑卸载它 - 配置网络管理器以将 Docker 接口视为非托管
- 如果您使用 Netplan,您可能需要应用自定义 Netplan 配置
卸载 netscript
如果您的系统上安装了 netscript,您可以通过卸载它来解决此问题。例如,在基于 Debian 的系统上:
$ sudo apt-get remove netscript-2.4
将 Docker 接口设为非托管
在某些情况下,网络管理器默认会尝试管理 Docker 接口。您可以通过编辑系统的网络配置设置,尝试明确将 Docker 网络标记为非托管。
如果您使用的是 NetworkManager,请在 /etc/network/interfaces 下编辑您的系统网络配置。
-
在
/etc/network/interfaces.d/20-docker0创建一个包含以下内容的文件:iface docker0 inet manual请注意,此示例配置仅将默认的
docker0网桥“非托管”,不包括自定义网络。 -
重启
NetworkManager以使配置更改生效。$ systemctl restart NetworkManager -
验证
docker0接口是否处于unmanaged状态。$ nmcli device
如果您在使用 systemd-networkd 作为网络守护进程的系统上运行 Docker,请通过在 /etc/systemd/network 下创建配置文件将 Docker 接口配置为非托管:
-
创建
/etc/systemd/network/docker.network,内容如下:# 确保 Docker 接口是非托管的 [Match] Name=docker0 br-* veth* [Link] Unmanaged=yes -
重新加载配置。
$ sudo systemctl restart systemd-networkd -
重启 Docker 守护进程。
$ sudo systemctl restart docker -
验证 Docker 接口是否处于
unmanaged状态。$ networkctl
防止 Netplan 覆盖网络配置
在使用 Netplan 通过 cloud-init 的系统上,您可能需要应用自定义配置以防止 netplan 覆盖网络管理器配置:
-
按照将 Docker 接口设为非托管中的步骤创建网络管理器配置。
-
在
/etc/netplan/50-cloud-init.yml下创建一个netplan配置文件。以下示例配置文件是一个起点。请根据您想要非托管的接口进行调整。不正确的配置可能导致网络连接问题。
/etc/netplan/50-cloud-init.ymlnetwork: ethernets: all: dhcp4: true dhcp6: true match: # 编辑此过滤器以匹配对您的系统有意义的任何内容 name: en* renderer: networkd version: 2 -
应用新的 Netplan 配置。
$ sudo netplan apply -
重启 Docker 守护进程:
$ sudo systemctl restart docker -
验证 Docker 接口是否处于
unmanaged状态。$ networkctl
卷 (Volumes)
无法删除文件系统
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 的容器,然后再次尝试删除其他容器。