Хочете власний реєстр образів без обмежень і сторонніх тарифів? Давайте розгорнемо приватний Docker Registry на вашому сервері Linux із шифруванням TLS, базовою автентифікацією, зберіганням образів у S3 та автоматичним прибиранням сміття (garbage-collection). Це надійна основа для CI/CD і продакшену 🚀

Покрокове розгортання (How‑to)

Вимоги

  • Домен: registry.example.com вказує на IP вашого сервера.
  • Відкриті порти 80/443 (для TLS і випуску сертифіката).
  • Встановлені Docker та плагін docker compose (Docker на Linux), а також certbot і htpasswd.
# Ubuntu/Debian
sudo apt update
sudo apt install -y docker.io docker-compose-plugin certbot apache2-utils

# (Опційно) якщо використовується UFW, відкрийте порти:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

Крок 1: Підготовка директорій

sudo mkdir -p /opt/registry/{auth,config}
sudo chown -R $USER:$USER /opt/registry

Крок 2: Створюємо Basic Auth

Згенеруємо файл паролів для базової автентифікації:

# замініть USERNAME на ваш логін; буде запит пароля
htpasswd -cB /opt/registry/auth/htpasswd USERNAME

Крок 3: Отримуємо TLS‑сертифікат Let’s Encrypt

sudo systemctl stop docker  # тимчасово звільнити порт 80, якщо зайнятий
sudo certbot certonly --standalone \
  -d registry.example.com \
  --agree-tos --email you@example.com --non-interactive
sudo systemctl start docker

# Сертифікати:
# /etc/letsencrypt/live/registry.example.com/fullchain.pem
# /etc/letsencrypt/live/registry.example.com/privkey.pem

Крок 4: Конфігурація Registry (TLS, Basic Auth, S3, delete)

Створимо конфіг:

# /opt/registry/config/config.yml
version: 0.1
log:
  level: info
storage:
  s3:
    bucket: my-registry-bucket
    region: us-east-1
    encrypt: true
    secure: true
    v4auth: true
    # Для AWS цей параметр можна не вказувати;
    # для MinIO/сумісних S3 використовуйте свій endpoint:
    # regionendpoint: https://minio.example.com:9000
  delete:
    enabled: true
http:
  addr: :5000
  # Згенеруйте секрет: openssl rand -hex 32
  secret: 7f1c1de8c4d24b96b8b2e5a3c6f1a4d0a1b2c3d4e5f60718aa55cc33dd44ee66
  tls:
    certificate: /certs/fullchain.pem
    key: /certs/privkey.pem
auth:
  htpasswd:
    realm: "Registry Realm"
    path: /auth/htpasswd
health:
  storagedriver:
    enabled: true
    interval: 10s
    threshold: 3

Крок 5: Docker Compose

Підготуємо змінні середовища для доступу до S3:

# /opt/registry/.env.registry
S3_ACCESS_KEY=PASTE_YOUR_KEY
S3_SECRET_KEY=PASTE_YOUR_SECRET
S3_BUCKET=my-registry-bucket
S3_REGION=us-east-1
# Для AWS можна лишити порожнім або пропустити; для MinIO вкажіть URL
S3_REGIONENDPOINT=https://minio.example.com:9000

Файл docker-compose.yml:

# /opt/registry/docker-compose.yml
services:
  registry:
    image: registry:2.8
    container_name: registry
    restart: always
    ports:
      - "443:5000"
    environment:
      - REGISTRY_STORAGE_S3_ACCESSKEY=${S3_ACCESS_KEY}
      - REGISTRY_STORAGE_S3_SECRETKEY=${S3_SECRET_KEY}
      - REGISTRY_STORAGE_S3_BUCKET=${S3_BUCKET}
      - REGISTRY_STORAGE_S3_REGION=${S3_REGION}
      - REGISTRY_STORAGE_S3_ENCRYPT=true
      - REGISTRY_STORAGE_S3_SECURE=true
      - REGISTRY_STORAGE_S3_V4AUTH=true
      - REGISTRY_STORAGE_S3_REGIONENDPOINT=${S3_REGIONENDPOINT}
    volumes:
      - ./config/config.yml:/etc/docker/registry/config.yml:ro
      - /etc/letsencrypt/live/registry.example.com:/certs:ro
      - ./auth:/auth:ro

Крок 6: Запуск і перевірка

cd /opt/registry
docker compose --env-file .env.registry up -d

# Логін і тестовий push
export REG=registry.example.com
docker login $REG  # введіть USERNAME і пароль з htpasswd

docker pull alpine:3.20
docker tag alpine:3.20 $REG/alpine:test
docker push $REG/alpine:test

docker pull $REG/alpine:test

Якщо push/pull працюють, то ваш приватний реєстр для контейнеризація готовий на сервер Linux.

Автоматичний garbage‑collection

GC видаляє осиротілі шари після очищення тегів/маніфестів. Для коректної роботи registry має бути зупинений на час GC (або в режимі readonly). Зробимо короткий нічний простій через systemd timer (cron та systemd timers):

Скрипт GC

# /opt/registry/gc.sh
#!/usr/bin/env bash
set -euo pipefail
cd /opt/registry

echo "[GC] Stopping registry..."
docker compose down

echo "[GC] Running garbage-collect..."
docker run --rm \
  --env-file /opt/registry/.env.registry \
  -v /opt/registry/config/config.yml:/etc/docker/registry/config.yml:ro \
  registry:2.8 \
  garbage-collect --delete-untagged /etc/docker/registry/config.yml

echo "[GC] Starting registry..."
docker compose --env-file .env.registry up -d
chmod +x /opt/registry/gc.sh

systemd unit і таймер

# /etc/systemd/system/registry-gc.service
[Unit]
Description=Docker Registry garbage-collection
After=network-online.target

[Service]
Type=oneshot
ExecStart=/opt/registry/gc.sh
User=root
# /etc/systemd/system/registry-gc.timer
[Unit]
Description=Nightly Docker Registry GC

[Timer]
OnCalendar=*-*-* 03:30:00
Persistent=true

[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now registry-gc.timer
sudo systemctl list-timers | grep registry-gc

Альтернативні способи

  • Nginx як reverse proxy: завершуйте TLS у Nginx, а Registry запускайте на HTTP (:5000) без внутрішнього TLS. Basic Auth можна залишити у Registry або перенести в Nginx. Це зручно, якщо у вас вже є спільний проксі.
  • MinIO або інші S3‑сумісні сховища: замініть S3_REGIONENDPOINT на ваш endpoint і створіть bucket заздалегідь. Не забудьте політику доступу (read/write) для ключів.
  • Readonly GC: просунутий варіант з переведенням Registry у maintenance.readonly і GC без повного зупину. Але це тонке налаштування, для більшості достатньо короткого простою вночі.

GUI‑спосіб (Portainer)

Якщо ви любите GUI, у Portainer створіть Stack зі стек‑yaml нижче (попередньо підготуйте файли та змінні середовища, як вище):

services:
  registry:
    image: registry:2.8
    ports:
      - "443:5000"
    environment:
      - REGISTRY_STORAGE_S3_ACCESSKEY=${S3_ACCESS_KEY}
      - REGISTRY_STORAGE_S3_SECRETKEY=${S3_SECRET_KEY}
      - REGISTRY_STORAGE_S3_BUCKET=${S3_BUCKET}
      - REGISTRY_STORAGE_S3_REGION=${S3_REGION}
      - REGISTRY_STORAGE_S3_SECURE=true
      - REGISTRY_STORAGE_S3_ENCRYPT=true
      - REGISTRY_STORAGE_S3_V4AUTH=true
      - REGISTRY_STORAGE_S3_REGIONENDPOINT=${S3_REGIONENDPOINT}
    volumes:
      - /opt/registry/config/config.yml:/etc/docker/registry/config.yml:ro
      - /etc/letsencrypt/live/registry.example.com:/certs:ro
      - /opt/registry/auth:/auth:ro
    restart: always

FAQ

Q: Під час docker login бачу x509: certificate signed by unknown authority?
A: Переконайтеся, що заходите за повним доменом registry.example.com, а не за IP, і що клієнт бачить дійсний ланцюжок сертифікатів (Let’s Encrypt). Не використовуйте --insecure-registry, якщо у вас є TLS.

Q: Отримую 401 Unauthorized при push/pull.
A: Перевірте логін/пароль, файл /opt/registry/auth/htpasswd та наявність auth.htpasswd у конфігу. Спробуйте заново docker login.

Q: Push великих образів падає.
A: Для S3 можна підвищити розмір чанків: додайте REGISTRY_STORAGE_S3_CHUNKSIZE=67108864 (64 MB) до environment і перезапустіть контейнер.

Q: GC відпрацював, але місце не звільнилося.
A: GC видаляє лише осиротілі шари. Спочатку видаліть непотрібні теги/маніфести (API або docker manifest rm), переконайтеся, що storage.delete.enabled=true, і запускайте GC з прапором --delete-untagged.

Q: Як оновлюються сертифікати Let’s Encrypt?
A: certbot типовим кроном/таймером подовжує сертифікати. Додайте хук на перезапуск: /etc/letsencrypt/renewal-hooks/post/10-restart-registry.sh з вмістом docker restart registry.

Q: Чи можна зберігати у кількох регіонах S3?
A: Registry працює з одним bucket. Для геореплікації використовуйте політики реплікації S3 або зовнішні mirror-и.

Порада від Kernelka

Увімкніть версіонування bucket’а в S3 і політику lifecycle для автоматичного очищення старих версій. Зберігайте файл .env.registry поза git і встановіть права доступу chmod 600 — так ваші ключі не потраплять у чужі руки 💡

Підсумок

  • Підняли приватний реєстр із TLS і Basic Auth.
  • Налаштували зберігання образів у S3‑bucket з шифруванням.
  • Додали автоматичний garbage‑collection через systemd timer.
  • Передбачили альтернативи: Nginx‑proxy та MinIO/інші S3‑сумісні сервіси.
  • Маємо готову базу для CI/CD і продакшен‑контейнерів на сервер Linux.