解決 Ubuntu 上 Docker 安裝與網絡問題的實踐筆記
在 Ubuntu(Noble 版本)上安裝 Docker 時,我遇到了兩個常見的網絡問題:apt-get update
失敗和無法拉取 Docker 鏡像。通過逐步排查和配置,最終成功運行 docker run hello-world
。這篇筆記整理了我的解決過程,重點講解了禁用 IPv6和為 Docker 守護進程配置代理的原理與操作,幫助讀者理解并復現。
問題背景
我按照 Docker 官方文檔的 Install using the apt repository 方法,在 Ubuntu 上安裝 Docker。使用的命令如下:
# 更新軟件源并安裝依賴
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings# 添加 Docker GPG 密鑰
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc# 添加 Docker 軟件源
echo \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update# 安裝 Docker
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
安裝過程順利,但運行測試命令時遇到問題:
sudo docker run hello-world
報錯如下:
Unable to find image 'hello-world:latest' locally
docker: Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
此外,最初運行 sudo apt-get update
時也遇到錯誤,提示無法連接 Docker 倉庫。
問題 1:apt-get update
失敗
現象
運行 sudo apt-get update
時,出現以下錯誤:
錯誤:1 https://download.docker.com/linux/ubuntu noble InReleaseCould not handshake: Error in the pull function. [IP: 2600:9000:2804:5800:3:db06:4200:93a1 443]
W: 無法下載 https://download.docker.com/linux/ubuntu/dists/noble/InRelease
原因分析
錯誤信息中的 IP 地址(2600:9000:...
)是一個 IPv6 地址,表明系統嘗試通過 IPv6 連接 Docker 倉庫,但失敗了。可能的原因包括:
- 網絡對 IPv6 支持不穩定:某些網絡環境(如國內部分運營商)對 IPv6 的支持不完善,導致連接超時或失敗。
- Docker 倉庫的 IPv6 配置問題:服務器可能優先返回 IPv6 地址,但實際連接不可靠。
解決方案:禁用 IPv6
為了強制系統使用 IPv4,我臨時禁用了 IPv6:
sudo sysctl -w net.ipv6.conf.all.disable_ipv6=1
sudo sysctl -w net.ipv6.conf.default.disable_ipv6=1
然后再次運行:
sudo apt-get update
這次更新成功,沒有報錯。
為什么禁用 IPv6?
- IPv6 vs IPv4:IPv6 是下一代互聯網協議,但許多網絡和服務器對 IPv6 的支持仍不完善。如果系統優先嘗試 IPv6 連接,而目標服務器的 IPv6 不可靠,就會導致超時或連接失敗。
- 命令解析:
sysctl -w net.ipv6.conf.all.disable_ipv6=1
:禁用所有網絡接口的 IPv6。sysctl -w net.ipv6.conf.default.disable_ipv6=1
:為新創建的網絡接口禁用 IPv6。- 這些命令通過修改內核參數(
/proc/sys/net/ipv6/conf/...
)臨時禁用 IPv6,重啟后會失效。
- 適用場景:如果你的網絡環境不支持 IPv6,或者目標服務器的 IPv6 連接不穩定,禁用 IPv6 是快速有效的解決方法。
注意事項
- 臨時性:上述命令僅在當前會話有效。如果需要永久禁用 IPv6,需編輯
/etc/sysctl.conf
:
添加:sudo nano /etc/sysctl.conf
保存后應用:net.ipv6.conf.all.disable_ipv6 = 1 net.ipv6.conf.default.disable_ipv6 = 1
sudo sysctl -p
- 風險:禁用 IPv6 可能影響依賴 IPv6 的服務,建議在確認網絡環境后使用。
問題 2:無法拉取 hello-world
鏡像
現象
安裝 Docker 后,運行 sudo docker run hello-world
報錯:
Unable to find image 'hello-world:latest' locally
docker: Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
原因分析
此錯誤表明 Docker 無法從 Docker Hub(registry-1.docker.io
)拉取鏡像,原因是連接超時。進一步排查發現:
- 我使用了代理(
http://127.0.0.1:7897
),通過以下命令驗證:
輸出顯示curl -v https://registry-1.docker.io/v2/
curl
通過代理成功連接(返回401 Unauthorized
,正常現象,因為需要認證)。 - 但是,Docker 守護進程(
dockerd
)并未使用代理,導致無法訪問 Docker Hub。
為什么需要為 Docker 守護進程配置代理?
- Docker 架構:Docker 采用客戶端-服務器架構。運行
docker run
時,客戶端(docker
命令)與守護進程(dockerd
)通信,守護進程負責拉取鏡像和運行容器。 - 環境變量隔離:用戶的代理環境變量(
HTTP_PROXY
、HTTPS_PROXY
)只對客戶端命令生效,守護進程默認不繼承這些設置。 - 網絡限制:在國內,Docker Hub 的訪問可能因網絡限制而失敗,代理或鏡像加速器是常見解決方案。
解決方案:為 Docker 守護進程配置代理
我通過以下步驟為 Docker 守護進程配置了代理:
-
創建代理配置文件:
sudo mkdir -p /etc/systemd/system/docker.service.d sudo nano /etc/systemd/system/docker.service.d/http-proxy.conf
添加以下內容:
[Service] Environment="HTTP_PROXY=http://127.0.0.1:7897" Environment="HTTPS_PROXY=http://127.0.0.1:7897" Environment="NO_PROXY=localhost,127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,172.29.0.0/16,::1"
- 解析:
HTTP_PROXY
和HTTPS_PROXY
:指定代理地址(127.0.0.1:7897
是本地代理服務地址)。NO_PROXY
:定義不需要代理的地址范圍(如本地地址和常見內網 IP 段),避免本地通信走代理。- 文件路徑
/etc/systemd/system/docker.service.d/
:Systemd 允許為服務添加自定義配置,http-proxy.conf
會覆蓋 Docker 的默認服務設置。
- 解析:
-
重新加載并重啟 Docker:
sudo systemctl daemon-reload sudo systemctl restart docker
daemon-reload
:通知 Systemd 重新加載配置文件。restart docker
:重啟 Docker 服務以應用新配置。
-
驗證服務狀態:
sudo systemctl status docker
確認服務狀態為
active (running)
。 -
測試拉取鏡像:
sudo docker run hello-world
這次命令成功運行,輸出:
Hello from Docker! This message shows that your installation appears to be working correctly. ...
理解代理配置
-
為什么單獨配置守護進程?
Docker 守護進程是一個獨立運行的后臺服務(通過 Systemd 管理),它不讀取用戶的 shell 環境變量(如export HTTPS_PROXY
)。因此,必須通過 Systemd 配置文件顯式設置代理。 -
NO_PROXY 的作用
NO_PROXY
防止本地通信(如守護進程與客戶端之間的通信)被代理攔截。例如,localhost
和127.0.0.1
是 Docker 客戶端與守護進程通信的常用地址,192.168.0.0/16
等內網地址常用于容器網絡。 -
適用場景
如果你的網絡環境需要代理訪問外部資源(如國內訪問 Docker Hub),或者企業網絡有代理要求,必須為守護進程配置代理。
最終結果
通過禁用 IPv6 和為 Docker 守護進程配置代理,我成功解決了網絡問題,docker run hello-world
正常運行。輸出表明 Docker 客戶端、守護進程和 Docker Hub 的通信都正常。
經驗總結與建議
-
禁用 IPv6 的場景:
- 當遇到類似
Could not handshake
的錯誤,且 IP 地址是 IPv6 時,禁用 IPv6 是快速排查方法。 - 注意檢查網絡環境,確認是否需要長期禁用 IPv6。
- 當遇到類似
-
代理配置的通用性:
- 如果使用代理,確保客戶端和守護進程都配置正確。
NO_PROXY
需根據網絡環境調整,包含所有本地和內網地址。
-
國內用戶優化:
- 考慮配置鏡像加速器(如阿里云、騰訊云)以提高拉取速度:
添加:sudo nano /etc/docker/daemon.json
重啟 Docker:{"registry-mirrors": ["https://mirror.ccs.tencentyun.com"] }
sudo systemctl restart docker
- 考慮配置鏡像加速器(如阿里云、騰訊云)以提高拉取速度:
-
權限優化:
- 為避免每次使用
sudo
,將用戶添加到docker
組:
注銷后重新登錄即可。sudo usermod -aG docker $USER
- 為避免每次使用
-
進一步學習:
- 嘗試運行復雜容器:
docker run -it ubuntu bash
。 - 探索 Docker Hub 和官方文檔:https://docs.docker.com/get-started/。
- 嘗試運行復雜容器:
結語
這次安裝 Docker 的過程讓我深入理解了網絡配置對 Docker 的影響。禁用 IPv6 解決了軟件源更新的問題,而為守護進程配置代理確保了鏡像拉取的成功。希望這篇筆記能幫助你在遇到類似問題時快速定位和解決,同時對 Docker 的網絡機制有更深的認識!
這篇博客簡潔明了,涵蓋了問題的現象、原因、解決方案以及背后的原理,適合初學者和有一定經驗的用戶參考。如果你有其他需求(例如添加圖片、代碼高亮,或調整語氣),請告訴我!