Хочете власний реєстр образів без обмежень і сторонніх тарифів? Давайте розгорнемо приватний 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.

Прокоментувати
На сайті відображається лише твоє ім'я та коментар. Електронна пошта зберігається виключно для зв'язку з тобою за потреби та в жодному разі не передається стороннім особам.