由gemini生成,方便我快速解决


WSL2 开发指南:彻底解决 Docker Pull 和 Build 的网络代理问题

在 Windows Subsystem for Linux 2 (WSL2) 下使用 Docker 是目前非常流行的开发方式,它结合了 Windows 的易用性和 Linux 的完整工具链。

然而,在这个环境下,网络问题(特别是拉取镜像慢、构建镜像时 apt-get 卡死)是每个开发者都会遇到的“终极 BOSS”。

你可能尝试过在 .bashrc 里写 export HTTP_PROXY,发现 curl 通了,但 Docker 依然不动如山。这是为什么?本文将从原理出发,给出一套通用的、自动化的解决方案。

核心痛点:三个独立的世界

在解决问题前,必须明白为什么简单的 export 不起作用。在 WSL2 + Docker 的架构中,其实存在三个隔离的网络环境:

  1. Shell 环境(用户态):你敲命令行的终端。这里设置的 export HTTP_PROXY 只影响 curl, wget, pip 等直接运行的命令。
  2. Docker Daemon(守护进程):后台运行的 Systemd 服务。它负责执行 docker pull。它不读取你 Shell 的环境变量,只读取 Systemd 的服务配置。
  3. Docker Build 容器(构建态):当你执行 docker build 时,Docker 会启动一个个临时的容器来运行 RUN 指令(如 apt-get)。这些临时容器默认是封闭的,既不认 Shell 的变量,很多时候也不自动继承 Daemon 的代理。

要彻底解决问题,我们需要打通这三层。


准备工作:获取 Windows 主机 IP

WSL2 本质上是一个运行在 Hyper-V 里的虚拟机,它和 Windows 宿主机相当于在一个局域网里。

  1. 代理软件设置:确保你的 Windows 代理软件(Clash, v2ray, Karing 等)开启了 “允许局域网连接” (Allow LAN)
  2. 防火墙设置(关键坑点):Windows 防火墙可能会拦截来自 WSL2 的连接。

    • 测试方法:在 WSL 里 telnet <Windows_IP> <Proxy_Port>。如果不通,需要去 Windows 防火墙新建入站规则,允许你的代理软件端口通过。
  3. 获取 IP:WSL2 每次重启(或者 Windows 重启),宿主机 IP 都会变。我们可以通过 DNS 配置动态获取:

    # 在 WSL 中获取 Windows IP
    grep nameserver /etc/resolv.conf | awk '{print $2}'

场景一:解决 docker pull 拉取慢

docker pull 是由 Docker Daemon 执行的。我们需要修改 Systemd 的配置。

配置文件路径/etc/systemd/system/docker.service.d/http-proxy.conf

由于 IP 会变,手动写死 IP 是不可持续的。我们可以利用 Shell 脚本动态生成这个配置。

通用解决思路
创建一个启动脚本或手动配置,内容如下:

[Service]
Environment="HTTP_PROXY=http://192.168.x.x:PORT"
Environment="HTTPS_PROXY=http://192.168.x.x:PORT"
Environment="NO_PROXY=localhost,127.0.0.1,::1,registry.local"

配置完成后,必须执行:

sudo systemctl daemon-reload
sudo systemctl restart docker

此时,docker pull 就会起飞了。


场景二:解决 docker build 卡死

这是最容易让人崩溃的地方。你在 Dockerfile 里写 RUN apt-get update,结果进度条卡在 0% 不动。这是因为构建容器没有梯子。

方法 A:修改 ~/.docker/config.json (推荐)

这是 Docker 官方推荐的客户端配置方式。在此处配置后,Docker 客户端会自动将代理参数注入到 docker builddocker run 启动的容器中,无需修改 Dockerfile

编辑 ~/.docker/config.json,加入 proxies 字段:

{
 "proxies": {
   "default": {
     "httpProxy": "http://192.168.x.x:PORT",
     "httpsProxy": "http://192.168.x.x:PORT",
     "noProxy": "localhost,127.0.0.1,::1"
   }
 }
}

注意:这个配置即时生效,不需要重启 Docker 服务。

方法 B:使用 docker-composeargs

如果你不想修改全局配置,可以在 docker-compose.yml 中显式传递:

services:
  web:
    build:
      context: .
      args:
        - HTTP_PROXY=http://192.168.x.x:PORT
        - HTTPS_PROXY=http://192.168.x.x:PORT

这种方法的缺点是比较繁琐,且需要维护 IP。


终极方案:自动化脚本

鉴于 WSL2 的 IP 会变,我们可以写一个 set_proxy.sh 脚本,每次开发前运行一下(或者放在 .zshrc / .bashrc 里),自动把 Shell、Systemd 和 Docker Config 全都配置好。

自动化脚本示例 (set_docker_proxy.sh):

#!/bin/bash

# 1. 定义你的代理端口(根据实际情况修改)
PROXY_PORT=4067

# 2. 自动获取 Windows 宿主机 IP
HOST_IP=$(grep nameserver /etc/resolv.conf | awk '{print $2}')
PROXY_URL="http://${HOST_IP}:${PROXY_PORT}"

echo "Check Windows Host IP: $HOST_IP"
echo "Proxy URL: $PROXY_URL"

# =======================================
# 1. 设置当前 Shell 代理 (可选)
# =======================================
export HTTP_PROXY="$PROXY_URL"
export HTTPS_PROXY="$PROXY_URL"
export NO_PROXY="localhost,127.0.0.1,::1"

# =======================================
# 2. 配置 Docker 客户端 (解决 docker build)
# =======================================
# 确保目录存在
mkdir -p ~/.docker

# 使用 jq 工具生成或更新 config.json (需要先安装 jq: sudo apt install jq)
# 如果没有 jq,可以用简单的 cat > 覆盖,但要小心覆盖原有 auth 配置
if command -v jq &> /dev/null; then
    # 创建临时文件来处理 JSON
    tmp=$(mktemp)
    # 如果文件不存在,初始化空 JSON
    [ ! -f ~/.docker/config.json ] && echo "{}" > ~/.docker/config.json
    
    cat ~/.docker/config.json | jq --arg proxy "$PROXY_URL" \
    '.proxies.default.httpProxy = $proxy | 
     .proxies.default.httpsProxy = $proxy | 
     .proxies.default.noProxy = "localhost,127.0.0.1,::1"' \
    > "$tmp" && mv "$tmp" ~/.docker/config.json
    echo "✅ ~/.docker/config.json updated."
else
    echo "⚠️  Skipping config.json update (install 'jq' for auto-update)."
fi

# =======================================
# 3. 配置 Docker Daemon (解决 docker pull)
# =======================================
# 注意:这一步需要 sudo 权限,建议手动执行或根据需要开启
# sudo mkdir -p /etc/systemd/system/docker.service.d
# echo "[Service]
# Environment=\"HTTP_PROXY=$PROXY_URL\"
# Environment=\"HTTPS_PROXY=$PROXY_URL\"
# Environment=\"NO_PROXY=localhost,127.0.0.1,::1\"" | sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf > /dev/null

# echo "✅ Docker Daemon config updated. Please run: sudo systemctl daemon-reload && sudo systemctl restart docker"

总结

在 WSL2 下玩转 Docker,网络是第一道坎。

  1. docker pull 慢 -> 改 Systemd 配置 (/etc/systemd/system/docker.service.d/)。
  2. docker build 卡 -> 改客户端配置 (~/.docker/config.json)。
  3. IP 变动 -> 用脚本自动读取 /etc/resolv.conf
  4. Connection Refused -> 99% 是 Windows 防火墙或代理软件没开“允许局域网”。

希望这篇指南能帮你节省几个小时的排查时间!Happy Coding!

Last modification:December 13, 2025
如果觉得我的文章对你有用,请随意赞赏