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 實用程式檢查服務狀態。

最後,您可以使用 pstop 等命令在程序列表中檢查 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 以消除衝突。

注意

如果您看到關於 hosts 的特定錯誤訊息,請繼續閱讀下一節以獲取解決方法。

如果您使用作業系統的 init 指令碼啟動 Docker,您可能需要以特定於作業系統的方式覆蓋這些指令碼中的預設設定。

使用 systemd 配置守護程序主機

一個難以排查的配置衝突的顯著例子是,當您想指定一個不同於預設的守護程序地址時。Docker 預設監聽一個套接字。在 Debian 和 Ubuntu 系統中,使用 systemd 意味著在啟動 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 代理

注意

如果您覆蓋此選項而沒有在 daemon.json 中指定 hosts 條目,或在手動啟動 Docker 時使用 -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 killer 停止。為防止這種情況發生,請確保您的應用程式在具有足夠記憶體的主機上執行,並參閱瞭解記憶體不足的風險

核心相容性

如果您的核心版本低於 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 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
# OR
IPForward=true

此配置允許按預期從容器進行 IP 轉發。

DNS 解析器問題

DNS resolver found in resolv.conf and containers can't use it

Linux 桌面環境通常執行著一個網路管理器程式,該程式使用 dnsmasq 來快取 DNS 請求,方法是將其新增到 /etc/resolv.conf 中。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 伺服器。

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 覆蓋網路配置

在透過 cloud-init 使用 Netplan 的系統上,您可能需要應用自定義配置以防止 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 的容器,然後再次嘗試移除另一個容器。