Создание своего Docker-репозитория
Обсуждаем два популярных решения для организации хранения контейнерных образов: Docker Registry и Nexus Repository.
Работа с Docker — это не только запуск контейнеров, но и продуманное хранение образов. Собственный репозиторий образов помогает ускорить работу с контейнерами, повысить безопасность и обеспечить независимость от внешних сервисов.
Зачем нужен свой репозиторий
Использовать публичные репозитории вроде Docker Hub удобно, но это не всегда удовлетворяет требованиям проекта. Например, проблемы могут возникать при низкой скорости загрузки, ограничениях доступа к интернету или наличии конфиденциальной информации в образах. В таких случаях целесообразно использовать собственное хранилище. Выбор между локальным и приватным репозиторием зависит от конкретных требований проекта и необходимого уровня безопасности.
Локальный репозиторий
Локальный репозиторий разворачивается на одном устройстве и доступен только с него. Это удобное решение для разработки и тестирования, когда образы нужны только на конкретной машине. Использование локального репозитория исключает зависимость от внешних сервисов и ускоряет работу, поскольку загрузка и выгрузка образов происходит без сетевых задержек.
Приватный репозиторий
Отличный инструмент для тех, кто заботится о безопасности. Он разворачивается на сервере и может быть доступен для нескольких пользователей по сети. Приватный репозиторий защищает образы от утечек и несанкционированного доступа, а также дает гибкость в управлении правами. Особенно это важно для компаний, где с контейнерами работают сразу несколько команд.
Упростить процесс развертывания, масштабирования и обслуживания контейнерной инфраструктуры можно благодаря Managed Kubernetes в Selectel. Это готовый к работе сервис с созданием кластеров за несколько минут, что обеспечивает быструю миграцию в облако. Развертывать и администрировать его самостоятельно не нужно — пользователь получает автоматизацию обслуживания кластеров Kubernetes «из коробки». Мы гарантируем доступность кластера и бесперебойную работу Control Plane по SLA и автомасштабируем кластеры до 1 500 нод, что помогает экономить до 70% бюджета.
Создание репозитория Docker
Существует два популярных решения для организации хранения контейнерных образов: Docker Registry и Nexus Repository.
- Docker Registry — официальное решение от Docker для развертывания собственного репозитория. Позволяет хранить, управлять и раздавать образы контейнеров в частной инфраструктуре. Это удобный вариант для тех, кто уже использует экосистему Docker и хочет минимизировать зависимость от внешних сервисов.
- Nexus Repository — универсальный менеджер артефактов, поддерживающий хранение не только Docker-образов, но и других типов данных, таких как библиотеки и пакеты для различных языков программирования. Этот продукт подходит для организаций, которым требуется централизованное хранилище для разных видов артефактов.
Рассмотрим создание приватных репозиториев Docker-образов с помощью каждого из решений.
Все команды приведены для Debian-based ОС.
Docker Registry
Подготовка системы
Если на вашем сервере еще не установлен сам Docker, выполните следующие действия.
- Обновите список пакетов:
sudo apt update
2. Установите Docker (docker.io):
sudo apt install docker.io --yes
3. Запустите Docker и включите его в список для автоматического запуска при старте системы:
sudo systemctl enable --now docker
Создание репозитория
Теперь создадим локальный репозиторий Docker-образов, который будет доступен только с данного устройства. Но это временная ситуация – после настройки он будет обладать SSL-сертификатом и аутентификацией и станет приватным репозиторием, к которому можно будет подключиться с другого устройства.
- Запустите контейнер с локальным Docker Registry, где:
- -d (detached mode) — запуск контейнера в фоновом режиме. Без этого флага контейнер работал бы в активной сессии терминала, и его завершение остановило бы работу реестра.
- -p 5000:5000 — перенаправление порта 5000 хоста на порт 5000 контейнера.
- —restart=always — автоматический перезапуск контейнера при сбоях или перезагрузке системы.
- —name TrexDockerRegistry — имя контейнера.
- registry:latest — указывает на использование последней версии Docker Registry.
docker run -d -p 5000:5000 --restart=always --name TrexDockerRegistry registry:latest
Теперь ваш локальный реестр доступен по адресу http://localhost:5000.
2. Проверьте доступность репозитория:
curl http://localhost:5000/v2/
Если контейнер запустился корректно, то в ответе должно прийти {} — это означает, что репозиторий работает, но в нем нет образов.
Подключение внешнего хранилища
Мы развернули репозиторий Docker Registry для хранения образов контейнеров, но сам по себе он тоже является контейнером. Это значит, что все загруженные образы будут удалены, когда контейнер остановится, так как по умолчанию используется временное файловое хранилище. Разберемся, как подключить постоянное хранилище и не терять образы при выключении контейнера.
Рассмотрим использование директории хоста в качестве постоянного хранилища.
- Создайте каталог на хосте:
mkdir -p /etc/docker/regrepo/
2. Удалите текущий контейнер Docker Registry:
docker container stop TrexDockerRegistry && docker container rm -v TrexDockerRegistry
3. Создайте новый контейнер с настройкой директорий:
docker run -d -p 5000:5000 --restart=always --name TrexDockerRegistry \
-v /etc/docker/regrepo:/var/lib/registry \
registry:latest
-v /etc/docker/regrepo:/var/lib/registry — монтирование хостовой директории /etc/docker/regrepo в директорию /var/lib/registry внутри контейнера. /var/lib/registry является директорией, в которой контейнер хранит всю информацию о Docker Registry, именно поэтому мы будем монтировать свою папку в нее.
Теперь при взаимодействии с хостовой директорией все изменения происходят и в контейнере, и наоборот.
Сохранение образа в репозиторий
Чтобы сохранить образ в наш репозиторий, выполните следующие действия.
- Скачайте образ на хост (например, nginx из публичного репозитория Docker Hub):
docker pull nginx:latest
2. Присвойте скачанному образу тег:
docker tag nginx:latest localhost:5000/nginx
3. Сохраните образ в репозиторий:
docker push localhost:5000/nginx
4. Проверьте, что в репозитории появился загруженный образ. Для этого просмотрите содержимое директории /etc/docker/regrepo:
ls /etc/docker/regrepo/docker/registry/v2/repositories
Если в выводе команды присутствует nginx, значит образ загружен в репозиторий успешно.
Настройка SSL
По умолчанию Docker Registry не поддерживает безопасное соединение, и это делает его недоступным для других узлов в сети. Чтобы обеспечить безопасную передачу данных и разрешить взаимодействие с репозиторием, необходимо настроить шифрование с использованием SSL-сертификатов.
Один из самых быстрых способов — сгенерировать самозаверенный сертификат. Однако такой сертификат не будет считаться действительным, так как он не подписан официальным центром сертификации (CA). В таком случае необходимо добавить Docker-реестр в список разрешенных на всех клиентских машинах или использовать сертификат от доверенного центра сертификации.
Рассмотрим процесс генерации самозаверенного сертификата и его подключения к Docker Registry.
- Установите OpenSSL:
sudo apt install openssl --yes
2. Создайте директорию, в которой будут храниться сертификаты:
mkdir -p /etc/docker/ssl/certregistry
3. Создайте сертификаты:
openssl req -x509 -new -nodes -days 365 \
-out /etc/docker/ssl/certregistry/public.pem \
-keyout /etc/docker/ssl/certregistry/private.key \
-subj "/C=RU/ST=SPb/L=SPb/O=Example/OU=Example/CN=example.local"
- -x509 — указывает, что нужно создать самоподписанный сертификат, а не запрос на подпись сертификата (CSR).
- -new — генерирует новый закрытый ключ и запрос на подпись сертификата (в нашем случае сразу превращается в самоподписанный сертификат благодаря флагу -x509).
- -nodes — указывает, что закрытый ключ не должен быть зашифрован паролем.
- -days 365 — срок действия сертификата в днях.
- -out /etc/docker/ssl/certregistry/public.pem — файл, в который будет записан открытый ключ (сертификат).
- -keyout /etc/docker/ssl/certregistry/private.key — файл, в который будет записан закрытый ключ.
- -subj «/C=RU/ST=SPb/L=SPb/O=Example/OU=Example/CN=example.local» — субъект сертификата.
- C=RU — страна (Country) = Россия (RU).
- ST=SPb — штат (State) = Санкт-Петербург (SPb).
- L=SPb — город (Locality) = Санкт-Петербург (SPb).
- O=Example — организация (Organization) = Example.
- OU=Example — подразделение организации (Organizational Unit) = Example.
CN=example.local — общее имя (Common Name). Обычно это доменное имя, для которого выдан сертификат.
4. Удалите текущий контейнер Docker Registry:
docker container stop TrexDockerRegistry && docker container rm -v TrexDockerRegistry
5. Создайте новый контейнер с настройкой сертификатов:
docker run -d -p 5000:5000 --restart=always --name TrexDockerRegistry \
-v /etc/docker/regrepo:/var/lib/registry \
-v /etc/docker/ssl/certregistry:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/public.pem \
-e REGISTRY_HTTP_TLS_KEY=/certs/private.key \
registry:latest
- -v /etc/docker/ssl/certregistry:/certs — монтирует каталог хоста с сертификатами /etc/docker/ssl/certregistry в папку контейнера /certs.
- -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/public.pem — устанавливает переменную среды REGISTRY_HTTP_TLS_CERTIFICATE, указывающую путь к публичному сертификату внутри контейнера.
- -e REGISTRY_HTTP_TLS_KEY=/certs/private.key — устанавливает переменную среды REGISTRY_HTTP_TLS_KEY, указывающую путь к закрытому ключу внутри контейнера.
6. Поскольку мы используем самоподписанный сертификат, при попытке подключения к репозиторию с другого хоста получим примерно следующую ошибку:
Error response from daemon: Get "https://[IP-address]:5000/v2/": x509: cannot validate certificate for [IP-address] because it doesn't contain any IP SANs
Чтобы хосты нашей сети могли подключаться к приватному репозиторию, который использует самоподписанный сертификат, необходимо на каждом из них выполнить некоторые манипуляции.Откройте на редактирование файл /etc/docker/daemon.json.
nano /etc/docker/daemon.json
Добавьте настройки:
{
"insecure-registries" : ["[IP-address_repository]:5000"]
}
[IP-address_repository] — IP-адрес сервера с развернутым Docker Registry.
Перезапустите сервис docker:
systemctl restart docker
Так мы сказали Docker, что доверяем репозиторию, указанному в параметре insecure-registry, несмотря на отсутствие «настоящего» сертификата.
Настройка аутентификации
По умолчанию Docker Registry не требует входа, и любой пользователь может загружать или скачивать образы. Чтобы ограничить доступ к репозиторию, добавим базовую аутентификацию с помощью htpasswd.
- Установите утилиту htpasswd, входящую в состав apache2-utils:
sudo apt install apache2-utils
2. Создайте директорию для хранения файла учетных данных:
mkdir -p /etc/docker/authregistry/
3. Создайте файл с парой логин/пароль:
htpasswd -Bbn [username] [password] > /etc/docker/authregistry/htpasswd
- -B — использование bcrypt для хеширования пароля (это самый безопасный метод).
- -b — передача пароля через командную строку вместо интерактивного ввода.
- -n — указание не запрашивать ввод пароля повторно.
- [username] — название учетной записи пользователя.
[password] — пароль.
При необходимости добавления нескольких пользователей, используйте >> вместо >, чтобы не перезаписывать файл, а добавлять в него новые данные.
4. Удалите текущий контейнер Docker Registry:
docker container stop TrexDockerRegistry && docker container rm -v TrexDockerRegistry
5. Создайте новый контейнер с настройкой аутентификации:
docker run -d -p 5000:5000 --restart=always --name TrexDockerRegistry \
-v /etc/docker/regrepo:/var/lib/registry \
-v /etc/docker/ssl/certregistry:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/public.pem \
-e REGISTRY_HTTP_TLS_KEY=/certs/private.key \
-v /etc/docker/authregistry:/auth \
-e REGISTRY_AUTH=htpasswd \
-e REGISTRY_AUTH_HTPASSWD_REALM="TrexDockerRegistry" \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
registry:latest
- -v /etc/docker/authregistry:/auth — монтирование хостовой директории /etc/docker/authregistry в директорию /auth контейнера для передачи файла с паролями.
- -e REGISTRY_AUTH=htpasswd — указание Docker Registry использовать базовую аутентификацию через htpasswd.
- -e REGISTRY_AUTH_HTPASSWD_REALM=»TrexDockerRegistry» — область (realm) для аутентификации, которую пользователи увидят при попытке войти в Docker Registry. Это текстовое поле помогает идентифицировать ресурс, к которому осуществляется доступ.
- -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd — путь до файла с паролями внутри контейнера.
На этом базовая настройка приватного репозитория Docker Registry завершена. Теперь у вас есть собственное хранилище Docker-образов!
Работа с приватным репозиторием
Теперь для работы с настроенным репозиторием необходимо пройти аутентификацию. Для этого на другом устройстве сети выполните следующую команду:
docker login [IP-address_repository]:5000
Укажите название учетной записи и пароль. При успешной аутентификации в терминал будет выведено сообщение Login Succeeded. Доступ к репозиторию открыт.
Для того чтобы скачать образ из конкретного репозитория, выполните следующую команду:
docker pull localhost:5000/nginx
Проверьте, что образ успешно загружен:
docker images
Вывод команды должен быть примерно такой:
REPOSITORY | TAG | IMAGE ID | CREATED | SIZE |
localhost:5000/nginx | latest | b52e0b094bc0 | 3 weeks ago | 192 MB |
registry | latest | 26b2eb03618e | 17 months ago | 25.4 MB |
Сохранение образа в приватный репозиторий выполняется командой:
docker push [IP-address_repository]:5000/nginx
Nexus Repository
Теперь рассмотрим процесс развертывания Nexus Repository с помощью Docker Compose.
Docker Compose — это инструмент для управления многоконтейнерными приложениями. Чтобы не запускать каждый контейнер вручную с длинными docker run командами, можно описать всю инфраструктуру в одном docker-compose.yml файле и запустить ее одной командой.
Подготовка системы
Если на вашем сервере еще не установлен сам Docker или Docker Compose, выполните следующие действия.
- Обновите список пакетов:
sudo apt update
2. Установите Docker (docker.io) и Docker Compose:
sudo apt install docker.io docker-compose --yes
3. Запустите сервис docker и включите его в список для автоматического запуска при старте системы:
sudo systemctl enable --now docker
Запуск Nexus Repository
- Создайте директорию для проекта:
mkdir ~/nexusrepo
2. Создайте в директории проекта директорию data и файл docker-compose.yml:
mkdir ~/nexusrepo/data
touch ~/nexusrepo/docker-compose.yml
3. Заполните файл docker-compose.yml следующим содержимым:
nexus:
image: sonatype/nexus3:latest
ports:
- "8081:8081"
- "8088:8088"
volumes:
- ./data:/nexus-data
- nexus — название сервиса, который будет запущен.
- image: sonatype/nexus3:latest — Docker-образ Sonatype Nexus, который будет использован для запуска контейнера.
- ports — раздел для публикации портов контейнера наружу, чтобы другие приложения могли взаимодействовать с ним.
- «8081:8081» — порт хоста 8081 сопоставлен с портом 8081 внутри контейнера. Мы сможем получить доступ к веб-интерфейсу Nexus по адресу http://[IP-address_host]:8081.
- «8088:8088» — порт хоста 8088 сопоставлен с портом 8088 внутри контейнера. Мы сможем получить доступ к Docker-репозиторию.
- volumes — раздел для монтирования томов, чтобы данные сохранялись вне контейнера.
./data:/nexus-data — хостовая директория ./data монтируется в директорию /nexus-data контейнера.
4. Запустите Nexus Repository:
docker-compose up -d
Отслеживать ход выполнения установки можно с помощью логов. Когда процесс будет завершен, в выводе команды docker-compose logs появится следующая информация:
nexus_1 | -------------------------------------------------
nexus_1 |
nexus_1 | Started Sonatype Nexus OSS 3.x.x
nexus_1 |
nexus_1 | -------------------------------------------------
5. После этого мы сможем перейти в веб-интерфейс Nexus, если введем в адресной строке браузера:
http://[IP-address_nexus]:8081

6. Чтобы узнать пароль администратора, установленный по умолчанию, просмотрите содержимое файла ~/nexus/data/admin.password:
cat ~/nexus/data/admin.password
Логин по умолчанию — admin.
7. Войдите в Nexus, используя полученные данные.
8. Измените пароль администратора, установленный по умолчанию.
В последних версиях Nexus такое окно автоматически появляется при первом входе в систему.
Создание репозитория
- Перейдите в настройки Nexus.
- Выберите вкладку Repositories.
- Нажмите на кнопку Create repository.

4. В списке типов репозиториев выберите docker (hosted).
5. Заполните необходимые данные:
- Name — название репозитория,
- HTTP — порт для подключения к репозиторию. Установите значение 8088,
- остальные поля можно оставить заполненными по умолчанию.

6. Нажмите на кнопку Create repository.
Настройка SSL
Чтобы устанавливать безопасное соединение с Nexus и созданными репозиториями, необходимо выполнить следующие действия.
- Перейти в настройки Nexus.
- В разделе Security открыть вкладку SSL Certificates.
- Нажать на кнопку Add Certificate.
- Загрузить SSL-сертификат или указать PEM.
Если у вас нет «настоящего» SSL-сертификата, можете создать самоподписанный. В таком случае не забудьте указать на клиентах в файле //6ef4e6a1-9d49-47ac-bfed-170f67a815cf.selcdn.net/etc/docker/daemon.json, что вы доверяете данному репозиторию.
Настройка аутентификации
При использовании Docker-репозитория на основе Nexus аутентификация является обязательной. Анонимный доступ возможен только для скачивания образов и при условии, что данная возможность включена в настройках репозитория (Settings – Repository – Repositories – [Your Repo] – Allow anonymous docker pull (Docker Bearer Token Realm required)).
Создать пользователей с доступом к Docker-репозиторию можно на вкладке Security – Users. Расширенные возможности разграничения доступа вы найдете на вкладках Security – Privileges и Security – Roles.
После настройки доступов подключение к репозиторию происходит стандартным способом:
docker login [IP-address_repository]:8088
Работа с приватным репозиторием
Сохранение образов в приватный Docker-репозиторий на основе Nexus выполняется так же, как при самостоятельном разворачивании Docker Registry.
Проверим, что образ действительно загружен на сервер.
- Перейдите в обозреватель контента Nexus (Browse server content).
- Выберите вкладку Browse.
- Нажмите на название своего репозитория.
На экране отобразится дерево каталогов, где вы можете просмотреть список сохраненных образов.

Загрузка образов из Docker-репозитория на основе Nexus ничем не отличается.
Для загрузки образа выполните команду:
docker pull [IP-address_nexus]:8088/nginx
Проверьте, что образ успешно загружен:
docker images
Container Registry в Selectel
Container Registry от Selectel — это облачный сервис, который позволяет легко хранить, управлять и развертывать контейнерные образы. Настроить реестр можно всего в пару кликов через удобную панель управления.
Перечислим несколько преимуществ использования Container Registry в Selectel.
- Простая настройка. Весь процесс развертывания выполняется через панель управления, где можно создать реестр буквально в несколько кликов. Также доступны интеграции через API Container Registry и Terraform для автоматизации.
- Максимальная производительность внутри экосистемы Selectel. Если ваши проекты уже работают на серверах Selectel, использование нашего облачного Container Registry обеспечит высокую скорость загрузки и скачивания образов без задержек.
- Надежность хранения данных. Система использует тройную репликацию данных, что гарантирует сохранность образов даже в случае сбоя оборудования.
- Гибкое управление версиями. В одном репозитории можно хранить несколько версий одного и того же Docker-образа, что упрощает откаты и управление релизами.
- Соответствие требованиям 152-ФЗ. Сервис отвечает требованиям Федерального закона № 152-ФЗ (УЗ-1), поэтому его можно использовать для хранения и обработки персональных данных пользователей с высоким уровнем защиты.
Selectel Container Registry — это простое, надежное и производительное решение для хранения контейнерных образов, которое легко интегрируется в существующую инфраструктуру.
Заключение
Создание собственного Docker-репозитория — важный шаг для повышения безопасности, независимости и эффективности работы с контейнерами. Вы можете выбрать подходящий тип репозитория в зависимости от потребностей вашего проекта: локальный репозиторий для повышения автономности или приватный для безопасной командной работы.