野草云 Docker 拉取失败?3 分钟解决限流问题

上周我在野草云服务器上部署项目时,突然遇到了一个让人头疼的问题。当我执行 docker pull 命令拉取镜像时,屏幕上跳出了这样的报错:

stderr: Error response from daemon: toomanyrequests: You have reached your unauthenticated pull rate limit.

说实话,第一次遇到野草云 Docker 拉取失败也很困恼。不过冷静下来仔细看提示信息,其实原因很简单:Docker Hub 对未登录用户设置了拉取次数限制

为什么会出现 Docker 拉取限流问题?

Docker Hub 的限流政策

Docker Hub 作为全球最大的容器镜像仓库,为了保证服务稳定性,对镜像拉取次数做了明确的限制。我把官方的限流规则整理成了下面这张表格:

用户类型限流规则计算方式
个人认证用户200次/6小时按账号计算
未认证用户100次/6小时按 IPv4 地址或 IPv6 /64 子网

看到这个规则,你可能会想:一天就拉取一两个镜像,怎么可能超过100次的限制呢?

说实话,我一开始也是这么想的。

野草云用户容易中招的真正原因

直到我在野草云服务器上反复遇到这个问题后,我发现:野草云支持 IPv6。这本来是个好事,毕竟 IPv6 是未来趋势嘛。但问题就出在这里。

现在越来越多的网络请求会优先走 IPv6 协议。当你在野草云服务器上执行 docker pull 命令时,如果你没有登录 Docker Hub,系统就会用你的 IPv6 地址去请求。

然而 Docker Hub 对 IPv6 的限流不是按单个 IP 地址计算的,而是按整个 /64 子网来统计

这意味着什么呢?

一个 IPv6 的 /64 子网下面可能有成百上千台机器。野草云作为云服务器提供商,同一个子网段下肯定不止你一个用户在用 Docker。当这个子网内其他用户频繁拉取镜像时,即使你自己只拉取了一两次,也可能被算进总数里,最终触发 100 次的限制。

我的实际测试

为了验证这个猜测,我做了个简单的测试:

在野草云服务器上执行 curl -I -v https://auth.docker.io/token 查看连接方式,然后我发现请求确实走的是 IPv6,这也解释了为什么我没有多少拉取操作,却遇到了限流。

    这下真相大白了。知道了原因,解决方法其实就很简单了。下一节我会详细有效的解决方案,帮你彻底摆脱这个烦人的限流问题。

    方法 1:禁用 IPv6(最直接)

    找到问题所在,解决起来就容易多了。既然问题出在 IPv6 子网共享配额上,那最直接的办法就是:让 Docker 走 IPv4 网络拉取镜像

    野草云的服务器大部分套餐都同时提供 IPv4 和 IPv6 地址,我们可以临时或永久禁用 IPv6,这样 Docker 就会自动使用 IPv4 连接,也就不会受到子网其他用户的影响了。

    临时禁用 IPv6(立即生效,重启失效)

    如果你只是临时需要拉取几个镜像,不想改动系统配置,可以用这个方法:

    sudo sysctl -w net.ipv6.conf.all.disable_ipv6=1
    sudo sysctl -w net.ipv6.conf.default.disable_ipv6=1

    执行完这两条命令后,IPv6 就被禁用了。你可以立即执行 docker pull 命令测试:

    docker pull nginx:latest

    这时候你会发现,镜像拉取速度正常了,也不会再报 toomanyrequests 错误。

    注意:这个方法的缺点是服务器重启后会失效,IPv6 会自动恢复启用。

    永久禁用 IPv6(推荐)

    如果你希望一劳永逸地解决问题,可以把禁用 IPv6 的配置写入系统文件,让它永久生效。

    步骤1:编辑系统配置文件

    sudo nano /etc/sysctl.conf

    如果你不习惯用 nano 编辑器,也可以用 vim:

    sudo vim /etc/sysctl.conf

    步骤2:在文件末尾添加以下内容

    net.ipv6.conf.all.disable_ipv6 = 1
    net.ipv6.conf.default.disable_ipv6 = 1
    net.ipv6.conf.lo.disable_ipv6 = 1

    保存退出(nano 按 Ctrl+X,然后按 Y 确认,vim 输入 :wq 回车)。

    步骤3:让配置立即生效

    sudo sysctl -p

    执行完这条命令后,你会看到系统输出刚才添加的三行配置,说明设置已经生效了。

    步骤4:验证 IPv6 是否已禁用

    ip a | grep inet6

    如果没有任何输出,说明 IPv6 已经成功禁用。

    禁用后会影响什么吗?

    我知道你可能会担心:禁用 IPv6 会不会影响服务器的其他功能?根据我在野草云服务器上的实际使用经验,对绝大多数应用没有影响。原因很简单:

    • 目前国内大部分网站和服务还是以 IPv4 为主
    • Docker、Nginx、数据库等常用服务都完全支持纯 IPv4 环境
    • 你的网站访客该访问还是能访问,不会受任何影响

    唯一需要注意的是:如果你的应用明确需要使用 IPv6(比如你在做 IPv6 相关的测试或开发),那就不能用这个方法,需要看后面我介绍的其他解决方案。

    方法 2:登录 Docker Hub 账号(最简单)

    如果你不想折腾系统网络配置,还有一个更简单的办法——注册并登录 Docker Hub 账号

    还记得前面我们说的限流规则吗?未认证用户只有 100 次 / 6 小时,但个人认证用户可以达到 200次 / 6 小时。而且这个配额是按账号计算的,不会被其他用户影响。

    对于个人开发者和小型项目来说,200 次的配额完全够用了。我自己测试过,即使是部署一个包含十几个容器的复杂应用,通常也就拉取 20-30 次镜像,离 200 次还远着呢。

    第一步:注册 Docker Hub 账号(1 分钟)

    如果你还没有 Docker Hub 账号,注册过程非常简单:

    1. 打开浏览器访问:https://hub.docker.com/signup
    2. 填写邮箱、用户名、密码
    3. 勾选同意条款,点击注册
    4. 去邮箱收验证邮件,点击链接激活账号

    整个过程不到 1 分钟就能完成,完全免费。

    第二步:在野草云服务器上登录(30秒)

    Docker 现在提供了一个超级方便的网页登录方式,比以前输入用户名密码要简单多了。

    在你的野草云服务器终端,直接执行:

    docker login

    系统会自动使用网页登录模式,显示类似这样的信息:

    USING WEB-BASED LOGIN
    i Info → To sign in with credentials on the command line, use 'docker login -u <username>'
             
    Your one-time device confirmation code is: SSAA-BBCC
    Press ENTER to open your browser or submit your device code here: https://login.docker.com/activate
    Waiting for authentication in the browser…

    这个时候需要你通过浏览器完成登录:

    1. 复制屏幕上显示的验证码(比如 SSZF-PJGF
    2. 在你的电脑浏览器中打开:https://login.docker.com/activate
    3. 输入验证码并登录你的 Docker Hub 账号
    4. 回到终端,等待几秒钟

    登录成功后你会看到:

    WARNING! Your credentials are stored unencrypted in '/root/.docker/config.json'.
    Configure a credential helper to remove this warning. See
    https://docs.docker.com/go/credential-store/
    
    Login Succeeded

    看到 Login Succeeded 就大功告成了!

    传统方式登录(可选)

    如果你更习惯传统的用户名密码登录方式,也可以用这个命令:

    docker login -u 你的用户名

    然后输入密码即可。不过说实话,新的网页登录方式真的方便太多了,我现在都用这个。

    第三步:立即测试效果

    现在你可以直接拉取镜像试试:

    docker pull nginx:latest
    docker pull mysql:8.0
    docker pull redis:alpine

    你会发现镜像顺利下载,不再出现 toomanyrequests 的报错了。

    其他解决方案

    当然,除了上面介绍的两种方法,你也可以通过配置国内镜像加速器来解决这个问题。

    镜像加速器的原理很简单:你不直接从 Docker Hub 拉取镜像,而是从国内的镜像站拉取,这样既能绕过 Docker Hub 的限流。常见的镜像加速器有阿里云、腾讯云、网易云等。

    不过说实话,前面介绍的禁用 IPv6 或登录 Docker 账号这两个方法已经足够解决问题了。镜像加速器虽然也有效,但配置相对复杂一些,而且国内镜像站的同步速度有时候不太理想。

    总结:野草云 Docker 拉取失败

    野草云 Docker 拉取失败限流的问题说复杂也不复杂,关键是要理解背后的原因。

    归根结底就是三个字:配额不够。要么你被 IPv6 子网其他用户”连累”了,要么就是你自己的拉取次数确实太频繁。可以通过禁用 IPv6 或者登录 Docker Hub 账号,几分钟解决问题。

    希望这篇文章能帮你彻底解决野草云 Docker 拉取失败的烦恼。

    常见问题解答(FAQ)

    在帮助用户解决野草云 Docker 限流问题的过程中,我发现大家经常会问到以下这些问题。我把它们整理出来,希望能帮你少走弯路。

    Q1:禁用 IPv6 后,我的网站访客还能正常访问吗?

    能,完全不影响。

    只要你的域名解析里配置了 A 记录(IPv4 地址),访客就能通过 IPv4 正常访问。而且现在国内绝大多数用户的网络环境还是以 IPv4 为主,就算你的服务器完全不支持 IPv6,对用户体验也没有任何影响。

    Q2:登录 Docker Hub 后,配额是永久有效的吗?

    是的,只要你保持登录状态,配额就一直有效。即使服务器重启,登录状态也不会丢失。除非你主动执行 docker logout 退出登录,或者重装系统导致配置文件丢失。

    Q3:我有 5 台服务器,需要每台都登录 Docker Hub 吗?

    是的,需要每台单独登录。Docker 的登录信息是存储在本地的,不会跨服务器同步。所以你有几台服务器,就需要在每台服务器上分别执行一次 docker login

    Q4:禁用 IPv6 和登录 Docker 账号,可以同时使用吗?

    可以,但没必要。只要登录了 Docker Hub 账号,就会按照个人账户的授权限制进行限流,每 6 小时 200 次的拉取额度,个人用户基本不会遇到限流问题。

    Q5:限流错误解决后,之前拉取失败的镜像需要重新拉取吗?

    需要,之前失败的拉取不会自动恢复。解决限流问题后,你需要重新执行一次 docker pull 命令。

    Q6:我用的是 Docker Compose,遇到限流怎么办?

    Docker Compose 底层调用的还是 Docker 引擎,所以遇到的限流问题和单独使用 docker pull 是一样的。你只需要按照前面介绍的方法(禁用 IPv6 或登录 Docker Hub),配置好之后即可。

    发表评论