Docker Daemon 疑難排解

此頁面說明如何在遇到問題時對守護行程進行疑難排解和偵錯。

您可以開啟守護行程的偵錯功能,以了解守護行程的執行階段活動,並協助進行疑難排解。如果守護行程沒有回應,您也可以強制將所有執行緒的完整堆疊追蹤新增至守護行程紀錄,方法是將 `SIGUSR` 訊號傳送至 Docker 守護行程。

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` 以移除衝突。

**注意**

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

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

使用 systemd 設定守護行程主機

一個難以排除故障的配置衝突的典型例子是,當您想要指定與預設不同的守護行程地址時。Docker 預設會監聽一個 socket。在使用 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 代理

**注意**

如果您覆寫此選項,但在手動啟動 Docker 時未在 daemon.json 中指定 hosts 項目或 -H 旗標,Docker 將無法啟動。

在嘗試啟動 Docker 之前,請執行 sudo systemctl daemon-reload。如果 Docker 成功啟動,它現在會監聽 daemon.jsonhosts 鍵中指定的 IP 地址,而不是 socket。

重要

在 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 沒有運行也是如此。

  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 來快取 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. 使用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 覆寫網路設定

在使用Netplancloud-init取消管理 Docker 介面中的步驟建立網路管理員配置。

  • /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
  • 套用新的 Netplan 配置。

    $ sudo netplan apply
    
  • 重新啟動 Docker 守護行程

    $ sudo systemctl restart docker
    
  • 驗證 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 的容器,然後再次嘗試移除其他容器。