如何代理 Docker 官方镜像的流量
坑边闲话:现代软件的开发、测试、部署基本离不开容器技术,然而大陆地区的防火墙屏蔽了 Docker 官方的 Registry,这无疑给普通开发者带来了很大的负担和痛苦。本文介绍一般场景下绕过防火墙的阻断的方法,帮助开发者较快地访问官方 Docker 镜像平台。
1. 使用 OpenClash 规则集·
作为一个成熟的程序员,应该学会使用 Clash 等代理工具,毕竟良好的技术网站访问体验是增进技术的重要支撑。笔者选择使用 OpenClash 这款 OpenWrt 插件作为主代理工具,用以给局域网中的所有设备提供透明代理服务。
如图 1 所示,在 OpenWrt 的「服务」→「OpenClash」→「覆写设置」→「规则设置」页面,勾选「自定义规则」,随后将如下内容按照图示添加进去。
1 | - DOMAIN-SUFFIX,docker.com,🔰国外流量 |
提醒:请查阅你 Clash 配置文件中的国外分流规则的名字,用以替换示例中的「🔰国外流量」。
重启 OpenClash 后,以 docker.com
、docker.io
为后缀的域名皆可被 OpenClash 代理。
2. 解决 IPv6 问题·
Docker Hub 镜像仓库支持双栈访问,如果你的机器支持 IPv6 上网,那么大多数情况下系统会自动解析出 Docker Hub 的 IPv6 地址并优先尝试建立 IPv6 连接。然而 Docker Hub 的 IPv6 地址同 IPv4 地址一样也被屏蔽了,而绝大多数代理节点均不支持 IPv6 代理,此时必然会出现建立连接失败的问题。那么该如何处理呢?方法有两种:
- 关闭本地机器的 IPv6 功能。这个代价太大,有些得不偿失的味道。
- 在本地的 DNS 服务器上做修改,当本机发起
docker.com
、docker.io
相关的解析时,本地 DNS 服务器只返回 IPv4 地址,自动丢弃 IPv6 解析结果。
这里我们选择后者。笔者选择使用 AdguardHome 作为本地的 DNS 解析服务器。可在 /etc/adguardhome.yaml
中做如下配置:
1 | dns: |
其中的 answer: A
指的是只返回 A 记录,丢弃 AAAA 记录,重启 AdguradHome 即可生效。
随后,将本地的 systemd-resolved
配置文件作如下修改:
1 | sudo vim /etc/systemd/resolved.conf |
1 | DNS=${YOUR_ADGUARDHOME_ADDR} |
随后重启 systemd-resolved
服务:
1 | sudo systemctl restart systemd-resolved.service |
在单网口并开启 IPv6 的场景下,该问题至此应该就迎刃而解了。
3. 解决多网口 DNS 解析问题·
3.1 查看接口的 DNS 解析配置·
在某些特殊场景下,服务器可能接入了多个网络。比如在实验室环境下,笔者的服务器会同时接入内网和校园网,而这两个网络均可以访问互联网。此时就又出现麻烦了。尽管默认网关是单一的或有不同的优先级,但 Linux 一般会默认从两个网口的 DHCP DNS 服务器下发内容中读取信息,并配置本地的 DNS 解析请求策略。
使用如下命令列出 NetworkManager 的连接项:
1 | sudo nmcli connection show |
单网口输出应该类似:
1 | NAME UUID TYPE DEVICE |
其中 NAME
列是 NetworkManager 的连接项名称。
而在校园网双线接入情况下,一般会多出一个 ethernet
连接项,如下所示
1 | NAME UUID TYPE DEVICE |
由于 Linux 也会生成非默认出口接口上的 DNS 解析服务器,如执行下列命令进行 DNS 服务查询:
1 | sudo resolvectl status |
可以发现校园网接口上也出现了 DNS 服务器配置:
1 | Link 9 (eth1) |
我们执行 resolvectl
命令查看 DNS 查询的细节。注意不要使用 nslookup
,因为它会走系统接口,导致我们看不到系统具体的查询细节。
1 | resolvectl query registry.hub.docker.com |
输出结果如下:
1 | registry.hub.docker.com: 157.240.9.36 -- link: eth0 |
果然,Docker Hub 的 IPv6 地址 2001::caa0:8028
是解析自 Ethernet_UCAS
,即网卡 eth1
. 由此断定,IPv6 的 Docker Hub 地址就是校园网解析出来的!罪魁祸首竟然是你!
3.2 调整不同接口 DNS 配置优先级·
原则上 DNS 服务器是系统层级的配置,而非 interface 层级的配置。然而诡异的是 Linux 确实会进行多网口同时查询 DNS. 为此,我们使用下面的命令将校园网接口的自动 DNS 优先级调低.
1 | sudo nmcli connection modify Ethernet_LAN ipv4.dns-priority -50 |
该命令与直接编辑 NetworkManager connection 配置文件等价。手动编辑其中之一的过程如下:
1 | sudo vim /etc/NetworkManager/system-connections/Ethernet_UCAS.nmconnection |
编辑后内容如下,特别注意 dns-priority
字段,
1 | [connection] |
另一个网口调高 DNS 的过程类似,只需注意将 100 改为 -50 即可。至此,多网口 DNS 查询请求处理完毕。
总结·
本文详细说明了如何在复杂的网络环境下配置 Docker Hub 代理,其中 IPv6 绕过和多网口 DNS 选取是两个较为棘手的问题,好在都被一一发现并解决。