[Перевод] Как сделать своё хранилище образов контейнеров
Примечание переводчика: Алекс Плютау (Alex Pliutau), эксперт в области облачных решений и DevOps, написал руководство по container registry (далее также — реестр), где описывает процесс его самостоятельного хостинга. Автор делится полезной информацией о том, как создать собственный container registry и управлять им. Передаём ему слово.

Что такое образ контейнера?
Прежде чем говорить о хранилище образов контейнеров, давайте разберёмся, что такое образ контейнера. Это пакет, содержащий все файлы, библиотеки и конфигурации, необходимые для запуска контейнера. Он состоит из слоёв, где каждый из них представляет собой набор преобразований, которые произошли с файловой системой в результате добавления, удаления или изменения файлов.
Самый распространённый способ создания образов контейнеров опирается на Dockerfile:
# build an image
docker build -t pliutau/hello-world:v0 .
# check the images locally
docker images
# REPOSITORY TAG IMAGE ID CREATED SIZE
# hello-world latest 9facd12bbcdd 22 seconds ago 11MB
Команда docker build
на локальной машине собирает образ контейнера. Команда docker images
выводит список всех образов. Но что, если нужно с кем-то поделиться образом или использовать его на другой машине? Вот тут-то в игру и вступает container registry.
Что такое container registry?
Container registry — это каталогизированное хранилище, из которого можно извлекать образы контейнеров и куда их можно записывать. Образы группируются в репозитории — коллекции связанных образов с одинаковым названием. Например, в реестре от Docker Hub nginx представляет собой репозиторий, содержащий различные версии образов nginx.
Некоторые реестры являются публичными, то есть размещённые в них образы доступны любому пользователю интернета. Публичные реестры вроде Docker Hub отлично подходят для хостинга Open Source-проектов.
С другой стороны, приватные реестры обеспечивают безопасность и конфиденциальность для корпоративного хранилища образов вне зависимости от его расположения — в облаке или on-premise. Такие приватные реестры часто включают в себя расширенные функции безопасности и техническую поддержку. Выбор приватных реестров достаточно богат — Amazon ECR, GCP Artifact Registry, GitHub Container Registry. Docker Hub также поддерживает приватные репозитории.
Разработчики взаимодействуют с container registry с помощью команд docker push
и docker pull
:
docker push docker.io/pliutau/hello-world:v0
# В случае Docker Hub можно пропустить часть, относящуюся к registry.
docker push pliutau/hello-world:v0
Структура URL-адреса образа контейнера:
docker pull docker.io/pliutau/hello-world:v0@sha256:dc11b2...
↓ ↓ ↓ ↓
реестр репозиторий тег дайджест
Зачем делать свой container registry?
Иногда вместо того, чтобы полагаться на готовое решение от провайдера (например, от AWS или GCP), разумно завести собственное хранилище образов. Плюсы такого подхода в том, что реестр остаётся полностью под вашим контролем — вы не зависите от сторонних вендоров. В некоторых регулируемых отраслях это обязательное требование.
Собственный реестр работает на ваших серверах. Вы можете контролировать его конфигурацию и место размещения образов контейнеров. В то же время это сопряжено с затратами на обслуживание и защиту.
Существуют различные решения с открытым исходным кодом для организации container registry. Наиболее популярное из них называется registry. Оно также упаковано в контейнер и позволяет хранить и распространять образы контейнеров и артефакты.
Чтобы запустить registry на сервере:
Установите Docker и Docker Compose на сервер.
Настройте и запустите контейнер с registry.
Запустите nginx для обработки TLS и перенаправления запросов в контейнер с registry.
Установите TLS-сертификаты и настройте домен.
Сервер
Можно воспользоваться любым сервером, который поддерживает Docker, например дроплетом DigitalOcean с Ubuntu. Для этой демонстрации я использовал виртуальную машину с Ubuntu в Google Compute Engine:
neofetch
# OS: Ubuntu 20.04.6 LTS x86_64
# CPU: Intel Xeon (2) @ 2.200GHz
# Memory: 3908MiB
Теперь в виртуальную машину нужно установить Docker и Docker Compose. Docker Compose необязателен, но упрощает управление мультиконтейнерными приложениями:
# Устанавливаем docker и docker-compose.
sudo snap install docker
# Проверяем правильность установки.
docker --version
docker-compose –version
Настройка container registry
Приведённый ниже файл compose.yaml создаёт контейнер реестра с томом для хранения образов и томом для хранения файла паролей.
services:
registry:
image: registry:latest
environment:
REGISTRY_AUTH: htpasswd
REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
REGISTRY_AUTH_HTPASSWD_PATH: /auth/registry.password
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
volumes:
# Монтируем файл паролей.
- ./registry/registry.password:/auth/registry.password
# Монтируем директорию с данными.
- ./registry/data:/data
ports:
- 5000
Файл паролей, заданный в REGISTRY_AUTH_HTPASSWD_PATH
, используется для аутентификации пользователей, когда те загружают образы в реестр или извлекают их из него. Создайте файл паролей с помощью команды htpasswd
, а также директорию для хранения образов:
mkdir -p ./registry/data
# Устанавливаем htpasswd.
sudo apt install apache2-utils
# Создаём файл password. Имя пользователя: busy, пароль: bee.
htpasswd -Bbn busy bee > ./registry/registry.password
Теперь можно запустить контейнер registry. Если всё работает как надо, вы увидите следующее сообщение:
docker-compose up
# registry | level=info msg="listening on [::]:5000"
SSL-сертификаты и nginx
Как уже говорилось, можно использовать nginx для обработки TLS-трафика и перенаправления запросов к контейнеру registry. Docker registry для работы требуется действительный доверенный SSL-сертификат. Можно воспользоваться сервисом вроде Let’s Encrypt или получить его вручную. Убедитесь, что доменное имя указывает на ваш сервер (в моём случае registry.pliutau.com). Для этой статьи я получил сертификаты с помощью certbot и поместил их в каталог ./nginx/certs
.
Поскольку Docker registry работает в контейнере, nginx тоже можно запустить в контейнере. Добавим соответствующий сервис в файл compose.yaml:
services:
registry:
# ...
nginx:
image: nginx:latest
depends_on:
- registry
volumes:
# Монтируем конфигурацию nginx.
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
# Монтируем сертификаты, полученные от Let's Encrypt.
- ./nginx/certs:/etc/nginx/certs
ports:
- "443:443"
А вот пример файла конфигурации nginx.conf:
worker_processes auto;
events {
worker_connections 1024;
}
http {
upstream registry {
server registry:5000;
}
server {
server_name registry.pliutau.com;
listen 443 ssl;
ssl_certificate /etc/nginx/certs/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/privkey.pem;
location / {
# Важный параметр для больших образов.
client_max_body_size 1000m;
proxy_pass http://registry;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 900;
}
}
}
Всё готово
После этих шагов можно запускать контейнеры registry и nginx:
docker-compose up
Входим в реестр:
docker login registry.pliutau.com
# Username: busy
# Password: bee
# Login Succeeded
Всё! Теперь можно собирать образы и пушить их в собственный реестр:
docker build -t registry.pliutau.com/pliutau/hello-world:v0 .
docker push registry.pliutau.com/pliutau/hello-world:v0
# v0: digest: sha256:a56ea4... size: 738
На самом сервере загруженные образы хранятся в директории data:
ls -la ./registry/data/docker/registry/v2/repositories/
Другие варианты
Следуя приведённому выше примеру, собственный реестр также можно запустить в Kubernetes. Или можно воспользоваться managed-сервисом вроде Harbor — Open Source-реестром с продвинутыми возможностями в области безопасности, совместимым с Docker и Kubernetes.
Тем, кто предпочитает работать через пользовательский интерфейс, рекомендую обратить внимание на проекты вроде joxit/docker-registry-ui (его также можно запустить в отдельном контейнере).
Заключение
С собственным реестром вы получаете полный контроль над ним. В то же время возникают дополнительные издержки на обслуживание и защиту.
Какими бы ни были причины завести собственный реестр, теперь вы знаете, как это сделать. Сравнивайте различные варианты, выбирайте тот, который лучше всего соответствует вашим потребностям.
Исходники для этой статьи доступны на GitHub. А тех, кто предпочитает видео, приглашаем в наш канал на YouTube.
P. S.
Читайте также в нашем блоге:
Как собрать Linux-контейнер с нуля и без Docker
Что не так с chroot: почему для контейнеров используется именно pivot_root
Как мы устанавливали community-чарт Sentry в Kubernetes
Неиспользуемые остатки образов в Docker: как удалить зомби-слои и защитить секреты