kai.kzLab

toomanyrequests: You have reached your pull rate limit — лимиты Docker Hub и как защитить CI

Команда KAI Lab · · 10 мин чтения

Ошибка toomanyrequests значит, что Docker Hub ответил кодом 429: с вашего IP-адреса или аккаунта за последние 6 часов скачали больше образов, чем разрешает лимит. На 25 сентября 2026 года анонимным пользователям доступно 100 скачиваний за 6 часов на IPv4-адрес или подсеть IPv6 /64, бесплатным аккаунтам Personal — 200, а у платных подписок Pro, Team и Business ограничение только по правилам fair use.

Сильнее всего лимит бьёт по CI и кластерам Kubernetes: там много машин ходят в интернет через один адрес и качают образы без входа в аккаунт. Ниже — как проверить остаток, как лимиты впервые остановили пайплайны в 2020 году и как перестать зависеть от чужого реестра.

Как выглядит ошибка

В Docker CLI:

$ docker pull node:20-alpine
Error response from daemon: toomanyrequests: You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limits

В Kubernetes та же строка приходит внутри события Failed от kubelet, а под уходит в ImagePullBackOff. Середина сообщения зависит от версии containerd, ниже она сокращена:

$ kubectl get events -n shop --field-selector reason=Failed
LAST SEEN   TYPE      REASON   OBJECT                    MESSAGE
52s         Warning   Failed   pod/api-6d9f8b7c5-2xkqp   Failed to pull image "postgres:16": ... 429 Too Many Requests ... toomanyrequests: You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limits

Есть и второй лимит — защита от злоупотреблений: порядка тысяч запросов в минуту с одного IPv4-адреса или подсети IPv6 /64, одинаково для всех аккаунтов. Он возвращает короткий 429 Too Many Requests, а лимит скачиваний — длинное сообщение со ссылкой на документацию.

Какие лимиты действуют сейчас

Данные документации Docker на 25 сентября 2026 года:

Тип пользователяЛимит скачиваний за 6 часов
Business, Team, Pro (с входом в аккаунт)без лимита, в рамках fair use
Personal (с входом в аккаунт)200
Без входа в аккаунт100 на IPv4-адрес или подсеть IPv6 /64

Что считается одним pull:

  • скачивание обычного образа — один pull, то есть один запрос его манифеста; слои отдельно не считаются;
  • скачивание multi-arch образа засчитывается как один pull на каждую архитектуру;
  • скачивания с входом в аккаунт считаются на аккаунт, без входа — на IP-адрес.

Как проверить остаток лимита

Документация Docker предлагает запросить заголовки у тестового репозитория. Запрос HEAD лимит не расходует, GET расходует как настоящий pull. Понадобятся curl и jq:

$ TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull" | jq -r .token)
$ curl -s --head -H "Authorization: Bearer $TOKEN" https://registry-1.docker.io/v2/ratelimitpreview/test/manifests/latest | grep -i ratelimit
ratelimit-limit: 100;w=21600
ratelimit-remaining: 20;w=21600
docker-ratelimit-source: 192.0.2.1

w=21600 — окно в 21 600 секунд, то есть 6 часов. docker-ratelimit-source показывает, на кого записаны скачивания, здесь — на IP-адрес. Для проверки лимита аккаунта токен получают с учётными данными: curl --user 'имя:токен' .... Если заголовков ratelimit нет, лимит к вам не применяется: платная подписка или партнёрская программа Docker. Запускайте проверку на раннере CI или ноде кластера: важен их адрес, а не адрес вашего ноутбука.

История: как в 2020 году покраснели пайплайны

До осени 2020 года Docker Hub не ограничивал анонимные скачивания, и на этом держалось множество пайплайнов: каждая сборка тянула базовые образы заново, без входа в аккаунт.

ДатаЧто произошло
14 августа 2020В документации Docker появилась страница о лимитах: они будут вводиться постепенно, с итоговым лимитом 100 pull за 6 часов для анонимных пользователей
24 августа 2020Docker объявил лимиты с полным вступлением в силу с 1 ноября: 100 pull за 6 часов без входа, 200 для бесплатных аккаунтов, без лимита для Pro и Team
28 октября 2020Документация уточнила: лимиты вводятся постепенно, начиная со 2 ноября 2020 года
30 октября 2020GitLab опубликовал разбор для клиентов: общие раннеры GitLab.com не пострадают, потому что ходят через зеркало Docker Hub от Google, а собственные раннеры клиентов попадают под лимит
2 ноября 2020Начало ограничений. AWS в тот же день выпустил советы клиентам и анонсировал свой публичный реестр
1 декабря 2020Запущены Amazon ECR Public и галерея ECR Public Gallery

Почему пострадали именно CI. Облачные раннеры и ноды кластеров выходят в интернет через общие NAT-адреса и делят один анонимный лимит. Свежий раннер не хранит кэш, и каждая сборка заново качает node, python или postgres. Сотня скачиваний на такой адрес заканчивается быстро, и сборки падают с toomanyrequests там, где вчера всё работало. GitLab предложил клиентам зеркало, вход в аккаунт и свой Dependency Proxy, AWS — копировать образы в ECR, а Docker добавил в документацию инструкции по входу для CircleCI, GitHub Actions, GitLab, TeamCity и AWS CodeBuild.

Урок тот же, что и после истории с left-pad в 2016 году: внешний сервис, без которого не собирается ваш код, — это зависимость со своими правилами. Её нужно кэшировать у себя.

2025 год: лимиты хотели ужесточить, но отложили

В феврале 2025 года документация Docker объявила новые лимиты с 1 апреля: 10 pull в час без входа в аккаунт и 100 pull в час для бесплатных аккаунтов. В апреле Docker их не ввёл. В обновлённом посте компании сказано, что лимиты 100 и 200 pull за 6 часов остаются, пока Docker изучает отзывы, а о будущих изменениях компания предупредит минимум за 6 месяцев. Платные подписки с 1 апреля 2025 года качают без лимита, в рамках fair use. Вывод: цифры в документации команды стоит сверять со страницей Docker Hub usage and limits.

Как решить: от быстрого к надёжному

1. Войти в аккаунт Docker Hub

Самая быстрая мера: скачивания считаются на аккаунт, а не на общий адрес. В CI берите персональный токен доступа из секретов пайплайна:

$ echo "$DOCKERHUB_TOKEN" | docker login -u "$DOCKERHUB_USER" --password-stdin

В Kubernetes учётные данные Docker Hub передают через imagePullSecrets, как для приватного реестра, — это показано в статье про ImagePullBackOff. От abuse-лимита вход не спасает: он считается по адресу.

2. Зеркало или pull-through cache

Образ скачивается из Docker Hub один раз, дальше — из вашего кэша. Официальный Docker Registry умеет работать как pull-through cache, если добавить в его конфигурацию секцию proxy:

proxy:
  remoteurl: https://registry-1.docker.io
  username: mirror-bot
  password: ТОКЕН

С учётными данными через зеркало станут доступны и приватные образы этого аккаунта, поэтому зеркало закрывают аутентификацией. Docker Engine направляют на зеркало в /etc/docker/daemon.json и перезапускают демон:

{
  "registry-mirrors": ["https://mirror.example.kz"]
}

Параметр работает только для Docker Hub. На нодах Kubernetes с containerd зеркало задают в /etc/containerd/certs.d/docker.io/hosts.toml, указав в конфигурации containerd config_path = "/etc/containerd/certs.d":

server = "https://registry-1.docker.io"

[host."https://mirror.example.kz"]
  capabilities = ["pull", "resolve"]

Вместо голого Registry часто берут Harbor с proxy cache, Nexus, Artifactory или GitLab Dependency Proxy. Зеркало Google mirror.gcr.io хранит только часто запрашиваемые образы и без гарантий, поэтому единственным решением быть не может.

3. Свой реестр для базовых образов

Базовые образы копируют в свой реестр и пишут в Dockerfile FROM registry.example.kz/base/node:20-alpine. docker pull, tag и push скопируют только одну платформу multi-arch образа, поэтому удобнее skopeo:

$ skopeo copy --all docker://docker.io/library/node:20-alpine docker://registry.example.kz/base/node:20-alpine

Копию обновляют по расписанию, иначе в ней не будет исправлений безопасности.

4. Меньше лишних скачиваний

В Kubernetes тег latest или отсутствие тега по умолчанию дают imagePullPolicy: Always, и kubelet обращается к реестру при каждом запуске контейнера. Фиксированные теги или digest и кэш слоёв на постоянных раннерах CI заметно сокращают число скачиваний.

Причины toomanyrequests: таблица

ПричинаКак узнатьКак исправить
Анонимные pull с общего IP (NAT, облачный CI)ratelimit-remaining: 0, в docker-ratelimit-source адрес NATdocker login, imagePullSecrets
Каждая сборка заново качает базовые образыв логах CI одни и те же docker pullкэш слоёв, зеркало
В Kubernetes тег latest или imagePullPolicy: Alwaysобращение к реестру при каждом старте подафиксированные теги и IfNotPresent
Исчерпан лимит аккаунта Personalratelimit-limit: 200;w=21600, ошибка и после входазеркало, свой реестр или платная подписка
Сработал abuse-лимиткороткий 429 Too Many Requests без ссылки на документациюснизить частоту запросов с одного адреса, зеркало

Реши сам

Два вопроса из разбора этого сбоя в симуляторе DevOps KAI Lab.

Вопрос 1. Почему лимиты больнее всего ударили по CI?

  1. CI использует старые версии Docker
  2. Раннеры скачивают образы анонимно и часто из общих IP, заново при каждой сборке
  3. CI не поддерживает Docker Hub
  4. Из-за медленной сети
Показать ответ

Верный ответ — 2. Лимит для анонимных скачиваний считается по IP-адресу. Облачные раннеры выходят в интернет через общие адреса, свежий раннер не хранит кэш, и каждая сборка заново тянет базовые образы. Сотня pull за шесть часов на такой адрес заканчивается очень быстро.

Вопрос 2. Какое решение устойчивое, а не временное?

  1. Перезапускать упавшие сборки
  2. Зеркало с кэшем или собственный реестр для базовых образов
  3. Собирать реже
  4. Использовать образ latest
Показать ответ

Верный ответ — 2. Образ скачивается из внешнего источника один раз, дальше — из своего кэша. Перезапуски только быстрее расходуют лимит, а latest заставляет Kubernetes обращаться к реестру при каждом старте пода.

Частые вопросы

Какие лимиты у Docker Hub сейчас? На 25 сентября 2026 года: 100 pull за 6 часов без входа в аккаунт, на IPv4-адрес или подсеть IPv6 /64; 200 pull за 6 часов для бесплатного аккаунта Personal; без лимита для Pro, Team и Business в рамках fair use. Перед планированием сверяйтесь с документацией Docker: лимиты уже менялись.

Когда лимит восстановится? Лимит считается в окне 6 часов, это видно по w=21600 в заголовке, а остаток показывает ratelimit-remaining. Перезапуск упавших сборок только тратит остаток.

Поможет ли вход в аккаунт, если все раннеры за одним NAT? Да: скачивания с входом считаются на аккаунт, а не на IP-адрес. Но abuse-лимит считается по адресу, поэтому для команды надёжнее зеркало.

Почему ошибка появилась в Kubernetes, где мы ничего не меняли? Ноды скачивают образ для каждого нового пода, если его нет локально. Масштабирование, новые ноды или тег latest резко увеличивают число скачиваний, а все ноды за NAT делят один анонимный лимит.

Будет ли Docker снова ужесточать лимиты? Ужесточение объявляли в феврале 2025 года, но не ввели. Docker обещает предупреждать о будущих изменениях минимум за 6 месяцев. Зеркало лучше завести заранее.

Разобрать сбой в симуляторе

История Docker Hub — один из 18 разборов реальных аварий в симуляторе DevOps KAI Lab: он идёт в месяце про Docker, рядом с задачами про реестр, теги и digest. Остальные истории собраны в статье 18 сбоев, которые должен знать инженер, а вопросы про слои, теги и реестры часто задают на собеседовании по Docker. Попробовать можно бесплатно: тест навыков DevOps и первые задания первого месяца.

Источники

Читать дальше