ADG Оставить заявку
Блог DevOps 5 мин чтения

GitLab 13.10: Dependency Proxy как ответ на Docker Hub rate limits

GitLab 13.10 привёз улучшенный Container Scanning, Review Apps в MR и Dependency Proxy для кеширования образов Docker Hub - последнее оказалось самым востребованным.

Контекст момента

GitLab 13.10: Dependency Proxy для кеширования Docker Hub образов, улучшенный Container Scanning, автоматические Review Apps в merge request

GitLab 13.10 вышел в конце марта, и на фоне крупных security-анонсов этих недель - ProxyLogon, Pulse Secure - его как-то прошли стороной. А зря: там есть вещи, которые решают конкретные рабочие проблемы прямо сейчас.

Dependency Proxy - вот за чем стоило следить

Docker Hub в ноябре 2020 ввёл rate limits: анонимным запросам - 100 pull за 6 часов с одного IP, авторизованным на free-плане - 200. Для разработчика, который тянет образ руками раз в день, это ничто. Для CI/CD с несколькими десятками параллельных job'ов, каждый из которых делает FROM node:14-alpine или FROM python:3.9-slim, - проблема в полный рост. Ошибки toomanyrequests начали всплывать у нас на нескольких проектах именно тогда.

Классические решения: платный Docker Hub аккаунт с более высокими лимитами, собственный pull-through cache (Nexus, Harbor в режиме proxy, nginx с кешированием). Всё это работает, но требует отдельной инфраструктуры и настройки.

GitLab Dependency Proxy - это встроенный pull-through кеш для Docker Hub, встроенный прямо в инстанс GitLab. Схема работы простая: вместо docker.io/node:14-alpine в пайплайне пишешь ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/node:14-alpine. GitLab при первом обращении тянет образ с Docker Hub от имени своего сервисного аккаунта (с авторизацией), кеширует его локально, при последующих запросах отдаёт из кеша. Rate limits попадают на один аккаунт GitLab, а не на сотни параллельных job'ов.

Dependency Proxy появился ещё в GitLab 11, но именно в 13.10 он получил поддержку авторизованного pull от Docker Hub через учётные данные группы. Это важно: без этого GitLab тянул образы анонимно и сам попадал под те же лимиты.

Для включения достаточно нескольких шагов. В настройках группы включаем Dependency Proxy. В настройках CI группы (Settings - CI/CD - Variables) добавляем переменные DOCKER_HUB_USER и DOCKER_HUB_PASSWORD от авторизованного Docker Hub аккаунта. В .gitlab-ci.yml меняем ссылки на образы:

variables:
  IMAGE_PREFIX: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX

build:
  image: ${IMAGE_PREFIX}/node:14-alpine
  script:
    - npm ci
    - npm run build

Для services - так же:

integration-test:
  image: ${IMAGE_PREFIX}/python:3.9-slim
  services:
    - name: ${IMAGE_PREFIX}/postgres:13
      alias: db
  script:
    - pytest tests/integration/

В пайплайне CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX разворачивается в gitlab.example.com/groupname/dependency_proxy/containers. Первый pull каждого образа идёт на Docker Hub, дальше - из кеша GitLab.

Что поменялось на практике

У нас один из клиентов - e-commerce, Kubernetes-кластер, GitLab с несколькими десятками разработчиков. Пайплайны запускаются часто, параллельно, на разных ветках. После ноября 2020 ошибки toomanyrequests стали появляться нерегулярно, но достаточно часто, чтобы это раздражало. Временным решением была авторизация в Docker Hub прямо в пайплайне через docker login - помогало, но добавляло шаг к каждому job'у и требовало хранить credentials в CI-переменных каждого проекта по отдельности.

После перехода на Dependency Proxy ошибки rate limit исчезли. Credentials храним в одном месте - переменные группы. Первый прогон после переключения чуть медленнее (образы тянутся впервые и кешируются), дальше - быстро, потому что node:14-alpine в следующий раз приходит уже с локального инстанса.

Кеш не вечный: по умолчанию GitLab хранит образы 90 дней без обращений, потом удаляет. На практике популярные образы обращаются к себе каждый день из пайплайнов, так что старение не проблема.

Container Scanning в 13.10

Параллельно GitLab улучшил встроенный Container Scanning - поиск уязвимостей в Docker-образах. Основное изменение: переход на Trivy (от Aqua Security) как основной сканер рядом с Clair. Trivy заметно быстрее, лучше работает с alpine-based образами и даёт более детальные отчёты по пакетам.

Мы начали переводить проекты на встроенный Container Scanning в рамках той же работы по GitLab security features. Настройка стандартная:

include:
  - template: Security/Container-Scanning.gitlab-ci.yml

container_scanning:
  variables:
    CS_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
    CS_SEVERITY_THRESHOLD: HIGH

CS_SEVERITY_THRESHOLD: HIGH - это ключевая переменная: фильтрует только высокие и критические уязвимости, иначе первый прогон выдаст сотни medium-предупреждений по базовым пакетам alpine и парализует команду. Сначала закрываем HIGH/CRITICAL, потом разбираемся с остальными.

Review Apps в merge request

Ещё одно из 13.10, которое интересно, но мы пока не внедрили: автоматическое создание Review Apps при открытии MR с автоматической записью URL окружения в комментарий к MR.

Технически это не новая концепция - Review Apps в GitLab были давно. Новое в 13.10 - упрощение конфигурации: GitLab может сам формировать ссылку на временное окружение и добавлять её в UI merge request без дополнительных скриптов. Для команд, которые делают review на pull request'ах с живым окружением, это уменьшает количество шагов.

У нас это на очереди для проектов с фронтендом - сейчас review делается по скриншотам и описаниям, живые окружения под каждую ветку не поднимаем. Посмотрим как будет работать с Kubernetes namespace per branch, там своя специфика.

Итого

Из 13.10 реально внедрили прямо сейчас: Dependency Proxy - решение готовое, работает, закрывает Docker Hub rate limit без отдельного сервиса. Остальное - в очереди.

В рамках managed-сопровождения переключение на Dependency Proxy делается в течение пары часов: включить в GitLab, добавить групповые переменные, поправить .gitlab-ci.yml в проектах. Особой магии нет, но делать это нужно один раз централизованно, а не в каждом проекте по отдельности.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.