Приватный Docker-реестр на Rocky Linux 8 с хранением в Amazon S3

Если вам нужно хранить Docker-образы в закрытой, управляемой среде — разверните приватный Docker Registry на сервере с Rocky Linux 8 и используйте Amazon S3 как удалённое хранилище. В этом руководстве показан поэтапный процесс: настройка брандмауэра, установка Docker и Docker Compose, конфигурация registry и Nginx, настройка HTTPS через Let’s Encrypt, а также проверка работы и рекомендации по безопасности и эксплуатации.
Важно: перед началом убедитесь, что у вас есть домен, привязанный к серверу, и IAM-пользователь с правами для работы с S3.
Основные варианты использования
- Локальное хранение приватных образов для CI/CD и деплойментов.
- Централизованное управление версиями образов для команд разработчиков и операций.
- Снижение зависимости от публичных Docker Hub репозиториев.
Ключевые термины (1 строка)
- Registry: приватный сервер хранения Docker-образов.
- S3: объектное хранилище Amazon для долговременного хранения образов.
- Nginx: обратный прокси и точка авторизации для registry.
Преднастройка и требования
- Два сервера с Rocky Linux 8: один — хост registry, второй — клиент.
- Домен, указывающий на хост (в примерах — registry.example.com).
- Ненулевой пользователь с sudo на обоих серверах.
Примечание: все команды следует выполнять под пользователем с sudo-привилегиями. В примерах сохранены оригинальные имена доменов и путей для наглядности.
Шаг 1 — Конфигурация брандмауэра
Rocky Linux использует firewalld. На хосте проверьте статус:
$ sudo firewall-cmd --state
runningСписок текущих сервисов в публичной зоне:
$ sudo firewall-cmd --permanent --list-servicesРазрешите HTTP и HTTPS:
$ sudo firewall-cmd --permanent --add-service=http
$ sudo firewall-cmd --permanent --add-service=httpsПроверьте и перезагрузите правила:
$ sudo firewall-cmd --permanent --list-services
$ sudo firewall-cmd --reloadШаг 2 — Установка Docker и Docker Compose
Выполните эти шаги и на хосте, и на клиенте.
Установите репозиторий Docker и зависимости:
$ sudo dnf install yum-utils
$ sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repoУстановите Docker:
$ sudo dnf install docker-ce docker-ce-cli containerd.ioВключите демона Docker и добавьте пользователя в группу docker:
$ sudo systemctl enable docker --now
$ sudo usermod -aG docker $(whoami)Выйдите и войдите снова, чтобы изменения группы вступили в силу.
Установите Docker Compose (пример с версией 1.29.2, обновите при необходимости):
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ sudo curl -L https://raw.githubusercontent.com/docker/compose/1.29.2/contrib/completion/bash/docker-compose -o /etc/bash_completion.d/docker-compose
$ source ~/.bashrcШаг 3 — Конфигурация Docker Registry
Создание директорий пользователя
$ mkdir ~/docker-registry
$ cd ~/docker-registry
$ mkdir auth
$ mkdir logsСоздание Amazon S3 bucket
Вы можете хранить данные локально или в облаке. В этом руководстве используется Amazon S3.
Рекомендованные настройки бакета:
- ACL отключена.
- Публичный доступ запрещён.
- Версионирование отключено (по желанию включайте при требованиях версии).
- Шифрование включено через управляемые ключи S3 (SSE-S3).
- Object lock отключён.
Создайте IAM пользователя и примените политику, аналогичную этой (замените S3_BUCKET_NAME):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetBucketLocation",
"s3:ListBucketMultipartUploads"
],
"Resource": "arn:aws:s3:::S3_BUCKET_NAME"
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject",
"s3:ListMultipartUploadParts",
"s3:AbortMultipartUpload"
],
"Resource": "arn:aws:s3:::S3_BUCKET_NAME/*"
}
]
}Запишите Access Key, Secret Key и регион бакета — они понадобятся позже.
Создание файла docker-compose.yml
Откройте и вставьте следующий файл (в текущем виде). Не забудьте заменить секреты и имя бакета на свои значения в рабочей среде.
version: '3.3'
services:
registry:
image: registry:2
restart: always
environment:
- REGISTRY_STORAGE=s3
- REGISTRY_STORAGE_S3_REGION=us-west-2
- REGISTRY_STORAGE_S3_BUCKET=hf-docker-registry
- REGISTRY_STORAGE_S3_ENCRYPT=true
- REGISTRY_STORAGE_S3_CHUNKSIZE=5242880
- REGISTRY_STORAGE_S3_SECURE=true
- REGISTRY_STORAGE_S3_ACCESSKEY=AKIA3FIG4NVFCJ6STMUA
- REGISTRY_STORAGE_S3_SECRETKEY=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
- REGISTRY_STORAGE_S3_V4AUTH=true
- REGISTRY_STORAGE_S3_ROOTDIRECTORY=/image-registry
- REGISTRY_STORAGE_CACHE_BLOBDESCRIPTOR=inmemory
- REGISTRY_HEALTH_STORAGEDRIVER_ENABLED=false
nginx:
image: "nginx:alpine"
ports:
- 443:443
links:
- registry:registry
volumes:
- ./auth:/etc/nginx/conf.d
- ./auth/nginx.conf:/etc/nginx/nginx.conf:ro
- ./logs:/var/log/nginx
- /etc/letsencrypt:/etc/letsencryptЧто важно здесь:
- Используется образ registry:2 — фиксирование мажорной версии снижает риск несовместимости.
- Переменные окружения конфигурируют использование S3 как storage backend.
- REGISTRY_STORAGE_S3_CHUNKSIZE рекомендуем > 5MB.
- REGISTRY_HEALTH_STORAGEDRIVER_ENABLED=false — отключает проверку хранилища, обход известной ошибки драйвера.
- Nginx проксирует трафик по 443 порту и монтирует локальные конфиги и сертификаты.
Настройка HTTP-аутентификации
Установите утилиты для создания htpasswd-файлов и создайте файл паролей:
$ sudo dnf install httpd-tools
$ htpasswd -Bc ~/docker-registry/auth/nginx.htpasswd user1Флаг -B указывает использовать bcrypt, флаг -c — создать файл. Для добавления новых пользователей используйте команду без -c.
Шаг 4 — Установка SSL (Let’s Encrypt)
Установите EPEL и certbot:
$ sudo dnf install epel-release
$ sudo dnf install certbotСгенерируйте сертификат (замените email и домен на свои):
$ sudo certbot certonly --standalone --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m [email protected] -d registry.example.comСертификаты будут в /etc/letsencrypt/live/registry.example.com.
Создайте Diffie-Hellman параметры:
$ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096Проверьте тестовое обновление сертификата:
$ sudo certbot renew --dry-runСкопируйте dhparam.pem в директорию, которую монтирует Nginx:
$ sudo cp /etc/ssl/certs/dhparam.pem ~/docker-registry/authШаг 5 — Конфигурация Nginx
Создайте ~/docker-registry/auth/nginx.conf и вставьте следующий конфиг (оставлен как в примере):
events {
worker_connections 1024;
}
http {
upstream docker-registry {
server registry:5000;
}
## Set a variable to help us decide if we need to add the
## 'Docker-Distribution-Api-Version' header.
## The registry always sets this header.
## In the case of nginx performing auth, the header is unset
## since nginx is auth-ing before proxying.
map $upstream_http_docker_distribution_api_version $docker_distribution_api_version {
'' 'registry/2.0';
}
server {
listen 443 ssl http2;
server_name registry.example.com;
# SSL
ssl_certificate /etc/letsencrypt/live/registry.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/registry.example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/registry.example.com/chain.pem;
access_log /var/log/nginx/registry.access.log;
error_log /var/log/nginx/registry.error.log;
# Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers on;
ssl_ecdh_curve X25519:prime256v1:secp384r1:secp521r1;
ssl_session_cache shared:SSL:10m;
ssl_dhparam /etc/nginx.d/conf.d/dhparam.pem;
resolver 8.8.8.8;
# disable any limits to avoid HTTP 413 for large image uploads
client_max_body_size 0;
# required to avoid HTTP 411: see Issue #1486 (https://github.com/moby/moby/issues/1486)
chunked_transfer_encoding on;
location /v2/ {
# Do not allow connections from docker 1.5 and earlier
# docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents
if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) {
return 404;
}
# To add basic authentication to v2 use auth_basic setting.
auth_basic "Registry realm";
auth_basic_user_file /etc/nginx/conf.d/nginx.htpasswd;
## If $docker_distribution_api_version is empty, the header is not added.
## See the map directive above where this variable is defined.
add_header 'Docker-Distribution-Api-Version' $docker_distribution_api_version always;
proxy_pass http://docker-registry;
proxy_set_header Host $http_host; # required for docker client's sake
proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 900;
}
}
}Примените SELinux-булеву переменную, чтобы Nginx мог подключаться к сети:
$ sudo setsebool -P httpd_can_network_connect onШаг 6 — Запуск Docker Registry
Запустите в каталоге ~/docker-registry:
$ docker-compose up -dПроверьте статусы контейнеров:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
88d6addc1687 nginx:alpine "/docker-entrypoint.…" 5 minutes ago Up 5 minutes 80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp docker-registry_nginx_1
2b112edc1c72 registry:2 "/entrypoint.sh /etc…" 5 minutes ago Up 5 minutes 5000/tcp docker-registry_registry_1Вход в реестр:
$ docker login -u=testuser -p=testpassword https://registry.example.comПроверка через браузер: откройте https://registry.example.com/v2/ — будет запрошена аутентификация и возвращён пустой JSON: {}.
Проверка с curl:
$ curl -u testuser -X GET https://registry.nspeaks.xyz/v2/
Enter host password for user 'testuser':
{}Пример загрузки и публикации образа:
$ docker pull ubuntu:latest
$ docker tag ubuntu:latest registry.example.com/ubuntu2004
$ docker push registry.example.com/ubuntu2004Проверка каталога репозиториев:
$ curl -u testuser -X GET https://registry.nspeaks.xyz/v2/_catalog
Enter host password for user 'testuser':
{"repositories":["ubuntu2004"]}Шаг 7 — Доступ и использование с клиентской машины
На клиенте выполните вход и загрузку образа:
$ docker login -u=testuser -p=testpassword https://registry.example.com
$ docker pull registry.example.com/ubuntu2004
$ docker run -it registry.example.com/ubuntu2004 /bin/bashВнутри контейнера можно проверить релиз ОС:
root@a2da49fdbea9$ cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.4 LTS (Focal Fossa)"
...Теперь клиенты могут подтягивать образы из вашего приватного реестра.
Отладка и распространённые ошибки
- Ошибка авторизации 401/403
- Проверьте файл nginx.htpasswd и соответствие логина/пароля.
- Убедитесь, что auth_basic_user_file указывает на правильный путь внутри контейнера.
- Ошибка подключения к S3 (исключения при push)
- Проверьте ACCESSKEY/SECRETKEY и регион. Убедитесь, что IAM-политика содержит нужные права.
- Попробуйте временно установить REGISTRY_STORAGE_S3_V4AUTH=false при проблемах с сигнатурой.
- Ошибка 413 Request Entity Too Large
- Убедитесь, что client_max_body_size установлен в 0 в конфиге Nginx.
- Сертификаты Let’s Encrypt не обновляются
- Проверьте, что certbot может получить доступ к порту 80 при dry-run и что cron/timers работают.
- Непредвиденные остановки контейнеров
- Просмотрите docker logs для контейнеров registry и nginx. Проверьте доступ к S3 и права на монтируемые директории.
Альтернативные подходы и когда они подходят
- Хранение образов локально на диске сервера — проще и дешевле, но не масштабируется при нескольких репликах.
- Использование управляемых решений (Amazon ECR, Harbor) — если важны интеграция с облаком, IAM и упрощённая поддержка.
- Использование Redis для кеша дескрипторов вместо in-memory — полезно при нескольких экземплярах registry.
Когда не использовать этот подход:
- Если вам нужен встроенный RBAC и управление пользователями на уровне реестра — рассмотрите Harbor или ECR.
- Если требуется хранение артефактов разных типов (не только Docker) — специализированные решения лучше.
Модель зрелости развертывания (уровни)
- Уровень 0 — Proof of Concept: single-node, самоподписанные сертификаты.
- Уровень 1 — Production минимальный: Nginx, Let’s Encrypt, S3, резервное копирование облака.
- Уровень 2 — Высокая доступность: кластер registry, shared cache (Redis), мониторинг и SLO.
- Уровень 3 — Enterprise: кластерный контроллер, централизованный RBAC, отдельный CI-пайплайн для сканирования образов.
Контрольный список перед вводом в эксплуатацию
- Доменные записи указывают на хост.
- Certbot сгенерировал валидный сертификат и успешен dry-run.
- Фаерволл открыт для 443 порта.
- Nginx корректно проксирует /v2/ к registry:5000.
- htpasswd файл создан и монтируется в контейнер.
- IAM-пользователь имеет права доступа к S3-бакету.
- Резервная стратегия для метаданных и критичных артефактов.
Чек-листы для ролей
Администратор инфраструктуры:
- Подготовить сервер и домен.
- Настроить firewalld и SELinux.
- Установить Docker и Docker Compose.
DevOps-инженер:
- Настроить docker-compose, S3 и переменные окружения.
- Поддерживать процесс обновления и ротации секретов.
Разработчик:
- Тестировать push/pull образов.
- Использовать CI/CD для автоматической загрузки образов в реестр.
Мини-методология развёртывания (5 шагов)
- Подготовка окружения (единый домен, DNS, пользователи).
- Установка Docker, Compose, настройка S3 и IAM.
- Настройка Nginx и HTTPS (Certbot + dhparam).
- Запуск сервисов и проверка (docker-compose up, docker login, push/pull).
- Внедрение мониторинга и процедур обновления/бэкапа.
Примеры тест-кейсов и критерии приёмки
Критерии приёмки:
- Аутентификация: пользователь может войти в registry и получить код 200 для /v2/.
- Push/Pull: успешный push образа > 100 МБ и успешный pull на клиенте.
- HTTPS: сертификат валидный, тест certbot renew –dry-run проходит.
- Сетевая безопасность: доступ по 443 открыт, а по 5000 — только локально в Docker-сети.
Тест-кейсы:
- Попытка загрузки образа без авторизации должна приводить к 401.
- Имитация ошибки S3 (неверные ключи) должна привести к логам с причинами отказа.
Меры безопасности и защита данных
- Всегда используйте HTTPS и безопасные TLS-настройки (как в примере Nginx).
- Не храните секреты (ACCESSKEY/SECRETKEY) в репозитории. Используйте менеджеры секретов или переменные окружения с ограниченным доступом.
- Ограничьте доступ к S3-бакету по принципу наименьших привилегий.
- Включите логирование доступа и мониторьте неудачные попытки аутентификации.
- Планируйте регулярную ротацию ключей и паролей.
Приватность и соответствие требованиям (коротко)
- Если вы храните образы, содержащие персональные данные или конфиденциальные артефакты, убедитесь в соответствии с внутренними политиками и локальными требованиями по защите данных.
- Для GDPR: хранение образов как таковое обычно не подпадает под персональные данные, но в образах не храните открытые секреты и персональную информацию.
Миграция и совместимость
- При переносе registry между бэкендами (локально → S3) убедитесь, что структура rootdirectory и права объектов совпадают.
- При обновлении версии registry тестируйте в staging: registry:2.* поддерживает совместимость внутри мажорной версии, но мажорный апгрейд может ломать API.
Резюме и дальнейшие шаги
- Этот процесс даёт управляемый приватный реестр с безопасным доступом и хранением образов в S3.
- Для production-готовности добавьте мониторинг (Prometheus + Grafana), backup/restore план и CI-интеграцию.
Полезные дальнейшие улучшения:
- Автоматизация развёртывания через Terraform/Ansible.
- Интеграция с системой сканирования уязвимостей образов.
- Переход на Harbor или ECR при необходимости встроенного RBAC и политики хранения.
Если у вас остались вопросы по конкретным шагам, предоставьте вывод команд или логи — и я помогу диагностировать проблему.
Похожие материалы
Несколько аккаунтов Skype: Multi Skype Launcher
Журнал для работы: повысить продуктивность
Персональные звуки уведомлений на Android
Скачивание шоу Hulu для офлайн‑просмотра
Microsoft Start: персонализированная новостная лента