Перейти к содержимому

Проксирование Docker

NORA может работать как сквозной кэш (pull-through cache) для вышестоящих Docker-реестров. Если образ не найден локально, NORA загружает его из настроенного upstream-реестра, сохраняет в кэш и отдаёт клиенту. Последующие запросы обслуживаются из кэша.

docker pull nora:4000/library/nginx:latest
┌──────┐ попадание в кэш ┌───────────┐
│ NORA │ ──────────────────► │ хранилище │
└──┬───┘ └───────────┘
│ промах кэша
┌────────────┐ загрузка + фоновое кэширование
│ upstream │ ────────────────────────────────► хранилище
│ (Docker Hub)│
└────────────┘
  1. Клиент запрашивает образ у NORA
  2. NORA проверяет локальное хранилище — если найден, отдаёт сразу (попадание в кэш)
  3. Если не найден, перебирает настроенные upstreams последовательно
  4. Первый успешный ответ возвращается клиенту
  5. Образ сохраняется в хранилище асинхронно в фоне
  6. Следующий запрос того же образа обслуживается из кэша

Две переменные окружения управляют поведением прокси:

ПеременнаяПо умолчаниюОписание
NORA_DOCKER_UPSTREAMShttps://registry-1.docker.ioСписок upstream-реестров через запятую
NORA_DOCKER_PROXY_TIMEOUT60Таймаут HTTP-запросов к upstream (секунды)

По умолчанию NORA проксирует к Docker Hub без дополнительной настройки:

Окно терминала
docker pull nora.internal:4000/library/nginx:latest

NORA перебирает upstreams по порядку. Если Docker Hub недоступен или не содержит нужный образ, используется следующий:

Окно терминала
NORA_DOCKER_UPSTREAMS="https://registry-1.docker.io,https://ghcr.io,https://quay.io"
[docker]
proxy_timeout = 60
[[docker.upstreams]]
url = "https://registry-1.docker.io"
[[docker.upstreams]]
url = "https://ghcr.io"
services:
nora:
image: ghcr.io/getnora-io/nora:latest
ports:
- 4000:4000
volumes:
- nora-data:/data
environment:
- NORA_HOST=0.0.0.0
- NORA_DOCKER_UPSTREAMS=https://registry-1.docker.io,https://ghcr.io
- NORA_DOCKER_PROXY_TIMEOUT=30
restart: unless-stopped
volumes:
nora-data:
Окно терминала
# Вместо: docker pull nginx:latest
docker pull nora.internal:4000/library/nginx:latest
# Вместо: docker pull redis:7-alpine
docker pull nora.internal:4000/library/redis:7-alpine
# Образы пользовательских репозиториев:
docker pull nora.internal:4000/grafana/grafana:latest

Если GHCR указан в списке upstreams и образ отсутствует в Docker Hub:

Окно терминала
docker pull nora.internal:4000/getnora-io/nora:latest

Настройте демон Docker для использования NORA как зеркала реестра. Отредактируйте /etc/docker/daemon.json:

{
"registry-mirrors": ["http://nora.internal:4000"]
}

Перезапустите Docker:

Окно терминала
sudo systemctl restart docker

Теперь все команды docker pull автоматически проходят через NORA:

Окно терминала
# Этот запрос пойдёт через кэш NORA:
docker pull nginx:latest

NORA обрабатывает аутентификацию к upstream-реестрам автоматически:

  1. Отправляет неаутентифицированный запрос к upstream
  2. При ответе 401 Unauthorized извлекает заголовок Www-Authenticate
  3. Получает bearer-токен от сервиса аутентификации upstream
  4. Повторяет запрос с токеном
  5. Токены кэшируются на 5 минут для каждой пары реестр/репозиторий

Учётные данные не требуются для публичных образов. Docker Hub, GHCR и Quay поддерживают анонимную загрузку публичных репозиториев.

Любой реестр, совместимый с Docker Registry v2 API:

РеестрURL
Docker Hubhttps://registry-1.docker.io
GitHub Container Registryhttps://ghcr.io
Quay.iohttps://quay.io
GitLab Container Registryhttps://registry.gitlab.com
Google Artifact Registryhttps://REGION-docker.pkg.dev
AWS ECRhttps://ACCOUNT.dkr.ecr.REGION.amazonaws.com

NORA отслеживает эффективность кэша через метрики Prometheus на /metrics:

  • nora_cache_hits_total — образы, отданные из локального кэша
  • nora_cache_misses_total — образы, загруженные из upstream
  • nora_docker_downloads_total — общее количество операций загрузки Docker

Процент попаданий в кэш также отображается на панели мониторинга в веб-интерфейсе.

  • Только загрузка — прокси работает только на чтение. Отправка образов (push) идёт в локальное хранилище NORA и не пересылается в upstream.
  • Последовательный перебор — upstreams опрашиваются один за другим, не параллельно. При таймауте первого upstream задержка суммируется.
  • Без аутентификации к приватным upstreams — поддерживается только анонимный доступ и bearer-токен (OAuth2). Передача логина/пароля к приватным upstream-реестрам пока не реализована.
  • Асинхронное кэширование — запись в кэш происходит в фоне. При перезапуске NORA во время кэширования образ не сохранится и будет загружен повторно при следующем запросе.