Гид по технологиям

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

• 7 min read • DevOps • Обновлено 25 Nov 2025
Приватный Docker-реестр на Rocky Linux 8
Приватный Docker-реестр на Rocky Linux 8

Иллюстрация архитектуры: приватный Docker-реестр за Nginx с хранением образов в 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

Что важно здесь:

  1. Используется образ registry:2 — фиксирование мажорной версии снижает риск несовместимости.
  2. Переменные окружения конфигурируют использование S3 как storage backend.
  3. REGISTRY_STORAGE_S3_CHUNKSIZE рекомендуем > 5MB.
  4. REGISTRY_HEALTH_STORAGEDRIVER_ENABLED=false — отключает проверку хранилища, обход известной ошибки драйвера.
  5. 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)"
...

Теперь клиенты могут подтягивать образы из вашего приватного реестра.


Отладка и распространённые ошибки

  1. Ошибка авторизации 401/403
    • Проверьте файл nginx.htpasswd и соответствие логина/пароля.
    • Убедитесь, что auth_basic_user_file указывает на правильный путь внутри контейнера.
  2. Ошибка подключения к S3 (исключения при push)
    • Проверьте ACCESSKEY/SECRETKEY и регион. Убедитесь, что IAM-политика содержит нужные права.
    • Попробуйте временно установить REGISTRY_STORAGE_S3_V4AUTH=false при проблемах с сигнатурой.
  3. Ошибка 413 Request Entity Too Large
    • Убедитесь, что client_max_body_size установлен в 0 в конфиге Nginx.
  4. Сертификаты Let’s Encrypt не обновляются
    • Проверьте, что certbot может получить доступ к порту 80 при dry-run и что cron/timers работают.
  5. Непредвиденные остановки контейнеров
    • Просмотрите 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 шагов)

  1. Подготовка окружения (единый домен, DNS, пользователи).
  2. Установка Docker, Compose, настройка S3 и IAM.
  3. Настройка Nginx и HTTPS (Certbot + dhparam).
  4. Запуск сервисов и проверка (docker-compose up, docker login, push/pull).
  5. Внедрение мониторинга и процедур обновления/бэкапа.

Примеры тест-кейсов и критерии приёмки

Критерии приёмки:

  • Аутентификация: пользователь может войти в 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 и политики хранения.

Если у вас остались вопросы по конкретным шагам, предоставьте вывод команд или логи — и я помогу диагностировать проблему.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Несколько аккаунтов Skype: Multi Skype Launcher
Программное обеспечение

Несколько аккаунтов Skype: Multi Skype Launcher

Журнал для работы: повысить продуктивность
Productivity

Журнал для работы: повысить продуктивность

Персональные звуки уведомлений на Android
Android.

Персональные звуки уведомлений на Android

Скачивание шоу Hulu для офлайн‑просмотра
Стриминг

Скачивание шоу Hulu для офлайн‑просмотра

Microsoft Start: персонализированная новостная лента
Новости

Microsoft Start: персонализированная новостная лента

Как изменить имя в Epic Games быстро
Гайды

Как изменить имя в Epic Games быстро