Новые ограничения в использовании Docker Hub и как GitLab реагировал на их ввод

  • Tutorial

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

В компании GitLab мы очень внимательно следили за этими изменениями, так как они затрагивали практически всех наших пользователей и клиентов. Сегодня я хотел бы рассказать о том, какие изменения мы внесли и как адаптировались к новым правилам.

Что же произошло?

Публичный регистр контейнеров Docker Hub очень широко и часто используется сообществом DevOps для достижения разнообразных целей: запуска CI/CD задач, стандартизации процессов, выката контейнерных приложений как в sandbox, так и в production. Как только мы узнали о введении новых ограничения по количеству запросов, мы начали анализ новых правил, чтобы понять, как они повлияют на работу наших пользователей, и как мы можем помочь решить возможные проблемы.

Согласно новым правилам после 100 запросов за 6 часов с одного клиентского IP адреса каждый новый docker pull вернет ошибку 429 - too many requests, что несомненно приведет к сломанным CI/CD конвейерам, невозможности выкатить приложения и целому букету ошибок в ваших Kubernetes кластерах. Вполне понятно, что этот лимит может быть очень быстро достигнут, особенно если все задачи выполняются с одного и того же GitLab Runner агента, или если команда из нескольких инженеров работает с одного и того же публичного адреса.

Аутсорсинг Dependency Proxy

Как отметил мой коллега Tim Rizzi "Нам следует срочно всем рассказать о Dependency Proxy", который изначально создавался для проксирования и кэширования образов Docker Hub. Этот функционал существует в GitLab уже довольнейший давно (начиная с версии 11.11), но до сегодняшнего дня был доступен только для пользователей Enterprise подписки уровня Premium. Перед продуктовой командой встал вполне резонный вопрос: "Стоит ли нам вынести Dependency Proxy в open source версию продукта, помогая таким образом широкому сообществу пользователей минимизировать проблемы из-за новых ограничений Docker Hub?"

Не вдаваясь в подробности, ответ на этот вопрос был ДА. При принятии решения, в какой уровень подписки должен попадать тот или иной функционал продуктовая команда GitLab всегда руководствуется вопросом "Кто является целевым пользователем?". Согласно этому принципу те возможности, которые чаще всего запрашивает индивидуальный участник или разработчик, попадают в Core или Open Source версию продукта. Скачивание образов с Docker Hub вполне соответсвует этому описанию. Более того аутсорсинг Dependency Proxy поможет большому количеству разработчиков повысить надежность и производительность их CI/CD конвейеров.

Как результат, начиная с версии 13.6 вышедшей 22 ноября 2020 года, проксирование и кэширование образов в GitLab стало абсолютно бесплатным для всех наших пользователей!

Что дальше?

К сожалению, идеальные решения не появляются мгновенно. Мы как никто другой знаем, что нашему продукту есть куда расти, поэтому активно работаем над улучшением функционала Dependency Proxy и уже в ближайших релизах планируем добавить новые возможности / решить имеющиеся проблемы:

  • 13.7 (22 декабря, 2020)

    • gitlab-#11582 сделает возможным использование Dependency Proxy для приватных групп в GitLab (сегодня работает только для публичных проектов)

    • gitlab-#241639 позволит использовать закэшированный образ даже если Docker Hub недоступен. На сегодня это невозможно, так как даже при наличии закэшированного образа, его манифест всегда скачивается из конечного регистра

    • gitlab-#21619 добавит новый параметр pull_policy в YAML описании CI/CD задач, позволяющий разработчикам самим указывать политику скачивания контейнера (always, if-not-present, never) вместо того, чтобы полагаться на настройки GitLab Runner

    • gitlab-runner-#26558 позволит конфигурировать GitLab Runner с набором политик для скачивания образов (always, if-not-present)

Мониторинг ограничений

Решения обозначенные выше, а также в блог посте моего коллеги Steve Azzopardi, помогут упростить работу с новыми ограничениями, но не избавят от них на все 100%. Поэтому мы также выработали набор советов и инструментов, цель которых - помочь широкому сообществу адаптироваться к новым лимитам за счет их мониторинга.

Как проверить текущее значение лимита?

Документация Docker рекомендует использовать HTTP запрос для проверки текущего значения ограничений запросов в Docker Hub.

Начнем с определения образа, для которого мы хотим получить текущее ограничение и получения токена для авторизации:

$ IMAGE="ratelimitpreview/test"
$ TOKEN=$(curl "https://auth.docker.io/token?service=registry.docker.io&scope=repository:$IMAGE:pull" | jq -r .token)

$ echo $TOKEN

Следующий шаг - симуляция запроса docker pull. Вместо использования метода GET отправляем HEAD запрос (он не учитывается при подсчете ограничений). Ответ на этот запрос содержит параметры RateLimit-Limit и RateLimit-Remaining.

$ curl --head -H "Authorization: Bearer $TOKEN" https://registry-1.docker.io/v2/$IMAGE/manifests/latest

В примере ниже количество запросов ограничено 2500, из которых 2495 еще доступны. 21600 определяет шестичасовой период (в секундах)

RateLimit-Limit: 2500;w=21600
RateLimit-Remaining: 2495;w=21600

Автоматизация проверки лимитов

Michael Friedrich, один из евангелистов GitLab, поделился готовым решением на Python для проверки ограничений. Проект включает подробную документацию по установке и использованию

$ python check_docker_hub_limit.py --help

usage: check_docker_hub_limit.py [-h] [-w WARNING] [-c CRITICAL] [-v] [-t TIMEOUT]

Version: 2.0.0

optional arguments:
  -h, --help            show this help message and exit
  -w WARNING, --warning WARNING
                        warning threshold for remaining
  -c CRITICAL, --critical CRITICAL
                        critical threshold for remaining
  -v, --verbose         increase output verbosity
  -t TIMEOUT, --timeout TIMEOUT
                        Timeout in seconds (default 10s)

Скрипт возвращает следующие exit коды в зависимости от указанных параметров

  • 0- OK

  • 1- WARNING

  • 2- CRITICAL

$ python3 check_docker_hub_limit.py
OK - Docker Hub: Limit is 5000 remaining 4997|'limit'=5000 'remaining'=4997

$ echo $?
0

$ python3 check_docker_hub_limit.py -w 10000 -c 3000
WARNING - Docker Hub: Limit is 5000 remaining 4999|'limit'=5000 'remaining'=4999

$ echo $?
1

$ python3 check_docker_hub_limit.py -w 10000 -c 5000
CRITICAL - Docker Hub: Limit is 5000 remaining 4998|'limit'=5000 'remaining'=4998

$ echo $?
2

Экспортер Prometheus

Кроме этого мы подготовили и выпустили экспортер для Prometheus, который позволит экспортировать метрики ограничений и реализовать их полноценный мониторинг.

Репозиторий проекта включает демо контейнер, включающий себе экспортер, Prometheus, Grafana, и docker-compose инструкции для его выката

$ cd example/docker-compose

$ docker-compose up -d

Перейдите по адресу http://localhost:3000 для доступа к дэшборду Grafana

Надеюсь, наш опыт и рекомендации окажутся для вас полезными!

GitLab
Company

Comments 4

    0
    Ну вот почему, почему в Maven кэширование и прокси-репозитории есть 15 лет уже как, а в Docker всё заново изобретается (. Это же просто ненормальная практика, завязываться на один центральный источник бинарников.
      +4
      хм. так это именно в maven есть прокси-репозитории или в nexus/artifactory/gitlab?
        0
        upd: меня чуть-чуть опередили. дополню.


        а в Docker всё заново изобретается

        давно есть решения для проксирования\кэширования докера.

        просто теперь это появилось и в гитлабе.

        завязываться на один центральный источник бинарников

        согласен, в плане подхода — это не очень. но hub — не один источник, он «дефолтныый». на jfrog.io встречал авторов с образами, гитхаб тоже поддерживает — просто эти платформы по сравнению менее популярны, кмк.

        0
        goharbor.io умеет как прокси, так и зеркалирование.

        Only users with full accounts can post comments. Log in, please.