解决 Ubuntu 上 Docker 安装与网络问题:从禁用 IPv6 到配置代理

解决 Ubuntu 上 Docker 安装与网络问题的实践笔记

在 Ubuntu(Noble 版本)上安装 Docker 时,我遇到了两个常见的网络问题:apt-get update 失败和无法拉取 Docker 镜像。通过逐步排查和配置,最终成功运行 docker run hello-world。这篇笔记整理了我的解决过程,重点讲解了禁用 IPv6为 Docker 守护进程配置代理的原理与操作,帮助读者理解并复现。


问题背景

我按照 Docker 官方文档的 Install using the apt repository 方法,在 Ubuntu 上安装 Docker。使用的命令如下:

bash 复制代码
# 更新软件源并安装依赖
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

安装过程顺利,但运行测试命令时遇到问题:

bash 复制代码
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 InRelease
  Could 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:

bash 复制代码
sudo sysctl -w net.ipv6.conf.all.disable_ipv6=1
sudo sysctl -w net.ipv6.conf.default.disable_ipv6=1

然后再次运行:

bash 复制代码
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

    bash 复制代码
    sudo nano /etc/sysctl.conf

    添加:

    复制代码
    net.ipv6.conf.all.disable_ipv6 = 1
    net.ipv6.conf.default.disable_ipv6 = 1

    保存后应用:

    bash 复制代码
    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),通过以下命令验证:

    bash 复制代码
    curl -v https://registry-1.docker.io/v2/

    输出显示 curl 通过代理成功连接(返回 401 Unauthorized,正常现象,因为需要认证)。

  • 但是,Docker 守护进程(dockerd)并未使用代理,导致无法访问 Docker Hub。

为什么需要为 Docker 守护进程配置代理?

  • Docker 架构 :Docker 采用客户端-服务器架构。运行 docker run 时,客户端(docker 命令)与守护进程(dockerd)通信,守护进程负责拉取镜像和运行容器。
  • 环境变量隔离 :用户的代理环境变量(HTTP_PROXYHTTPS_PROXY)只对客户端命令生效,守护进程默认不继承这些设置。
  • 网络限制:在国内,Docker Hub 的访问可能因网络限制而失败,代理或镜像加速器是常见解决方案。

解决方案:为 Docker 守护进程配置代理

我通过以下步骤为 Docker 守护进程配置了代理:

  1. 创建代理配置文件

    bash 复制代码
    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_PROXYHTTPS_PROXY:指定代理地址(127.0.0.1:7897 是本地代理服务地址)。
      • NO_PROXY:定义不需要代理的地址范围(如本地地址和常见内网 IP 段),避免本地通信走代理。
      • 文件路径 /etc/systemd/system/docker.service.d/:Systemd 允许为服务添加自定义配置,http-proxy.conf 会覆盖 Docker 的默认服务设置。
  2. 重新加载并重启 Docker

    bash 复制代码
    sudo systemctl daemon-reload
    sudo systemctl restart docker
    • daemon-reload:通知 Systemd 重新加载配置文件。
    • restart docker:重启 Docker 服务以应用新配置。
  3. 验证服务状态

    bash 复制代码
    sudo systemctl status docker

    确认服务状态为 active (running)

  4. 测试拉取镜像

    bash 复制代码
    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 防止本地通信(如守护进程与客户端之间的通信)被代理拦截。例如,localhost127.0.0.1 是 Docker 客户端与守护进程通信的常用地址,192.168.0.0/16 等内网地址常用于容器网络。

  • 适用场景

    如果你的网络环境需要代理访问外部资源(如国内访问 Docker Hub),或者企业网络有代理要求,必须为守护进程配置代理。


最终结果

通过禁用 IPv6 和为 Docker 守护进程配置代理,我成功解决了网络问题,docker run hello-world 正常运行。输出表明 Docker 客户端、守护进程和 Docker Hub 的通信都正常。


经验总结与建议

  1. 禁用 IPv6 的场景

    • 当遇到类似 Could not handshake 的错误,且 IP 地址是 IPv6 时,禁用 IPv6 是快速排查方法。
    • 注意检查网络环境,确认是否需要长期禁用 IPv6。
  2. 代理配置的通用性

    • 如果使用代理,确保客户端和守护进程都配置正确。
    • NO_PROXY 需根据网络环境调整,包含所有本地和内网地址。
  3. 国内用户优化

    • 考虑配置镜像加速器(如阿里云、腾讯云)以提高拉取速度:

      bash 复制代码
      sudo nano /etc/docker/daemon.json

      添加:

      json 复制代码
      {
        "registry-mirrors": ["https://mirror.ccs.tencentyun.com"]
      }

      重启 Docker:

      bash 复制代码
      sudo systemctl restart docker
  4. 权限优化

    • 为避免每次使用 sudo,将用户添加到 docker 组:

      bash 复制代码
      sudo usermod -aG docker $USER

      注销后重新登录即可。

  5. 进一步学习


结语

这次安装 Docker 的过程让我深入理解了网络配置对 Docker 的影响。禁用 IPv6 解决了软件源更新的问题,而为守护进程配置代理确保了镜像拉取的成功。希望这篇笔记能帮助你在遇到类似问题时快速定位和解决,同时对 Docker 的网络机制有更深的认识!


这篇博客简洁明了,涵盖了问题的现象、原因、解决方案以及背后的原理,适合初学者和有一定经验的用户参考。如果你有其他需求(例如添加图片、代码高亮,或调整语气),请告诉我!

相关推荐
IT成长日记2 小时前
【Docker基础】Docker数据卷管理:docker volume ls及其参数详解
运维·docker·容器·volume ls
偷萧逸苦茶3 小时前
docker常见命令
docker·容器·eureka
好奇的菜鸟12 小时前
如何在 Ubuntu 24.04 (Noble) 上使用阿里源
linux·运维·ubuntu
好奇的菜鸟14 小时前
如何在Ubuntu上检查MySQL是否启动并放开3306端口
mysql·ubuntu·adb
高山莫衣16 小时前
Docker Desktop导致存储空间不足时的解决方案
docker·容器·eureka
鹏大师运维16 小时前
在银河麒麟V10 SP1上手动安装与配置高版本Docker的完整指南
linux·运维·docker·容器·麒麟·统信uos·中科方德
lovely_nn16 小时前
docker 介绍
docker·k8s
Ahlson17 小时前
【fnNAS】docker的nginx配置html
nginx·docker·容器·fnnas
LuckyLay17 小时前
Compose 常用命令详解——AI教你学Docker
docker·容器·eureka
moppol17 小时前
容器化 vs 虚拟机:什么时候该用 Docker?什么时候必须用 VM?
运维·docker·容器