Skip to content

Commit cc9f724

Browse files
committed
docs(docker-management): 补充 WSL 网络代理诊断
1 parent 52cc81f commit cc9f724

6 files changed

Lines changed: 407 additions & 3 deletions

File tree

‎ai/skills/dev/docker-management/SKILL.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,16 @@ description: 管理 Docker 运行方案的选型、配置、迁移与日常运
2626
- 选型对比:读 `references/runtime-options.md`。
2727
- Windows 安装、方案 C 配置、Docker Desktop 迁移:读 `references/platforms/windows.md`。
2828
- WSL2 `.wslconfig` / `/etc/wsl.conf` 模板:读 `references/wsl2-config-templates.md`。
29+
- WSL2 mirrored / NAT 网络代理、Docker daemon 拉取代理排障:读 `references/wsl-network-proxy.md`。
2930
- 迁移策略、要不要备份、备份/恢复命令:读 `references/migration-strategy.md`。
3031
- 日常运维:读 `references/daily-ops.md`。
3132
- 命令与 compose 工作流:读 `references/commands.md`。
3233
- 故障排查:读 `references/troubleshooting.md`。
3334

35+
## 可复用脚本
36+
37+
- WSL2 Docker 代理诊断:优先运行 `scripts/Test-WslDockerProxy.ps1`,再根据输出决定是否修改 daemon proxy、代理软件监听或防火墙。
38+
3439
## 安全护栏
3540

3641
迁移、卸载 Docker Desktop、删除容器、清理卷、执行 `prune`、注销 WSL 发行版、覆盖 `.wslconfig` / `/etc/wsl.conf` 都是高风险操作。执行前先确认:

‎ai/skills/dev/docker-management/references/daily-ops.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ docker volume prune
113113

114114
代理分三层处理:当前 shell、Docker daemon 拉取镜像、新建容器运行环境。不要假设项目内存在代理脚本;直接写入对应层的标准配置。
115115

116+
Windows + WSL2 的 mirrored / NAT 代理地址选择、`host.docker.internal`、`/etc/resolv.conf` 和 `docker pull unexpected EOF` 排查见 `wsl-network-proxy.md`。
117+
116118
当前 shell 临时代理:
117119

118120
```bash
@@ -169,7 +171,7 @@ cat >~/.docker/config.json <<'EOF'
169171
EOF
170172
```
171173

172-
在 WSL mirrored 网络中,优先使用 `127.0.0.1:<port>` 或显式 `PROXY_DEFAULT_HOST/PORT`,不要再依赖解析 `/etc/resolv.conf` 的旧 NAT 主机 IP 方案。
174+
在 WSL mirrored 网络中,优先使用 `127.0.0.1:<port>` 或 `host.docker.internal:<port>`,不要写死局域网 IP。只有回退到 NAT 模式时,才使用 `/etc/resolv.conf` 的 `nameserver` 地址。
173175

174176
## 数据卷习惯
175177

‎ai/skills/dev/docker-management/references/platforms/windows.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ volumes:
132132
133133
### 5. 代理与端口策略
134134
135-
代理配置不要依赖某个项目里的脚本。需要代理时,直接按当前环境写入 shell 环境变量、Docker daemon systemd drop-in 或 Docker CLI 容器代理配置。
135+
代理配置不要依赖某个项目里的脚本。需要代理时,直接按当前环境写入 shell 环境变量、Docker daemon systemd drop-in 或 Docker CLI 容器代理配置。WSL2 mirrored / NAT 的代理地址选择和排障细节见 `../wsl-network-proxy.md`。
136136

137137
当前 shell 临时代理:
138138

@@ -174,7 +174,7 @@ cat >~/.docker/config.json <<'EOF'
174174
EOF
175175
```
176176

177-
WSL mirrored 网络中,优先使用 `127.0.0.1:<port>` 访问 Windows 侧代理。旧式解析 `/etc/resolv.conf` nameserver 的代理脚本只适合早期 NAT 模式,不再作为默认方案。
177+
WSL mirrored 网络中,优先使用 `127.0.0.1:<port>` 或 `host.docker.internal:<port>` 访问 Windows 侧代理。旧式解析 `/etc/resolv.conf` nameserver 的代理脚本只适合 NAT 模式,不再作为默认方案。
178178

179179
本机开发服务默认把端口绑定到 `127.0.0.1`:
180180

‎ai/skills/dev/docker-management/references/troubleshooting.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ systemctl show --property=Environment docker
5252
- 当前 shell 需要代理时执行 `proxy on`。
5353
- Docker daemon 拉取需要代理时执行 `proxy docker on`,该命令会重启 Docker。
5454
- 新建容器内部需要代理时执行 `proxy container on`。
55+
- Windows + WSL2 场景先按 `wsl-network-proxy.md` 区分 mirrored / NAT、shell 代理和 Docker daemon 代理。`curl -x ...` 能通不代表 `docker pull` 已经走代理。
5556

5657
## 端口无法访问或被占用
5758

@@ -141,3 +142,4 @@ autoProxy=true
141142
- 修改 `.wslconfig` 后必须 `wsl --shutdown`。
142143
- mirrored 模式对入站访问可能需要 Hyper-V 防火墙规则。
143144
- 只做本机开发时,不要为了局域网访问放宽防火墙;优先保持容器端口绑定到 `127.0.0.1`。
145+
- 代理问题优先测试 `127.0.0.1:<port>` 和 `host.docker.internal:<port>`;只有 NAT 模式才使用 `/etc/resolv.conf` 的 `nameserver` 地址。完整流程见 `wsl-network-proxy.md`。
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
# WSL2 网络与代理
2+
3+
## 目录
4+
5+
- [推荐判断](#推荐判断)
6+
- [Mirrored 模式](#mirrored-模式)
7+
- [NAT 模式](#nat-模式)
8+
- [Docker daemon 代理](#docker-daemon-代理)
9+
- [排查命令](#排查命令)
10+
- [常见结论](#常见结论)
11+
12+
## 推荐判断
13+
14+
优先使用新版 WSL 的 mirrored 网络;不能使用或行为异常时,再回退到 NAT 模式的 Windows 宿主机地址。
15+
16+
| 场景 | 代理地址优先级 | 说明 |
17+
|---|---|---|
18+
| mirrored 网络 | `127.0.0.1:<port>`,其次 `host.docker.internal:<port>` | 不写死局域网 IP;换 Wi-Fi、路由器或 VPN 时更稳 |
19+
| NAT 网络 | `/etc/resolv.conf` 里的 `nameserver:<port>` | 该地址通常是 WSL 访问 Windows 宿主机的网关 |
20+
| Docker daemon 拉取镜像 | 写 systemd drop-in,不只写 shell env | `docker pull` 由 dockerd 发起,不继承普通 shell 的临时代理 |
21+
| 容器内访问外网 | 写 `~/.docker/config.json` 或 compose `environment` | 只影响新建容器,不影响 daemon 拉镜像 |
22+
23+
Windows 代理软件必须真实监听 WSL 可达地址。若只监听 `127.0.0.1`,mirrored 下通常可用;NAT 下通常需要开启 `Allow LAN` / `允许局域网连接`,并确认 Windows 防火墙允许专用网络入站。
24+
25+
## Mirrored 模式
26+
27+
确认 WSL 版本和配置:
28+
29+
```powershell
30+
wsl --version
31+
wsl --status
32+
Get-Content "$env:USERPROFILE\.wslconfig"
33+
```
34+
35+
推荐 `.wslconfig` 关键项:
36+
37+
```ini
38+
[wsl2]
39+
networkingMode=mirrored
40+
dnsTunneling=true
41+
autoProxy=true
42+
firewall=true
43+
localhostForwarding=true
44+
```
45+
46+
修改后必须重启 WSL:
47+
48+
```powershell
49+
wsl --shutdown
50+
```
51+
52+
代理测试:
53+
54+
```bash
55+
curl -x http://127.0.0.1:7890 https://registry-1.docker.io/v2/ -I
56+
curl -x http://host.docker.internal:7890 https://registry-1.docker.io/v2/ -I
57+
```
58+
59+
`HTTP/2 401` 或 `401 Unauthorized` 是 Docker Registry 未带 token 时的正常探活结果,说明代理链路能访问 registry。
60+
61+
`autoProxy=true` 依赖 Windows 系统代理配置;代理软件开着但 Windows 系统代理关闭时,WSL 不一定会自动注入 `HTTP_PROXY` / `HTTPS_PROXY`。
62+
63+
## NAT 模式
64+
65+
传统 NAT 模式中,WSL 内的 `127.0.0.1` 是 WSL 自己,不是 Windows。通过 `/etc/resolv.conf` 获取 Windows 宿主机地址:
66+
67+
```bash
68+
WIN_HOST="$(awk '/nameserver/ {print $2; exit}' /etc/resolv.conf)"
69+
echo "$WIN_HOST"
70+
curl -x "http://${WIN_HOST}:7890" https://registry-1.docker.io/v2/ -I
71+
```
72+
73+
NAT 模式通常要求代理软件开启:
74+
75+
```yaml
76+
allow-lan: true
77+
bind-address: "*"
78+
mixed-port: 7890
79+
```
80+
81+
不同代理软件名称不同,重点是代理端口要监听 Windows 的非 loopback 地址,且防火墙允许 WSL 访问。
82+
83+
## Docker daemon 代理
84+
85+
当前 shell 的代理只影响当前进程:
86+
87+
```bash
88+
export http_proxy="http://127.0.0.1:7890"
89+
export https_proxy="$http_proxy"
90+
export HTTP_PROXY="$http_proxy"
91+
export HTTPS_PROXY="$http_proxy"
92+
```
93+
94+
Docker daemon 拉取镜像必须写 systemd drop-in:
95+
96+
```bash
97+
sudo mkdir -p /etc/systemd/system/docker.service.d
98+
sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf >/dev/null <<'EOF'
99+
[Service]
100+
Environment="HTTP_PROXY=http://127.0.0.1:7890"
101+
Environment="HTTPS_PROXY=http://127.0.0.1:7890"
102+
Environment="NO_PROXY=localhost,127.0.0.1,::1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,.ts.net,100.64.0.0/10"
103+
EOF
104+
sudo systemctl daemon-reload
105+
sudo systemctl restart docker
106+
```
107+
108+
验证 daemon 是否读到代理:
109+
110+
```bash
111+
systemctl show --property=Environment docker
112+
docker info | sed -n '/HTTP Proxy/,+4p'
113+
docker pull hello-world:latest
114+
```
115+
116+
若 mirrored 模式下 `127.0.0.1` 不通但 `host.docker.internal` 通,可以把 drop-in 中的代理地址改成 `http://host.docker.internal:<port>`。不要写死 `192.168.x.x`,除非只是临时排障。
117+
118+
新建容器默认代理写入 Docker CLI 配置:
119+
120+
```bash
121+
mkdir -p ~/.docker
122+
cat >~/.docker/config.json <<'EOF'
123+
{
124+
"proxies": {
125+
"default": {
126+
"httpProxy": "http://127.0.0.1:7890",
127+
"httpsProxy": "http://127.0.0.1:7890",
128+
"noProxy": "localhost,127.0.0.1,::1"
129+
}
130+
}
131+
}
132+
EOF
133+
```
134+
135+
这只影响之后创建的容器,不会修复 `docker pull`。
136+
137+
## 排查命令
138+
139+
优先使用 skill 自带脚本,避免 PowerShell 与 bash 嵌套引号导致误判:
140+
141+
```powershell
142+
.\scripts\Test-WslDockerProxy.ps1 -Distro Ubuntu -HttpPort 7890
143+
.\scripts\Test-WslDockerProxy.ps1 -Distro Ubuntu -HttpPort 7890 -TestDockerPull
144+
```
145+
146+
脚本默认只诊断,不修改配置。`-TestDockerPull` 会额外执行 `docker pull hello-world:latest` 和 `docker run --rm hello-world`。
147+
148+
Windows 侧检查代理监听地址:
149+
150+
```powershell
151+
Get-NetTCPConnection -LocalPort 7890 -ErrorAction SilentlyContinue |
152+
Select-Object LocalAddress,LocalPort,State,OwningProcess
153+
```
154+
155+
WSL 侧检查名称解析和端口:
156+
157+
```bash
158+
getent hosts host.docker.internal || true
159+
for hp in 127.0.0.1:7890 host.docker.internal:7890; do
160+
h="${hp%:*}"
161+
p="${hp##*:}"
162+
printf '%s ' "$hp"
163+
timeout 3 bash -lc "</dev/tcp/$h/$p" >/dev/null 2>&1 && echo ok || echo fail
164+
done
165+
```
166+
167+
区分 shell 代理和 daemon 代理:
168+
169+
```bash
170+
env | grep -i proxy
171+
systemctl show --property=Environment docker
172+
docker info | sed -n '/HTTP Proxy/,+4p'
173+
```
174+
175+
查看 Docker 拉取错误:
176+
177+
```bash
178+
docker --debug pull hello-world:latest
179+
journalctl -u docker --since '10 minutes ago' --no-pager -l
180+
```
181+
182+
## 常见结论
183+
184+
- `curl -x ... https://registry-1.docker.io/v2/` 能返回 401,只说明当前 shell 代理可用;`docker pull` 仍需要 daemon 代理。
185+
- `docker info` 显示了 HTTP Proxy,但仍出现 `unexpected EOF`,通常是代理软件、规则、TLS 中间链路或 Registry 规则问题;继续用 `journalctl -u docker` 和代理客户端日志定位。
186+
- mirrored 模式下可能出现 `localhostForwarding ignored` 提示,这是因为 mirrored 网络已有自己的 localhost 行为,不代表代理一定不可用。
187+
- `external-controller` 不是代理端口,不要把它写进 `HTTP_PROXY`。
188+
- 本机开发默认避免把数据库、Portainer 等服务暴露到局域网;端口绑定优先使用 `127.0.0.1:hostPort:containerPort`。

0 commit comments

Comments
 (0)