疑難排解 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 預設會監聽一個通訊端。在使用 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 代理

注意

如果您在未於 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 終止器停止。為了防止這種情況發生,請確保您的應用程式在具有足夠記憶體的主機上執行,並參閱了解記憶體不足的風險

核心相容性

如果您的核心版本低於 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. 使用 Red Hat 文件手動設定 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 的容器,然後再次嘗試移除其他容器。

© . This site is unofficial and not affiliated with Kubernetes or Docker Inc.