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 dockersudo status dockersudo service docker status,或者使用Windows工具检查服务状态。

最后,您可以在进程列表中检查dockerd进程,使用像pstop这样的命令。

检查您的客户端正在连接到哪个主机

要查看您的客户端正在连接到哪个主机,请检查您环境中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的这个特定错误信息,请继续到 下一节 寻找解决方法。

如果您使用操作系统的初始化脚本启动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

还有其他时候你可能需要配置systemd与Docker一起使用,例如 配置HTTP或HTTPS代理

注意

如果您在手动启动Docker时覆盖此选项而未在daemon.json中指定hosts条目或使用-H标志,Docker将无法启动。

在尝试启动Docker之前,请运行sudo systemctl daemon-reload。如果Docker成功启动,它现在正在监听daemon.jsonhosts键指定的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上启用这些功能。内存和交换会计会导致总可用内存约1%的开销和整体性能下降10%,即使Docker没有运行。

  1. 以具有sudo权限的用户登录Ubuntu或Debian主机。

  2. 编辑/etc/default/grub文件。添加或编辑GRUB_CMDLINE_LINUX行,以添加以下两个键值对:

    GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"

    保存并关闭文件。

  3. 更新GRUB引导加载程序。

    $ sudo update-grub
    

    如果您的GRUB配置文件语法不正确,则会发生错误。在这种情况下,请重复步骤2和3。

    更改在您重启系统后生效。

网络

IP转发问题

如果您使用systemd-network手动配置网络,并且系统版本为219或更高,Docker容器可能无法访问您的网络。从systemd版本220开始,给定网络的转发设置(net.ipv4.conf..forwarding)默认关闭。此设置阻止IP转发。它还与Docker在容器内启用net.ipv4.conf.all.forwarding设置的行为冲突。

要在RHEL、CentOS或Fedora上解决此问题,请编辑Docker主机上的.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通过将它们添加到/etc/resolv.conf来缓存DNS请求。dnsmasq实例运行在回环地址上,例如127.0.0.1127.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

  1. 创建或编辑Docker守护进程配置文件,默认情况下是 /etc/docker/daemon.json 文件,该文件控制Docker守护进程 配置。

    $ sudo nano /etc/docker/daemon.json
    
  2. 添加一个dns键,其值为一个或多个DNS服务器IP地址。

    {
      "dns": ["8.8.8.8", "8.8.4.4"]
    }

    如果文件已有内容,您只需添加或编辑dns行。如果您的内部DNS服务器无法解析公共IP地址,请至少包含一个能够解析的DNS服务器。这样做可以让您连接到Docker Hub,并让您的容器解析互联网域名。

    保存并关闭文件。

  3. 重新启动Docker守护进程。

    $ sudo service docker restart
    
  4. 通过尝试拉取一个镜像来验证Docker是否可以解析外部IP地址:

    $ docker pull hello-world
    
  5. 如有必要,通过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

  1. 编辑 /etc/NetworkManager/NetworkManager.conf 文件。

  2. 通过在该行开头添加#字符来注释掉dns=dnsmasq行。

    # dns=dnsmasq

    保存并关闭文件。

  3. 重新启动NetworkManager和Docker。或者,您可以重新启动系统。

    $ sudo systemctl restart network-manager
    $ sudo systemctl restart docker
    

要在RHEL、CentOS或Fedora上关闭dnsmasq

  1. 关闭dnsmasq服务:

    $ sudo systemctl stop dnsmasq
    $ sudo systemctl disable dnsmasq
    
  2. 手动配置DNS服务器,使用 Red Hat文档


Docker 网络消失

如果Docker网络,例如docker0桥接或自定义网络,随机消失或以其他方式出现工作不正常,可能是因为另一个服务正在干扰或修改Docker接口。已知管理主机上网络接口的工具有时也会不适当地修改Docker接口。

请参考以下部分,了解如何根据主机上存在的网络管理工具配置网络管理器,将Docker接口设置为未管理状态:

卸载 netscript

如果您的系统上安装了netscript,您可以通过卸载它来解决这个问题。例如,在基于Debian的系统上:

$ sudo apt-get remove netscript-2.4

取消管理 Docker 接口

在某些情况下,网络管理器会默认尝试管理Docker接口。您可以通过编辑系统的网络配置设置,明确将Docker网络标记为不受管理。


如果你正在使用NetworkManager,请在/etc/network/interfaces下编辑你的系统网络配置。

  1. /etc/network/interfaces.d/20-docker0创建一个文件,内容如下:

    iface docker0 inet manual

    请注意,此示例配置仅“取消管理”默认的 docker0 桥接,不包括自定义网络。

  2. 重启NetworkManager以使配置更改生效。

    $ systemctl restart NetworkManager
    
  3. 验证 docker0 接口是否处于 unmanaged 状态。

    $ nmcli device
    

如果您在使用systemd-networkd作为网络守护进程的系统上运行Docker,请通过在/etc/systemd/network下创建配置文件来将Docker接口配置为未管理状态:

  1. 创建 /etc/systemd/network/docker.network 文件,内容如下:

    # Ensure that the Docker interfaces are un-managed
    
    [Match]
    Name=docker0 br-* veth*
    
    [Link]
    Unmanaged=yes
  2. 重新加载配置。

    $ sudo systemctl restart systemd-networkd
    
  3. 重新启动Docker守护进程。

    $ sudo systemctl restart docker
    
  4. 验证Docker接口是否处于unmanaged状态。

    $ networkctl
    

防止Netplan覆盖网络配置

在使用Netplan通过cloud-init的系统上,您可能需要应用自定义配置以防止netplan覆盖网络管理器配置:

  1. 按照 取消管理 Docker 接口 中的步骤创建网络管理器配置。

  2. /etc/netplan/50-cloud-init.yml下创建一个netplan配置文件。

    以下示例配置文件是一个起点。 根据您想要取消管理的接口进行调整。 不正确的配置可能导致网络连接问题。

    /etc/netplan/50-cloud-init.yml
    network:
      ethernets:
        all:
          dhcp4: true
          dhcp6: true
          match:
            # edit this filter to match whatever makes sense for your system
            name: en*
      renderer: networkd
      version: 2
  3. 应用新的Netplan配置。

    $ sudo netplan apply
    
  4. 重新启动Docker守护进程:

    $ sudo systemctl restart docker
    
  5. 验证Docker接口是否处于unmanaged状态。

    $ networkctl
    

无法移除文件系统

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/内的文件系统句柄上使用statfsfstatfs并且没有关闭它们,就会出现这个问题。

通常,我们会建议不要以这种方式绑定挂载 /var/lib/docker。 然而,cAdvisor 需要这种绑定挂载来实现核心功能。

如果不确定是哪个进程导致错误中提到的路径繁忙并阻止其被删除,可以使用lsof命令来查找其进程。例如,对于上述错误:

$ sudo lsof /var/lib/docker/containers/74bef250361c7817bee19349c93139621b272bc8f654ae112dd4eb9652af9515/shm

要解决这个问题,停止绑定挂载/var/lib/docker的容器,然后再次尝试删除其他容器。