Home » Создание приватного Docker реестра на Ubuntu 24
Создание приватного Docker реестра на Ubuntu 24

Создание приватного Docker реестра на Ubuntu 24

Если вы когда-нибудь задавались вопросом, куда деваются все эти образы Docker после сборки, и почему пулить их из Docker Hub через медленный интернет — не самая лучшая идея для продакшена, то эта статья для вас. Создание собственного приватного Docker реестра — это не просто прихоть параноика, а реальная необходимость для любого серьёзного проекта. Особенно когда речь идёт о корпоративной разработке, где безопасность и контроль над артефактами критически важны.

Сегодня разберём, как поднять собственный Docker Registry на Ubuntu 24, настроить его правильно и не наступить на грабли, которые поджидают каждого второго админа. Приготовьтесь к практике — будет много команд, конфигов и полезных трюков.

Зачем нужен приватный Docker реестр?

Представьте ситуацию: у вас есть микросервисная архитектура из 20+ сервисов, каждый обновляется по несколько раз в день, а команда разработчиков разбросана по всему миру. Загружать каждый раз образы по 500МБ из Docker Hub — это не только медленно, но и дорого в плане трафика. Плюс, не все образы должны быть публичными.

Вот основные причины, почему стоит заморочиться с собственным реестром:

  • Скорость — образы хранятся в вашей сети, пулятся мгновенно
  • Безопасность — никто посторонний не получит доступ к вашим образам
  • Контроль — вы сами решаете, кто и к чему имеет доступ
  • Экономия трафика — особенно актуально для дата-центров с лимитированным внешним каналом
  • Compliance — многие корпоративные политики безопасности требуют полного контроля над артефактами

Как это работает под капотом?

Docker Registry — это HTTP API-сервис, который работает по протоколу Docker Registry HTTP API V2. Когда вы делаете docker push или docker pull, клиент общается с реестром через REST API, передавая слои образов в виде блобов.

Архитектура довольно простая:

  • Storage backend — где физически хранятся образы (filesystem, S3, Google Cloud Storage, etc.)
  • Authentication — кто может читать/писать образы
  • TLS termination — для безопасного соединения
  • Reverse proxy — для балансировки и кэширования (обычно nginx)

Пошаговая настройка приватного реестра

Для начала вам понадобится сервер на Ubuntu 24. Если у вас его ещё нет, можно заказать VPS или выделенный сервер. Рекомендую минимум 2GB RAM и 20GB места на диске для старта.

Шаг 1: Устанавливаем Docker

# Обновляем пакеты
sudo apt update && sudo apt upgrade -y

# Устанавливаем необходимые пакеты
sudo apt install -y ca-certificates curl gnupg lsb-release

# Добавляем официальный GPG ключ Docker
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# Добавляем репозиторий Docker
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Устанавливаем Docker
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

# Добавляем пользователя в группу docker
sudo usermod -aG docker $USER

# Включаем автозапуск Docker
sudo systemctl enable docker
sudo systemctl start docker

Шаг 2: Создаём структуру директорий

# Создаём директории для нашего реестра
sudo mkdir -p /opt/docker-registry/{data,auth,certs,config}

# Назначаем правильные права
sudo chown -R $USER:$USER /opt/docker-registry

Шаг 3: Настраиваем SSL сертификаты

Без HTTPS Docker Registry работать не будет (ну, технически будет, но только локально). Есть несколько вариантов:

# Вариант 1: Самоподписанный сертификат (для тестирования)
openssl req -newkey rsa:4096 -nodes -sha256 -keyout /opt/docker-registry/certs/registry.key -x509 -days 365 -out /opt/docker-registry/certs/registry.crt

# Вариант 2: Let's Encrypt (для продакшена)
sudo apt install -y certbot
sudo certbot certonly --standalone -d your-registry.domain.com

# Копируем сертификаты Let's Encrypt
sudo cp /etc/letsencrypt/live/your-registry.domain.com/fullchain.pem /opt/docker-registry/certs/registry.crt
sudo cp /etc/letsencrypt/live/your-registry.domain.com/privkey.pem /opt/docker-registry/certs/registry.key
sudo chown $USER:$USER /opt/docker-registry/certs/*

Шаг 4: Настраиваем аутентификацию

# Устанавливаем htpasswd для создания файла паролей
sudo apt install -y apache2-utils

# Создаём файл с пользователями (замените username на нужное имя)
htpasswd -Bbn username password > /opt/docker-registry/auth/htpasswd

# Добавляем ещё пользователей
htpasswd -Bn additional_user >> /opt/docker-registry/auth/htpasswd

Шаг 5: Создаём конфигурационный файл

# Создаём config.yml
cat > /opt/docker-registry/config/config.yml << 'EOF'
version: 0.1
log:
  accesslog:
    disabled: false
  level: info
  formatter: text
storage:
  filesystem:
    rootdirectory: /var/lib/registry
    maxthreads: 100
  delete:
    enabled: true
  cache:
    blobdescriptor: inmemory
http:
  addr: :5000
  headers:
    X-Content-Type-Options: [nosniff]
    Access-Control-Allow-Origin: ['*']
    Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE']
    Access-Control-Allow-Headers: ['Authorization', 'Accept', 'Cache-Control']
    Access-Control-Max-Age: [1728000]
    Access-Control-Allow-Credentials: [true]
    Access-Control-Expose-Headers: ['Docker-Content-Digest']
auth:
  htpasswd:
    realm: basic-realm
    path: /auth/htpasswd
health:
  storagedriver:
    enabled: true
    interval: 10s
    threshold: 3
EOF

Шаг 6: Запускаем Registry контейнер

# Создаём docker-compose.yml
cat > /opt/docker-registry/docker-compose.yml << 'EOF'
version: '3.8'

services:
  registry:
    image: registry:2.8.3
    container_name: docker-registry
    restart: unless-stopped
    ports:
      - "5000:5000"
    environment:
      REGISTRY_CONFIG_PATH: /etc/docker/registry/config.yml
      REGISTRY_HTPASSWD_REALM: Registry Realm
      REGISTRY_HTPASSWD_PATH: /auth/htpasswd
      REGISTRY_STORAGE_DELETE_ENABLED: true
    volumes:
      - ./data:/var/lib/registry
      - ./auth:/auth:ro
      - ./config/config.yml:/etc/docker/registry/config.yml:ro
      - ./certs:/certs:ro
    environment:
      REGISTRY_HTTP_TLS_CERTIFICATE: /certs/registry.crt
      REGISTRY_HTTP_TLS_KEY: /certs/registry.key

  registry-ui:
    image: joxit/docker-registry-ui:2.5.5
    container_name: docker-registry-ui
    restart: unless-stopped
    ports:
      - "8080:80"
    environment:
      SINGLE_REGISTRY: true
      REGISTRY_TITLE: My Private Docker Registry
      DELETE_IMAGES: true
      SHOW_CONTENT_DIGEST: true
      NGINX_PROXY_PASS_URL: https://registry:5000
      SHOW_CATALOG_NB_TAGS: true
      CATALOG_MIN_BRANCHES: 1
      CATALOG_MAX_BRANCHES: 1
      TAGLIST_PAGE_SIZE: 100
      REGISTRY_SECURED: true
      CATALOG_ELEMENTS_LIMIT: 1000
    depends_on:
      - registry
EOF

# Запускаем
cd /opt/docker-registry
docker compose up -d

Шаг 7: Настраиваем reverse proxy (nginx)

# Устанавливаем nginx
sudo apt install -y nginx

# Создаём конфигурацию для реестра
sudo tee /etc/nginx/sites-available/docker-registry << 'EOF'
upstream docker-registry {
    server localhost:5000;
}

upstream docker-registry-ui {
    server localhost:8080;
}

server {
    listen 80;
    server_name your-registry.domain.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name your-registry.domain.com;

    ssl_certificate /opt/docker-registry/certs/registry.crt;
    ssl_certificate_key /opt/docker-registry/certs/registry.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;

    client_max_body_size 0;
    chunked_transfer_encoding on;

    location /v2/ {
        proxy_pass http://docker-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;
    }

    location / {
        proxy_pass http://docker-registry-ui;
        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;
    }
}
EOF

# Включаем сайт
sudo ln -s /etc/nginx/sites-available/docker-registry /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx

Тестируем наш реестр

Теперь самое интересное — проверяем, что всё работает:

# Логинимся в наш реестр
docker login your-registry.domain.com

# Тагируем существующий образ
docker tag nginx:latest your-registry.domain.com/nginx:latest

# Пушим образ в наш реестр
docker push your-registry.domain.com/nginx:latest

# Удаляем локальный образ
docker rmi your-registry.domain.com/nginx:latest nginx:latest

# Пулим образ из нашего реестра
docker pull your-registry.domain.com/nginx:latest

Расширенная настройка и оптимизация

Настройка garbage collection

Со временем в реестре накапливается мусор из удалённых образов. Настроим автоматическую очистку:

# Создаём скрипт очистки
sudo tee /opt/docker-registry/cleanup.sh << 'EOF'
#!/bin/bash

# Останавливаем registry
cd /opt/docker-registry
docker compose stop registry

# Запускаем garbage collection
docker run --rm -v /opt/docker-registry/data:/var/lib/registry registry:2.8.3 garbage-collect /etc/docker/registry/config.yml

# Запускаем registry обратно
docker compose start registry

echo "Garbage collection completed at $(date)"
EOF

sudo chmod +x /opt/docker-registry/cleanup.sh

# Добавляем в crontab (запуск каждую неделю в 3 ночи)
(crontab -l 2>/dev/null; echo "0 3 * * 0 /opt/docker-registry/cleanup.sh >> /var/log/docker-registry-cleanup.log 2>&1") | crontab -

Настройка мониторинга

# Добавляем Prometheus метрики в docker-compose.yml
cat >> /opt/docker-registry/docker-compose.yml << 'EOF'

  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    restart: unless-stopped
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'
EOF

# Создаём конфигурацию Prometheus
cat > /opt/docker-registry/prometheus.yml << 'EOF'
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'docker-registry'
    static_configs:
      - targets: ['registry:5000']
    metrics_path: '/metrics'
    scheme: https
    tls_config:
      insecure_skip_verify: true
EOF

Сравнение с альтернативами

Решение Плюсы Минусы Сложность настройки
Docker Registry Простота, официальная поддержка Базовый функционал Низкая
Harbor Enterprise-функции, сканирование уязвимостей Ресурсоёмкость Высокая
Nexus Repository Поддержка разных форматов Тяжёлый, Java-based Средняя
GitLab Container Registry Интеграция с CI/CD Нужен GitLab Средняя

Автоматизация и интеграция в CI/CD

Вот пример интеграции с GitLab CI:

# .gitlab-ci.yml
stages:
  - build
  - push

variables:
  REGISTRY_URL: your-registry.domain.com
  IMAGE_NAME: $REGISTRY_URL/myapp

build:
  stage: build
  script:
    - docker build -t $IMAGE_NAME:$CI_COMMIT_SHA .
    - docker build -t $IMAGE_NAME:latest .

push:
  stage: push
  script:
    - echo $REGISTRY_PASSWORD | docker login $REGISTRY_URL -u $REGISTRY_USER --password-stdin
    - docker push $IMAGE_NAME:$CI_COMMIT_SHA
    - docker push $IMAGE_NAME:latest
  only:
    - main

Безопасность и бэкапы

Не забываем про безопасность:

# Создаём скрипт бэкапа
sudo tee /opt/docker-registry/backup.sh << 'EOF'
#!/bin/bash

BACKUP_DIR="/backup/docker-registry"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p $BACKUP_DIR

# Бэкапим данные реестра
tar -czf $BACKUP_DIR/registry-data-$DATE.tar.gz -C /opt/docker-registry data/

# Бэкапим конфигурацию
tar -czf $BACKUP_DIR/registry-config-$DATE.tar.gz -C /opt/docker-registry config/ auth/

# Удаляем старые бэкапы (старше 30 дней)
find $BACKUP_DIR -name "*.tar.gz" -mtime +30 -delete

echo "Backup completed at $(date)"
EOF

sudo chmod +x /opt/docker-registry/backup.sh

# Добавляем в crontab (ежедневный бэкап в 2 ночи)
(crontab -l 2>/dev/null; echo "0 2 * * * /opt/docker-registry/backup.sh >> /var/log/docker-registry-backup.log 2>&1") | crontab -

Интересные факты и нестандартные применения

Вот несколько крутых способов использования приватного реестра:

  • Кэширующий прокси — можно настроить Registry как кэш для Docker Hub, что ускорит пулы образов
  • Multi-registry setup — несколько реестров для разных команд/проектов с общим nginx
  • Географическое распределение — реестры в разных регионах с синхронизацией
  • Интеграция с LDAP — для корпоративной аутентификации

Пример настройки кэширующего прокси:

# В config.yml добавляем секцию proxy
proxy:
  remoteurl: https://registry-1.docker.io
  username: your-dockerhub-user
  password: your-dockerhub-password

Устранение типичных проблем

Самые частые грабли и как их избежать:

  • Проблема: "x509: certificate signed by unknown authority"

    Решение: Добавить самоподписанный сертификат в доверенные или использовать Let's Encrypt
  • Проблема: "denied: requested access to the resource is denied"

    Решение: Проверить права пользователя в htpasswd и правильность логина
  • Проблема: Медленные push/pull операции

    Решение: Увеличить nginx client_max_body_size и настроить кэширование

Мониторинг и логирование

# Настройка ELK стека для логов
version: '3.8'

services:
  elasticsearch:
    image: elasticsearch:7.15.0
    environment:
      - discovery.type=single-node
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    
  logstash:
    image: logstash:7.15.0
    depends_on:
      - elasticsearch
    volumes:
      - ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf
      
  kibana:
    image: kibana:7.15.0
    ports:
      - "5601:5601"
    depends_on:
      - elasticsearch

Заключение и рекомендации

Поздравляю! Теперь у вас есть полноценный приватный Docker реестр, который можно использовать в продакшене. Вот основные рекомендации по использованию:

  • Для разработки: Используйте самоподписанные сертификаты и базовую аутентификацию
  • Для staging/production: Обязательно Let's Encrypt, мониторинг, бэкапы и автоматическая очистка
  • Для enterprise: Рассмотрите Harbor или интеграцию с корпоративными системами аутентификации

Основные преимущества, которые вы получили:

  • Полный контроль над образами
  • Ускорение CI/CD процессов
  • Экономия на внешнем трафике
  • Повышение безопасности

Не забывайте регулярно обновлять Registry до последних версий и следить за логами. И помните: лучший реестр — это тот, о котором вы не думаете, потому что он просто работает!

P.S. Если вам нужен надёжный сервер для развёртывания такого реестра, рекомендую посмотреть на VPS или выделенные серверы — там можно подобрать конфигурацию под ваши потребности.


В этой статье собрана информация и материалы из различных интернет-источников. Мы признаем и ценим работу всех оригинальных авторов, издателей и веб-сайтов. Несмотря на то, что были приложены все усилия для надлежащего указания исходного материала, любая непреднамеренная оплошность или упущение не являются нарушением авторских прав. Все упомянутые товарные знаки, логотипы и изображения являются собственностью соответствующих владельцев. Если вы считаете, что какой-либо контент, использованный в этой статье, нарушает ваши авторские права, немедленно свяжитесь с нами для рассмотрения и принятия оперативных мер.

Данная статья предназначена исключительно для ознакомительных и образовательных целей и не ущемляет права правообладателей. Если какой-либо материал, защищенный авторским правом, был использован без должного упоминания или с нарушением законов об авторском праве, это непреднамеренно, и мы исправим это незамедлительно после уведомления. Обратите внимание, что переиздание, распространение или воспроизведение части или всего содержимого в любой форме запрещено без письменного разрешения автора и владельца веб-сайта. Для получения разрешений или дополнительных запросов, пожалуйста, свяжитесь с нами.

Leave a reply

Your email address will not be published. Required fields are marked