Модуль 15 / 18
Registry: публикация, authentication, mirror и retention
Содержание
1. Цели и модель registry
После модуля вы сможете публиковать image, разрешать tag в digest, читать Registry API, проектировать authentication/TLS и управлять retention.
- repository группирует manifests
- tag является изменяемым указателем
- manifest связывает config и blobs
- digest фиксирует содержимое
- registry хранит OCI artifacts
2. Теория: Distribution API
/v2/ проверяет API; manifests endpoint принимает tag или digest; blobs адресуются digest. Push сначала загружает недостающие blobs, затем manifest.
Docker-Content-Digest возвращает canonical digest ответа. При удалении manifest используйте digest и правильный Accept media type.
3. Теория: TLS и authentication
Production registry обязан использовать TLS и access control. Basic htpasswd допустим только поверх TLS и требует bcrypt. Token auth выдаёт scoped bearer token для repository actions.
docker login хранит credential через configured credential store. Не передавайте password аргументом и не публикуйте registry анонимно.
4. Теория: storage, HA и consistency
Filesystem backend подходит одному экземпляру; HA требует совместимого shared object storage, одинакового secret/config и load balancer. Backup должен включать storage и конфигурацию identity/policy.
Registry availability не заменяет digest verification; proxy cache и CDN обязаны сохранять headers, ranges и immutable blob semantics.
5. Теория: retention и garbage collection
Удаление manifest убирает reference, но blobs могут остаться, пока на них ссылаются другие manifests. Garbage collector выполняет mark-and-sweep.
Для offline GC registry переводят read-only или останавливают: concurrent push может привести к удалению ещё не отмеченного blob. Retention учитывает tags, signatures и attestations.
6. Теория: pull-through cache
Registry mirror Docker Hub уменьшает повторные загрузки, но не является универсальным mirror любого private registry и остаётся subject to upstream policy.
Credentials upstream дают cache доступ к private content, поэтому сам mirror обязательно защищают. Cache не заменяет curated internal registry.
7. Методические указания
- Используйте TLS и scoped least privilege
- Продвигайте release по digest
- Разделяйте push и pull identities
- Проверяйте quota, latency и error rate
- Не удаляйте tags без inventory attestations
- Тестируйте restore registry
- Запускайте GC в безопасном окне
- Не логируйте Authorization headers
8. Лабораторная работа: локальный registry
Поднимите временный Registry 3 только на loopback, опубликуйте Alpine и исследуйте API.
docker run --detach --name docker-m15-registry --publish 127.0.0.1:15000:5000 --env REGISTRY_STORAGE_DELETE_ENABLED=true --volume docker-m15-registry:/var/lib/registry registry:3
for attempt in 1 2 3 4 5; do curl --fail --silent http://127.0.0.1:15000/v2/ && break; sleep 1; done
docker logs --tail 20 docker-m15-registry
docker inspect docker-m15-registry --format '{{json .Mounts}}' | jqdocker pull alpine:3.21
docker tag alpine:3.21 127.0.0.1:15000/course/alpine:3.21
docker push 127.0.0.1:15000/course/alpine:3.21
curl --fail --silent http://127.0.0.1:15000/v2/_catalog | jq
curl --fail --silent http://127.0.0.1:15000/v2/course/alpine/tags/list | jqПолучите canonical digest, pull по immutable reference, затем удалите manifest по digest.
manifest_digest=$(curl --fail --silent --head -H 'Accept: application/vnd.oci.image.manifest.v1+json' http://127.0.0.1:15000/v2/course/alpine/manifests/3.21 | tr -d '\r' | awk -F': ' 'tolower($1)=="docker-content-digest"{print $2}')
printf 'manifest_digest=%s\n' "$manifest_digest"
docker pull "127.0.0.1:15000/course/alpine@$manifest_digest"
docker image inspect "127.0.0.1:15000/course/alpine@$manifest_digest" --format '{{json .RepoDigests}}'curl --fail --silent --request DELETE --output /dev/null --write-out 'delete_status=%{http_code}\n' "http://127.0.0.1:15000/v2/course/alpine/manifests/$manifest_digest"
curl --silent --output /dev/null --write-out 'manifest_after_delete=%{http_code}\n' -H 'Accept: application/vnd.oci.image.manifest.v1+json' http://127.0.0.1:15000/v2/course/alpine/manifests/3.21
docker pull 127.0.0.1:15000/course/alpine:3.21 || trueКритерий: catalog и tags видны; pull по digest успешен; DELETE возвращает 202; tag после удаления даёт 404.
9. Диагностика push/pull
Проверяйте путь DNS → TCP → TLS → /v2/ challenge → token scope → manifest → platform → blobs → storage.
curl -sS -D - -o /dev/null http://127.0.0.1:15000/v2/
docker logs --timestamps --tail 100 docker-m15-registry
docker inspect docker-m15-registry --format '{{json .State}}' | jq
docker system df
docker volume inspect docker-m15-registry
df -h /var/lib/docker- 401: authentication challenge/credentials
- 403: scope или policy
- 404: repository/tag/digest
- 429: rate limit
- 5xx: registry/storage
- digest mismatch: integrity/proxy/storage
- no matching manifest: platform
10. Контроль и cleanup
- Tag или digest?
- Что возвращает /v2/?
- Зачем Accept при manifest?
- Почему Basic требует TLS?
- Что такое token scope?
- Что удаляет DELETE manifest?
- Почему GC требует read-only?
- Чем mirror отличается от registry?
docker rm --force docker-m15-registry
docker volume rm docker-m15-registry
docker image rm 127.0.0.1:15000/course/alpine:3.21 2>/dev/null || true
docker ps -a --filter name=docker-m15Модуль освоен, если вы публикуете immutable artifact и локализуете registry failure по протоколу.