В одной из предыдущих статей, а именно в «Применение Portainer в CI/CD процессах», мы разобрались, что такое сборка Docker-образов и какие существуют варианты их хранения. В том примере использовался GitHub Docker Registry, а в своей работе я применяю хранилище в собственном Git-хостинге на базе Gitea.
Альтернативой хранению образов рядом с кодом является самостоятельный (self-hosted) репозиторий образов, например Harbor.
В этой статье мы разберём, что такое Harbor, как установить его на свой сервер и как начать им пользоваться.
Что такое Harbor?
Harbor — это open-source решение для хранения Docker-образов на собственном сервере (self-hosted). Оно активно используется как в небольших проектах, так и в корпоративном сегменте. Дополнительно Harbor интегрируется с Trivy, который выполняет сканирование образов на наличие уязвимостей.
Ключевые особенности
UI и API для управления репозиториями образов.
RBAC — разграничение прав на уровне проектов, пользователей и групп.
Аутентификация и SSO (LDAP, OIDC, Keycloak и т.д.).
Поддержка различных типов артефактов — не только контейнеров, но и Helm-чартов, OCI-артефактов и других.
Встроенный прокси-кэш для зеркалирования внешних регистри.
Встроенный сканер уязвимостей (Trivy).
Репликация образов между несколькими инстансами Harbor.
Подпись и проверка образов через Notary.
Аудит-лог действий пользователей.
Многоуровневая политика хранения (retention policies).
Системные требования
Минимально |
Рекомендовано |
|
---|---|---|
ЦПУ |
2 CPU |
4 CPU |
ОЗУ |
4 GB |
8 GB |
Диск |
40 GB |
160 GB |
Что такое Trivy
Trivy — это open-source сканер уязвимостей и ошибок конфигурации (misconfig) от Aqua Security. Он умеет проверять:
Образы контейнеров — как ОС-пакеты, так и зависимости приложений (npm, pip, Go, Java, Ruby и т.д.).
Файловые системы и репозитории — ищет уязвимые зависимости прямо в коде проекта.
Kubernetes и IaC-манифесты — Helm, Kubernetes, Terraform и другие, на предмет небезопасных настроек.
SBOM — читает и генерирует SPDX/CycloneDX, а также сканирует зависимости по готовому SBOM-файлу.
Секреты — базовый поиск «утёкших» ключей и токенов в коде.
Как Trivy интегрирован в Harbor
Trivy в Harbor интегрирован как отдельный сервис-адаптер, который:
Сканирует образы вручную по запросу или автоматически при push (если включена эта функция).
Сохраняет отчёт по CVE с классификацией уязвимостей по уровням LOW / MEDIUM / HIGH / CRITICAL.
Позволяет задать политику блокировки pull (например, запрет на загрузку образов с уязвимостями уровня High и выше).
Поддерживает allowlist (игнор-лист) на уровне проекта.
Деплой Harbor
Приступим к установке Harbor на собственный сервер.
Что понадобится:
Домен второго или третьего уровня.
VPS, соответствующий системным требованиям.
Reverse-proxy — в моём случае это будет Caddy.
Конфигурация Harbor
Подключаемся к серверу по SSH, создаём директорию и переходим в неё:
mkdir harbor && cd harbor
Скачиваем установщик. Возьмём последнюю актуальную версию — 2.13.2:
curl -LO https://github.com/goharbor/harbor/releases/download/v2.13.2/harbor-online-installer-v2.13.2.tgz
Распаковываем архив и переходим в директорию:
tar xzf harbor-online-installer-v2.13.2.tgz && cd harbor
Переименовываем пример конфигурационного файла и открываем его для редактирования:
cp harbor.yml.tmpl harbor.yml && nano harbor.yml
Изменяем следующие параметры:
hostname
— указываем домен безhttps://
.https
— закомментируем весь блок, так как SSL-сертификат и обработку HTTPS в нашем случае будет обеспечивать Caddy.external_url
— раскомментируем параметр и укажем домен с префиксомhttps
, например:https://<ваш_домен>
harbor_admin_password
— зададим сложный пароль администратора Harbor.database.password
— укажем пароль для базы данных.
Остальные параметры можно оставить по умолчанию или адаптировать под свои нужды.
Сохраняем изменения (CTRL+S
) и выходим из редактора (CTRL+X
).
Запускаем генерацию конфигурационных файлов с включённым Trivy:
sudo ./prepare --with-trivy
На этом этапе будут загружены и подготовлены необходимые конфигурационные файлы.
Правки docker-compose.yml
Так как у меня Caddy работает в отдельном Docker Compose, Harbor нужно подключить к той же сети, что и Caddy.
Открываем файл для редактирования:
nano docker-compose.yml
В самом конце, в блоке networks
, добавляем внешнюю сеть:
networks:
harbor:
external: false
caddy_net:
name: caddy_net
external: true
Далее находим сервис proxy
и вносим изменения:
Удаляем блок
ports
, чтобы прокси не слушал порт напрямую и был доступен только через Caddy.Меняем значение
container_name
наharbor-proxy
— так будет проще ориентироваться.В блок
networks
добавляем внешнюю сеть — в моём случае этоcaddy_net
.
Настройка Caddy
Открываем Caddyfile
и добавляем проксирование на nginx Harbor:
<ваш_домен> {
encode {
gzip
}
header {
X-Content-Type-Options "nosniff"
}
reverse_proxy harbor-proxy:8080
}
Так Caddy будет обрабатывать входящие HTTPS-запросы и передавать их на Harbor.
Запуск
Для запуска выполняем команду:
docker compose up -d
Дожидаемся, пока скачаются образы и запустятся все контейнеры.
Когда Harbor будет запущен, открываем в браузере адрес вашего домена.
Если всё прошло успешно, вас встретит страница с формой входа — значит, установка завершена и сервис готов к работе.

Проект и отправка образа
Деплой прошёл успешно, теперь создадим проект и загрузим в него Docker-образ.
Что такое проект в Harbor?
В Harbor проект — это отдельное пространство для хранения артефактов (Docker-образов, Helm-чартов и др.), с собственными настройками доступа, политиками хранения и сканирования.
Проекты позволяют:
Разделять образы по приложениям, командам или окружениям (dev, staging, prod).
Настраивать права доступа для отдельных пользователей или групп.
Включать или отключать автоматическое сканирование уязвимостей.
Управлять retention-политикой (удаление старых или неиспользуемых образов).
Это удобно, когда в одном Harbor работают сразу несколько команд или сервисов.
Создание проекта
В левом меню переходим в раздел "Projects" — откроется страница со списком проектов.

По умолчанию уже есть проект library
, но мы создадим свой. Нажимаем кнопку «New project».

В появившемся окне заполняем поля:
Название проекта — обязательно в нижнем регистре.
Уровень доступа — публичный или приватный.
Лимит дискового пространства — в гигабайтах или
-1
для отключения лимита.Переключатель Proxy Cache — при включении, если образа нет в вашем реестре, Harbor попытается получить его из другого источника и сохранить локально. Это удобно для часто используемых образов, но перед этим в разделе «Registries» нужно добавить источники.
После заполнения нажимаем «Ok» — проект появится в списке.

Переходим в созданный проект — откроется страница реестра с набором функций.

Чтобы получить подсказки по отправке образов, нажмите «PUSH COMMAND».

Здесь же указан адрес проекта в формате:
<ваш_домен>/<ваш_проект>/<название_образа>
Отправка образа в репозиторий
Для примера я воспользуюсь CI/CD-конфигурацией из статьи «Применение Portainer в CI/CD процессах».
Изначально у нас было так:
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
push: true
cache-from: type=registry,ref=ghcr.io/prodreams/tempproject:latest
cache-to: type=inline
tags: |
ghcr.io/prodreams/tempproject:latest
ghcr.io/prodreams/tempproject:${{ github.sha }}
Чтобы отправлять образы в Harbor, нужно заменить адреса и реквизиты на новые:
- name: Log in to Harbor Registry
uses: docker/login-action@v3
with:
registry: <ваш_домен>/<ваш_проект>
username: ${{ secrets.HARBOR_USER }}
password: ${{ secrets.HARBOR_PASSWORD }}
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
push: true
cache-from: type=registry,ref=<ваш_домен>/<ваш_проект>/tempproject:latest
cache-to: type=inline
tags: |
<ваш_домен>/<ваш_проект>/tempproject:latest
<ваш_домен>/<ваш_проект>/tempproject:${{ github.sha }}
Полный пример доступен в репозитории на GitHub: ссылка
После внесения изменений отправляем коммит в репозиторий и ждём завершения сборки образа:

Проверяем, что образ появился в репозитории Harbor:

Перейдя внутрь образа, можно запустить проверку на уязвимости (или включить автоматическую проверку в настройках проекта). В отчёте отобразятся все найденные уязвимости с указанием их уровня опасности:

Заключение
Harbor — это мощное и удобное решение для организации собственного Docker Registry, которое подойдёт как для небольших команд, так и для крупных компаний. Я лично планирую перенести в него все свои образы и настроить гибкое распределение доступов.
Мир open-source решений постоянно развивается, и впереди ещё множество интересных инструментов, которые можно опробовать и внедрить в свои продакшн-процессы.
А если вы хотите узнавать о таких инструментах и лучших практиках их применения — присоединяйтесь к нашему Telegram-каналу «Код на салфетке»!
Комментарии (6)
kozlyuk
14.08.2025 12:13По опыту использования Harbor как внутри компании, так и для публикации образов вовне.
Что хорошо:
Из коробки целостное решение, которое можно отдать пользователям, и они накликают, что им нужно.
Очистка неиспользуемых образов, политики очистки. Must have для хранилища образов с CI.
На уровне конфигов сделано расширяемо и ремонтопригодно.
Что плохо:
Убогий UI за пределами базовых задач. В таблицах ни сортировки, ни гибкого поиска, ни достаточной ширины столбцов (вы же знаете, что там будет SHA256!). Никакую аналитику: что сколько занимает, что качают, кто и откуда — толком не сделать, хотя отдельные данные видны.
Контроль доступа только через предопределенные роли в проектах. Например, нельзя ограничить версии образа, доступны конкретному пользователю, кроме как скопировать их в отдельный проект.
Нет групп пользователей, нет массовых действий.
До сих пор не проработан вариант раздельного доступа из internet и intranet.
Многие недостатки обходятся через кастомные конфиги или API при желании, но это уже не "из коробки все есть". Субъективно не нравится, что это комбайн, для частей которого всегда есть лучшие альтернативы.
proDream Автор
14.08.2025 12:13Отличное дополнение к статье! Для моих целей думаю это будет лучше хранения образов в Gitea, но если кто-то серьёзнее будет выбирать и наткнётся на статью и ваш комментарий, это может помочь. Спасибо =)
Arduinum
Очень удобное хранение контейнеров.
proDream Автор
Больше всего интересно разграничение доступов на те или иные образы по конкретным пользователям)