MAATRIX / Блог / Harbor в Docker Compose: готовый файл

Harbor в Docker Compose: готовый файл

MAATRIX

Когда команда вырастает из связки «Docker Hub + пароль в чате», встаёт вопрос приватного реестра. Голый registry:2 решает задачу с образами, но не даёт ролей, сканирования на уязвимости и внятного веб-интерфейса. Harbor закрывает именно этот разрыв — это полноценная платформа для хранения образов уровня продакшена, которую можно поднять на своём VPS через Docker Compose за один вечер. Ниже — рабочий harbor.yml, разбор из чего состоит стек и на что обратить внимание, чтобы не упереться в TLS-ошибки на старте.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Что такое Harbor и когда он оправдан

Harbor — open-source проект, изначально созданный в VMware и переданный в CNCF. Это не один контейнер, а связка сервисов: реестр образов (based on distribution/registry), веб-портал, сканер уязвимостей Trivy, очередь заданий, PostgreSQL и Redis, всё за общим nginx-прокси.

Смысл ставить Harbor вместо registry:2 появляется, когда нужно что-то из этого:

  • RBAC — роли на уровне проектов (guest/developer/maintainer/admin), а не общий пароль на весь реестр.
  • Сканирование на уязвимости — Trivy проверяет каждый запушенный образ и показывает CVE прямо в интерфейсе.
  • Квоты и подпись образов — ограничение места на проект, поддержка Cosign/Notary для доверенного контента.
  • Репликация — синхронизация образов между несколькими Harbor-инстансами или с Docker Hub/ECR.
  • Веб-интерфейс — просмотр тегов, манифестов, истории пушей без curl и jq.

Если вам нужно просто «свой Docker Hub для двух человек» — не тратьте на это отдельный сервер, хватит приватного Docker registry поверх nginx. Harbor имеет смысл от команды в 3-5+ разработчиков или когда сканирование на уязвимости — не опция, а требование (комплаенс, внешний аудит).

Требования к серверу

Harbor — не лёгкий сервис. Официальный минимум от разработчиков — 2 vCPU / 4 GB RAM / 40 GB диска, но это скорее «взлетит, но будет тормозить». Для комфортной работы команды на постоянной основе:

ПараметрМинимумКомфортно
CPU2 vCPU4 vCPU
RAM4 GB8 GB
Диск40 GB SSD100+ GB SSD (растёт с образами)
ОСUbuntu 22.04/24.04, Debian 12то же

Диск — узкое место в первую очередь: слои образов накапливаются быстро, а сборка мусора (garbage collection) в Harbor запускается вручную или по расписанию, а не сама по себе после каждого удаления тега. Закладывайте запас минимум в 2 раза больше, чем текущий вес ваших образов в CI.

Порты, которые понадобится открыть наружу:

  • 443/tcp — HTTPS-доступ к порталу и к самому реестру (docker push/pull идут через тот же порт).
  • 4443/tcp — опционально, если включаете отдельный порт для Notary (подпись образов).
  • 22/tcp — SSH-доступ к серверу, как обычно.

Порт 80 можно оставить закрытым снаружи и использовать только для редиректа на 443.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Подготовка сервера

Понадобится Docker и Docker Compose plugin. На Ubuntu 24.04:

curl -fsSL https://get.docker.com | sh
sudo systemctl enable --now docker
docker compose version

Заранее решите вопрос с DNS и TLS-сертификатом — Harbor в проде без HTTPS ставить не стоит: Docker-клиент по умолчанию требует TLS для взаимодействия с реестром, а прописывать insecure-registries на каждой машине, которая будет пушить образы, — плохая практика для команды больше одного человека.

Проще всего — направить A-запись (например harbor.example.com) на IP сервера и выпустить сертификат Let's Encrypt:

sudo apt install certbot -y
sudo certbot certonly --standalone -d harbor.example.com

Сертификат появится в /etc/letsencrypt/live/harbor.example.com/. Про сам процесс выпуска и продления подробно — в статье про Let's Encrypt на VPS, если раньше не настраивали.

Скачайте офлайн-инсталлятор Harbor (замените версию на актуальную на момент установки — на конец лета 2026 стабильной веткой считается 2.x, проверьте релизы на GitHub Harbor перед скачиванием):

wget https://github.com/goharbor/harbor/releases/download/v2.12.0/harbor-offline-installer-v2.12.0.tgz
tar xzvf harbor-offline-installer-v2.12.0.tgz
cd harbor

Важный нюанс: Harbor не поставляется как готовый docker-compose.yml, который можно просто запустить. Разработчики отдают шаблон harbor.yml.tmpl — вы конфигурируете его под себя, а установочный скрипт prepare сам генерирует финальный docker-compose.yml со всеми сервисами и правильными переменными окружения. Это осознанное архитектурное решение — слишком много параметров (TLS, база, объём хранения) зависят друг от друга, чтобы держать их в одном статичном compose-файле.

Готовый harbor.yml

Скопируйте шаблон и откройте его:

cp harbor.yml.tmpl harbor.yml
nano harbor.yml

Вот рабочий вариант конфигурации под сценарий «один сервер, свой домен, Let's Encrypt сертификат»:

hostname: harbor.example.com

http:
  port: 80

https:
  port: 443
  certificate: /etc/letsencrypt/live/harbor.example.com/fullchain.pem
  private_key: /etc/letsencrypt/live/harbor.example.com/privkey.pem

harbor_admin_password: ЗАМЕНИТЕ_НА_СВОЙ_ПАРОЛЬ

database:
  password: ЗАМЕНИТЕ_НА_ПАРОЛЬ_БД
  max_idle_conns: 100
  max_open_conns: 900

data_volume: /data/harbor

trivy:
  ignore_unfixed: false
  skip_update: false
  security_check: vuln
  insecure: false

jobservice:
  max_job_workers: 10

log:
  level: info
  local:
    rotate_count: 50
    rotate_size: 200M
    location: /var/log/harbor

_version: 2.12.0

Ключевые поля, за которыми нужно следить отдельно:

  • hostname — должен совпадать с доменом в сертификате и с тем, что вы будете писать в docker login/docker push. Несовпадение — самая частая причина ошибок TLS на старте.
  • data_volume — сюда пишутся все слои образов. Держите на отдельном разделе или диске с запасом, это растущая директория.
  • harbor_admin_password — пароль встроенного admin-аккаунта. Сгенерируйте случайный, не оставляйте Harbor12345 из примеров.
  • database.password — внутренний пароль для встроенного PostgreSQL-контейнера, наружу не смотрит, но всё равно не оставляйте пустым.

Если на сервере уже стоит Traefik или nginx под другие сервисы, секцию https в harbor.yml можно не заполнять и терминировать TLS на внешнем прокси — но тогда нужно прокинуть заголовки и поднять лимит на размер тела запроса, docker push идёт большими чанками. Общий подход к такой связке — в статье про Traefik как reverse proxy для Docker.

Установка и что получится в docker-compose.yml

Запускаете подготовку и установку:

sudo ./prepare
sudo ./install.sh --with-trivy

Флаг --with-trivy включает сканер уязвимостей — без него Trivy не поднимется и кнопка «Scan» в интерфейсе будет недоступна. Для базового приватного реестра с RBAC и сканированием этого достаточно, остальные опциональные компоненты (Notary, ChartMuseum) нужны только под конкретные сценарии.

После prepare в директории harbor/ появится готовый docker-compose.yml, а install.sh поднимет весь стек через docker compose up -d. Он состоит из отдельных контейнеров:

harbor-log          # централизованные логи всех сервисов
registry             # сам реестр образов (слой хранения)
registryctl          # управляющий API поверх registry
harbor-db            # PostgreSQL — метаданные проектов, пользователей, тегов
redis                # очереди и кэш для jobservice
harbor-portal        # веб-интерфейс (статика + API-прокси)
harbor-core           # основная бизнес-логика, auth, RBAC
harbor-jobservice     # фоновые задачи: репликация, garbage collection, сканы
trivy-adapter         # адаптер сканера уязвимостей
nginx                 # входной прокси, единственный сервис со внешними портами

Проверить, что всё поднялось:

docker compose ps

Все контейнеры должны быть в состоянии Up (для harbor-db и redisUp (healthy) через 20-30 секунд после старта). Если что-то не стартует — обычно проблема в правах на /data/harbor или в путях к сертификатам, которые не совпадают с тем, что указано в harbor.yml.

Заходите в браузере на https://harbor.example.com, логин admin, пароль — тот, что указали в harbor_admin_password.

Первые шаги: проекты, роли, push и сканирование

Harbor организует хранилище вокруг проектов — это аналог namespace, у каждого свои права доступа и настройки. Создайте первый проект через UI (Projects → New Project) или через API:

curl -u admin:ВАШ_ПАРОЛЬ -X POST "https://harbor.example.com/api/v2.0/projects" \
  -H "Content-Type: application/json" \
  -d '{"project_name": "backend", "public": false}'

Добавьте пользователей и назначьте роли внутри проекта: Project Admin, Maintainer, Developer, Guest, Limited Guest — каждая ограничивает набор действий (пуш/пул/удаление тегов/управление настройками). Это и есть RBAC, ради которого чаще всего выбирают Harbor вместо голого registry.

Логин и пуш образа с рабочей машины:

docker login harbor.example.com -u admin
docker tag myapp:latest harbor.example.com/backend/myapp:latest
docker push harbor.example.com/backend/myapp:latest

Сразу после пуша Trivy автоматически (если включено «Automatically scan images on push» в настройках проекта) просканирует образ и покажет в интерфейсе список найденных CVE с уровнями критичности. Это удобно проверить в CI — можно настроить пайплайн так, чтобы деплой блокировался при найденных Critical-уязвимостях, используя тот же API:

curl -u admin:ВАШ_ПАРОЛЬ "https://harbor.example.com/api/v2.0/projects/backend/repositories/myapp/artifacts/latest/scan/vulnerabilities"

Для CI/CD вместо обычного логина удобнее заводить robot accounts — сервисные учётки с ограниченным сроком жизни и правами только на конкретный проект, вместо прокидывания admin-пароля в переменные пайплайна.

Обслуживание: обновление, бэкап, garbage collection

Три вещи, о которых вспоминают обычно слишком поздно.

Garbage collection. Удаление тега не освобождает место сразу — слои остаются, пока не запущена сборка мусора (Administration → Garbage Collection, можно поставить по расписанию). На активном реестре имеет смысл запускать её еженедельно, иначе data_volume растёт даже после чистки старых тегов.

Бэкап. Резервировать нужно две вещи отдельно: содержимое data_volume (сами слои образов) и базу PostgreSQL (метаданные, пользователи, RBAC-настройки, история сканов):

docker exec harbor-db pg_dumpall -U postgres > harbor-db-backup-$(date +%F).sql
tar czf harbor-data-backup-$(date +%F).tar.gz /data/harbor

Без дампа базы восстановление одних только слоёв бесполезно — Harbor не поймёт, какие образы к какому проекту относятся. Общие принципы бэкапа томов разобраны в статье про резервное копирование Docker volume.

Обновление. Мажорные версии Harbor (например 2.11 → 2.12) требуют скачать новый офлайн-инсталлятор, остановить стек и прогнать ./prepare заново поверх обновлённого harbor.yml — храните свой конфиг отдельно от архива, чтобы не потерять его при следующей загрузке. Перед обновлением обязательно бэкапьте базу: миграции схемы иногда необратимы.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

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

Можно ли поставить Harbor без TLS, только для внутренней сети?

Технически да, через insecure-registries в /etc/docker/daemon.json на каждой машине-клиенте, но это лишняя ручная работа на каждый новый сервер и слабое место при компрометации внутренней сети. Проще выпустить сертификат, хотя бы self-signed, если Let's Encrypt недоступен.

Harbor можно поставить в Kubernetes вместо Docker Compose?

Да, есть официальный Helm-чарт — для кластеров это естественнее: переживает рестарт узла, легче масштабировать jobservice. Но для одного VPS и небольшой команды Compose проще в администрировании и не требует отдельного control plane.

Сколько ресурсов ест Harbor в простое, без активных пушей?

Заметную часть держат PostgreSQL и Redis с постоянными соединениями; в простое стек обычно укладывается в 1-1.5 GB RAM, но это ориентир — реальная цифра зависит от числа проектов и включённых компонентов вроде Trivy.

Что будет, если закончится место на диске под data_volume?

Registry начнёт отклонять push с ошибкой записи, уже загруженные образы останутся доступны для pull. Возможна и порча метаданных при обрыве записи в момент нехватки места — мониторинг свободного места стоит настроить заранее.

Нужен ли отдельный внешний load balancer перед Harbor?

Для одного сервера нет, встроенный nginx-контейнер справляется сам. Балансировщик нужен, если разворачиваете несколько Harbor-инстансов с репликацией для отказоустойчивости.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →