На ноутбуке ты собираешь образ и пушишь его в Docker Hub. Один человек, один аккаунт, паблик-репозиторий - всем удобно. А теперь представь команду из пятнадцати человек, CI, который собирает по сотне образов в день, прод, который дёргает pull тысячу раз в сутки при автоскейле, и требование безопасников: ни один уязвимый образ не должен доехать до кластера. Hub в бесплатном режиме тут разваливается: rate limit на анонимные и бесплатные pull, публичность по умолчанию, ноль RBAC, ноль сканирования, ноль контроля над тем, кто и что выкладывает. Плюс в РФ к этому добавляется простая боль - доступность registry-1.docker.io то есть, то нет, и твой деплой встаёт колом на ровном месте.
Приватный реестр docker (private registry) - это место, где живут образы твоей команды. По сути это HTTP-сервис, реализующий Docker Registry HTTP API V2 (он же OCI Distribution Spec). Любой клиент - docker, containerd, podman, buildkit - общается с ним по одному и тому же протоколу: проверяет манифест, тянет слои по их sha256-дайджесту, заливает блобы. Поэтому registry, Harbor, Yandex Container Registry и GitHub Container Registry снаружи выглядят одинаково. Разница - в том, что навешано вокруг: аутентификация, права, сканирование, репликация, чистка, квоты. Именно это отличает container registry для прода от игрушки. В этом уроке разберём механику и научимся выбирать.

registry:2 - минимальный docker registry под капотом
Начнём с самого простого, чтобы понять, что внутри. Опенсорсный registry (проект CNCF Distribution) - это и есть тот самый референс-сервер. Поднимается одной командой:
Код: Выделить всё
docker run -d --name registry --restart=always \
-p 5000:5000 \
-v /opt/registry/data:/var/lib/registry \
registry:2
Тегируем образ адресом реестра и пушим:
Код: Выделить всё
docker tag myapp:1.0 registry.local:5000/team/myapp:1.0
docker push registry.local:5000/team/myapp:1.0
Здесь же первая стена - HTTPS. Демон Docker по умолчанию отказывается работать с реестром по голому HTTP. Попробуешь push на http-only порт - получишь:
Код: Выделить всё
http: server gave HTTP response to HTTPS client
Код: Выделить всё
{
"insecure-registries": ["registry.local:5000"]
}
Минусы registry:2 как продового решения очевидны ровно в момент, когда команда становится больше одного человека: аутентификация только через внешний htpasswd или reverse-proxy, нет понятия пользователей и ролей, нет UI, нет сканирования, нет нормальной чистки из коробки. Он отличен как встроенный кирпичик (например, как pull-through cache - об этом ниже) или как registry внутри CI. Но как командный реестр он голый.
Harbor registry: что добавляет enterprise-обвязка
Harbor (тоже проект CNCF, актуальная ветка в 2026 - 2.1x, на момент урока релизы линии 2.14/2.15) - это registry:2 внутри плюс целый слой управления сверху. Когда говорят harbor registry в контексте прода, имеют в виду именно эту обвязку. Разберём по кусочкам, потому что каждый пункт закрывает конкретную боль.
Проекты и RBAC. В Harbor образы лежат не плоско, а в проектах. Проект - это и неймспейс (harbor.company.ru/payments/api), и граница доступа, и единица настроек (квоты, политики). Внутри проекта пользователю выдаётся роль: Limited Guest (только pull), Guest (pull), Developer (push+pull), Maintainer (плюс сканирование и управление тегами), ProjectAdmin (всё, включая членов и политики). Сам проект - публичный или приватный. Это и есть RBAC, которого нет в registry:2: ты раздаёшь права не на весь реестр, а точечно. Пользователи живут либо локально, либо приходят из LDAP/AD или OIDC (Keycloak, корпоративный SSO) - в проде почти всегда второе, чтобы не плодить учётки.
Сканирование уязвимостей (Trivy). Harbor из коробки идёт со сканером Trivy как дефолтным (исторически был ещё Clair, сейчас стандарт - Trivy). Сканер разбирает образ послойно, достаёт список установленных пакетов (apt, apk, npm, pip, gem и т.д.) и сверяет версии с базами CVE. Главная фишка - политика на уровне проекта: можно включить scan on push (каждый запушенный образ сразу сканируется) и, что важнее, prevent vulnerable images from running - запрет pull образов с уязвимостями выше заданного порога (например, Critical и High). То есть это не отчёт ради отчёта, а реальный шлюз: уязвимый образ физически не вытянется в кластер. Базы CVE стареют, поэтому в Harbor есть и периодическое пересканирование - вчера чистый образ сегодня может стать дырявым, если выкатили новую CVE.
Подпись образов. Образ - это просто данные на сервере, их теоретически можно подменить. Подпись доказывает, что образ собран доверенной стороной и не изменён после. Старый механизм Notary v1 (Docker Content Trust) в современной экосистеме считается легаси; индустрия ушла на Sigstore cosign, который кладёт подпись рядом с образом как отдельный артефакт в том же реестре. На стороне кластера политику подписи проверяют admission-контроллеры (Kyverno, OPA Gatekeeper, политики Harbor/Connaisseur). Практически: в CI после push делаешь cosign sign, в кластере не пускаешь неподписанное.
Репликация. Политика репликации тянет или толкает образы между реестрами по фильтрам (репозиторий, тег, метка). Сценарии из жизни: реплика Harbor в другом дата-центре или регионе для отказоустойчивости и близости к кластеру (pull по локальной сети, а не через полмира); зеркало образов из внешнего реестра (тот же Docker Hub) внутрь периметра, чтобы не зависеть от его доступности. Репликация бывает push (этот Harbor отправляет) и pull (этот забирает у другого), по расписанию или по событию.
Retention и квоты. CI генерирует теги пачками - на каждый коммит образ, и место кончается за недели. Tag retention policy в Harbor задаётся декларативно на проект: например, держать последние 10 тегов на репозиторий плюс всё, что матчится по маске prod-* и release-*, остальное - под снос. Квоты ограничивают объём проекта в гигабайтах, чтобы одна команда не съела весь диск. Tag immutability отдельно запрещает перезапись тега (чтобы myapp:1.0 нельзя было втихую подменить - критично для воспроизводимости).
Proxy cache (pull-through). Harbor умеет быть кеширующим прокси к внешнему реестру: создаёшь проект типа proxy cache, указываешь upstream (Docker Hub, GHCR, Quay), и при первом pull через него Harbor скачивает образ наружу, кладёт к себе и отдаёт. Дальше всё тянется уже локально. Это прямое лекарство от двух болей разом - rate limit Docker Hub и его недоступности в РФ.
Облачные registry: Yandex, VK, GitHub/GitLab, Nexus
Поднимать и обслуживать Harbor (а это база данных, Redis, сам registry, сканер, job-сервис, обновления, бэкапы, TLS) - работа. Если не хочешь её делать, берёшь managed registry в облаке. Снаружи протокол тот же V2/OCI, отличается биллинг, интеграция с IAM и регион.
Yandex Container Registry. Российский управляемый реестр, частый дефолт для команд на Yandex Cloud. Логин - не пароль, а IAM-токен или сервисный аккаунт. На практике:
Код: Выделить всё
yc container registry configure-docker
docker tag myapp:1.0 cr.yandex/<registry-id>/myapp:1.0
docker push cr.yandex/<registry-id>/myapp:1.0
GitHub Container Registry (ghcr.io) и GitLab Container Registry. Их сила - в том, что реестр сросся с CI/CD и репозиторием кода. У GitLab каждый проект автоматически получает свой registry, образы пушатся прямо из пайплайна предопределёнными переменными ($CI_REGISTRY, $CI_REGISTRY_IMAGE), а CI_JOB_TOKEN авторизует push без хранения отдельных секретов. У GitHub - ghcr.io с правами через GITHUB_TOKEN в Actions. Минус для РФ - доступность обоих к GitHub/GitLab.com нестабильна, для прода внутри страны это риск.
Nexus (Sonatype) и Artifactory. Это универсальные репозитории артефактов: Docker - лишь один из форматов рядом с Maven, npm, PyPI, apt. Берут, когда в компании уже есть Nexus/Artifactory под джавовые или питоновские зависимости, и логично хранить docker-образы там же, в одном месте с единым доступом. Они тоже умеют proxy-репозитории (pull-through кеш) и group-репозитории, объединяющие несколько источников за одним адресом.
Грубое правило выбора. Внутренний прод в РФ, нужен полный контроль, RBAC, сканирование, подпись, репликация - Harbor self-hosted или Yandex/VK managed. Уже живёшь в GitLab/GitHub и команда небольшая - их встроенный registry. Уже есть Nexus/Artifactory под другие артефакты - доложи туда же docker.
Аутентификация, imagePullSecrets и чистка места
Когда реестр приватный, кластеру надо как-то логиниться, чтобы тянуть образы. На уровне Docker всё просто:
Код: Выделить всё
docker login harbor.company.ru
# далее логин/пароль или robot-токен, кредент пишется в ~/.docker/config.json
В Kubernetes этот config.json превращается в Secret типа dockerconfigjson, на который ссылается imagePullSecrets:
Код: Выделить всё
kubectl create secret docker-registry harbor-cred \
--docker-server=harbor.company.ru \
--docker-username='robot$ci+pull' \
--docker-password='<token>' \
-n payments
Теперь про место - то, обо что спотыкаются все. Когда ты delete тег или retention снёс его, образ не освобождает диск. Удаляется лишь ссылка тег -> манифест. Сами blob-ы (слои) остаются лежать в storage как untagged, потому что content-addressable хранилище не знает, не сошлётся ли на них кто-то ещё. Реальное освобождение делает garbage collection - отдельный проход, который находит блобы, на которые больше не ссылается ни один манифест, и физически их стирает. В registry:2:
Код: Выделить всё
docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml
Типичные грабли и антипаттерны
- insecure-registries в проде. Удобно в лабе, дыра в проде: трафик и кред019енты можно перехватить. Всегда нормальный TLS, self-signed CA раздавай в /etc/docker/certs.d/ и /etc/containerd/certs.d/.
- Папка сертификата названа неправильно. Для хоста с портом нужна папка ровно registry.local:5000, а не registry.local. Не совпало - x509 unknown authority.
- Думать, что delete освобождает место. Не освобождает. Нет регулярного GC - реестр распухает молча. Настрой retention И garbage collection вместе.
- latest в проде и перезапись тегов. Тянешь по latest - не знаешь, что именно приехало. Деплой по неизменяемому тегу или по дайджесту (@sha256:...), включи tag immutability.
- Сканирование как украшение. Если Trivy просто рисует отчёт, а pull уязвимого образа не блокируется - это театр. Включай enforcement (prevent vulnerable from running).
- Живые учётки людей в CI и кластере. Используй robot-аккаунты и сервисные токены с минимальными правами и сроком жизни.
- Один Harbor без бэкапа и без реплики. Реестр лёг - встал весь деплой и автоскейл. Для прода - репликация и бэкап БД с storage.
- Подними registry:2 локально с volume на /var/lib/registry. Запушь туда любой образ под именем localhost:5000/test/app:1.0. Загляни в каталог данных и найди папки blobs и repositories - убедись, что слои адресуются по sha256.
- Дёрни каталог реестра через API: curl http://localhost:5000/v2/_catalog и curl http://localhost:5000/v2/test/app/tags/list - увидишь те же данные, что отдаёт UI любого большого реестра, протокол один.
- Сломай TLS специально: попробуй push на реестр без insecure-registries и без сертификата, прочитай ошибку, потом почини через daemon.json. Прочувствуй, на каком шаге всё падает.
- Если есть доступ к облаку - заведи Yandex или VK Container Registry, выполни configure-docker, запушь образ и посмотри, как кредент-хелпер логинит тебя без явного docker login.
- Подними Harbor по официальному offline-инсталлеру, создай приватный проект, robot-аккаунт с правом pull, включи scan on push, запушь заведомо старый образ (например, старый debian) и посмотри отчёт Trivy. Настрой tag retention на 3 последних тега.
- Почему удаление тега в реестре не освобождает место на диске и что именно его освобождает?
- Чем proxy cache (pull-through) проект Harbor помогает против rate limit и недоступности Docker Hub в РФ?
- Где физически должен лежать CA-сертификат self-signed реестра, чтобы docker и containerd ему доверяли, и почему важно имя папки?
- Что такое imagePullSecrets, почему ошибка чаще всего в неймспейсе секрета и чем robot-аккаунт лучше учётки человека?
Любой реестр снаружи - это один и тот же OCI Distribution API: манифесты и слои по дайджесту. registry:2 показывает голую механику и годится как кирпичик или кеш. Harbor добавляет то, без чего нет командного прода: проекты и RBAC, сканирование Trivy с блокировкой, подпись, репликацию, retention и квоты, proxy cache против болей Docker Hub. Облачные registry (Yandex, VK, GHCR, GitLab, Nexus) снимают эксплуатацию, отдавая контроль и привязываясь к своему IAM. А две вещи держи в голове всегда: TLS и доверие к сертификату решают, заработает ли pull вообще, а связка retention + garbage collection решает, не утонет ли реестр в собственных слоях.