Работа с OCI / Docker¶
CodeScoring.Save реализует стандарт OCI Distribution Spec на префиксе /v2/, поддерживая Docker, Helm OCI-чарты и любые другие OCI-артефакты (например, oras).
Proxy-репозиторий¶
curl -X POST https://save.example.com/api/v1/repos \
-H "Content-Type: application/json" \
-u "<username>:<password>" \
-d '{
"project": "common",
"name": "dockerhub-proxy",
"format": "docker",
"repository_type": "proxy",
"remote_url": "https://registry-1.docker.io",
"cache_ttl": 86400
}'
Для образов с одним именем (без слешей) применяется стандартная нормализация Docker Hub library/<image>.
Hosted-репозиторий¶
curl -X POST https://save.example.com/api/v1/repos \
-H "Content-Type: application/json" \
-u "<username>:<password>" \
-d '{
"project": "common",
"name": "docker-hosted",
"format": "docker",
"repository_type": "hosted"
}'
URL-схема¶
Базовая схема — путевая, как требует Docker / OCI:
Дополнительно поддерживается Nexus-совместимая маршрутизация плоских URL (flat-alias). Для совместимых репозиториев <project>/<repository> префикс заменяется коротким алиасом или вовсе опускается.
Настройка клиента¶
Docker / Podman¶
# Логин
docker login save.example.com
# Pull через proxy
docker pull save.example.com/common/dockerhub-proxy/library/nginx:latest
# Push в hosted
docker tag myapp:latest save.example.com/common/docker-hosted/myapp:1.0.0
docker push save.example.com/common/docker-hosted/myapp:1.0.0
Anonymous read и docker login
Endpoint /v2/ всегда отвечает 401 с challenge-заголовком WWW-Authenticate: Bearer realm=..., даже если репозиторий допускает анонимное чтение. Это нужно, чтобы Docker-клиент корректно выполнил cycle 401 → retry → 200 и затем при необходимости отправил Basic Auth. Это требование OCI Distribution Spec.
Robot-аккаунты в CI
Для CI/CD используйте robot-аккаунт: docker login -u 'sa$<robot-name>' -p '<api-key>' save.example.com. То же самое работает для helm registry login и oras login. Подробнее — в общем разделе Аутентификация.
Helm¶
CodeScoring.Save принимает Helm-чарты как обычные OCI-артефакты. Push/pull выполняется стандартными командами helm:
# Логин (Helm 3.8+)
helm registry login save.example.com -u <username>
# Push
helm package ./mychart # → mychart-0.1.0.tgz
helm push mychart-0.1.0.tgz oci://save.example.com/common/docker-hosted
# Pull
helm pull oci://save.example.com/common/docker-hosted/mychart --version 0.1.0
Plain HTTP для тестовых стендов
Для тестовых стендов без TLS используйте флаг --plain-http (Helm 3.13+):
oras¶
oras работает с любым OCI-совместимым артефактом — конфигами, политиками, SBOM, бинарями и т. д.:
# Push произвольного файла как OCI-артефакта
oras push save.example.com/common/docker-hosted/configs/app:v1 \
-u <username> -p <password> \
./config.yaml:application/vnd.example.config
# Pull
oras pull save.example.com/common/docker-hosted/configs/app:v1 \
-u <username> -p <password>
containerd / nerdctl¶
nerdctl login save.example.com
nerdctl pull save.example.com/common/dockerhub-proxy/library/alpine:latest
Маршрутизация плоских URL¶
Save поддерживает Nexus-совместимое плоское пространство имён для бесшовной миграции с Nexus / Artifactory: репозиторий можно сконфигурировать с префиксом-алиасом, чтобы он отвечал на запросы без <project>/<repository> в пути.
Применяется longest-prefix matching:
docker pull save.example.com/common/external/golang:1.24.1— попадёт в репозиторий, чей flat-alias =common/external/.docker pull save.example.com/johnny-depp:v1— попадёт в catch-all hosted-репозиторий (если он сконфигурирован).
При создании репозитория с flat-alias указываются параметры flat_alias_prefix и/или is_catch_all. Префиксы валидируются на уникальность.
Миграция URL репозитория¶
Сценарий использования: миграция Docker-реестра из Nexus / Artifactory на CodeScoring.Save.
| Источник | URL до миграции | URL после миграции (с проектом) | URL после миграции (flat-alias) |
|---|---|---|---|
| Nexus | nexus.host.ru:5000/library/nginx:latest |
save.example.com/common/dockerhub-proxy/library/nginx:latest |
save.example.com/library/nginx:latest |
| Artifactory | jfrog.host.ru/docker-remote/library/nginx |
save.example.com/common/dockerhub-proxy/library/nginx |
save.example.com/library/nginx |
| Docker Hub | docker.io/library/postgres:16 |
save.example.com/common/dockerhub-proxy/library/postgres:16 |
save.example.com/library/postgres:16 |
Flat-alias-вариант ничего не требует от клиента — старые скрипты, в которых жёстко прописано nexus.host.ru/library/nginx, начинают работать после простой замены хоста.
Устранение неполадок¶
Проверка /v2/¶
curl -i https://save.example.com/v2/
# Ожидается: HTTP/1.1 401 Unauthorized с Www-Authenticate: Bearer realm=...
Проверка эндпоинта токена¶
curl -u "<username>:<password>" \
"https://save.example.com/v2/token?service=save.example.com&scope=repository:common/dockerhub-proxy/library/nginx:pull"
В ответе — JSON с полем token, содержащим короткоживущий Docker v2 JWT.
Список тегов¶
curl -u "<username>:<password>" \
https://save.example.com/v2/<project>/<repository>/<image>/tags/list
Состояние сервиса¶
Аудит по репозиторию¶
curl -u "<username>:<password>" \
"https://save.example.com/api/v1/admin/audit?resource_type=repository&q=dockerhub-proxy&limit=50"