Registry API
Registry API
Docker Hub는 OCI 호환 레지스트리예요. 이 레퍼런스는 이미지 풀(Pull), 푸시(Push), 삭제(Delete)를 다루는 Registry HTTP API V2의 Docker Hub 지원 하위집합을 문서화해요.
출처: 문서
본문
호스팅 API — Registry API · API 2 · 11개 작업 · 0개의 이름 붙은 스키마
개요 (Overview)
Docker Hub는 OCI 호환 레지스트리예요. 즉 컨테이너 이미지를 배포하기 위해 Open Container Initiative(OCI)가 정의한 개방형 표준을 따르요. 이는 컨테이너 생태계의 다양한 도구와 플랫폼과의 호환성을 보장해요.
이 레퍼런스는 Registry HTTP API V2의 Docker Hub 지원 하위집합을 문서화해요. 이미지 풀, 푸시, 삭제에 초점을 맞춰요. 전체 OCI Distribution Specification은 다루지 않아요.
전체 OCI 사양은 OCI Distribution Specification을 참조하세요.
Registry API에 연결하기
registryToken
WWW-Authenticate 챌린지를 따라 저장소 스코프의 레지스트리 bearer 토큰을 얻어요. 공개 이미지 풀은 계정 자격 증명 없이 토큰을 얻을 수 있어요. 레지스트리 요청은 여전히 그 토큰을 보내요. 이 토큰 교환은 Hub API 인증과는 별개예요.
https://registry-1.docker.io
개요
이 API의 모든 엔드포인트는 버전과 저장소 이름이 접두사로 붙어요. 예:
/v2//
이 형식은 구조화된 접근 제어와 이미지 작업의 URI 기반 스코프 지정을 제공해요.
예를 들어 library/ubuntu 저장소와 상호작용하려면 다음을 사용해요.
/v2/library/ubuntu/
저장소 이름은 다음 요구 사항을 충족해야 해요.
[a-z0-9]+(?:[._-][a-z0-9]+)*와 일치하는 경로 구성 요소로 구성- 구성 요소가 둘 이상이면
/로 구분 - 전체 저장소 이름은 256자 미만
인증 (Authentication)
레지스트리 인증을 지정해요.
매니페스트 (Manifests)
이미지 매니페스트는 이미지를 설명하는 JSON 문서예요. 이미지의 구성(Config) 블롭, 각 레이어 블롭의 다이제스트, media-type과 어노테이션 같은 메타데이터를 담아요.
블롭 (Blobs)
블롭은 매니페스트에서 참조되는 이진 객체예요. 구성 JSON과 하나 이상의 압축된 레이어 tarball이에요.
이미지 풀 (Pulling Images)
이미지를 풀하려면 매니페스트를 검색하고 각 레이어 블롭을 다운로드해야 해요. 이 섹션은 동작하는 예시를 따르는 일반적인 단계를 설명해요.
- 저장소에 대한 bearer 토큰을 얻어요.
- 이미지 매니페스트를 얻어요.
- 이전 단계의 응답이 멀티 아키텍처 매니페스트 목록이라면 다음을 수행해야 해요:
manifests[]배열을 파싱해 대상 플랫폼(예:linux/amd64)의 다이제스트를 찾아요. - 찾은 다이제스트로 이미지 매니페스트를 얻어요.
- 다운로드 전에 블롭이 존재하는지 확인해요. 클라이언트는 각 레이어 다이제스트에 대해
HEAD요청을 보내야 해요. - 매니페스트에서 얻은 다이제스트를 사용해 각 레이어 블롭을 다운로드해요. 클라이언트는 각 레이어 다이제스트에 대해
GET요청을 보내야 해요.
다음 bash 스크립트 예시는 Docker Hub에서 library/ubuntu:latest를 풀해요.
#!/bin/bash
# Step 1: Get a bearer token
TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/ubuntu:pull" | jq -r .token)
# Step 2: Get the image manifest. In this example, an image manifest list is returned.
curl -s -H "Authorization: Bearer ***" \
-H "Accept: application/vnd.docker.distribution.manifest.list.v2+json" \
https://registry-1.docker.io/v2/library/ubuntu/manifests/latest \
-o manifest-list.json
# Step 3a: Parse the `manifests[]` array to locate the digest for your target platform (e.g., `linux/amd64`).
IMAGE_MANIFEST_DIGEST=$(jq -r '.manifests[] | select(.platform.architecture == "amd64" and .platform.os == "linux") | .digest' manifest-list.json)
# Step 3b: Get the platform-specific image manifest
curl -s -H "Authorization: Bearer ***" \
-H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
https://registry-1.docker.io/v2/library/ubuntu/manifests/$IMAGE_MANIFEST_DIGEST \
-o manifest.json
# Step 4: Send a HEAD request to check if the layer blob exists
DIGEST=$(jq -r '.layers[0].digest' manifest.json)
curl -I -H "Authorization: Bearer ***" \
https://registry-1.docker.io/v2/library/ubuntu/blobs/$DIGEST
# Step 5: Download the layer blob
curl -L -H "Authorization: Bearer ***" \
https://registry-1.docker.io/v2/library/ubuntu/blobs/$DIGEST
이 예시는 linux/amd64 플랫폼의 ubuntu:latest 이미지에 대한 매니페스트와 첫 번째 레이어를 풀해요. 매니페스트의 .layers[] 배열에 있는 각 다이제스트에 대해 4, 5단계를 반복하세요.
이미지 푸시 (Pushing Images)
이미지를 푸시하려면 이미지 블롭(구성(Config) 또는 레이어)을 업로드한 다음, 그 블롭을 참조하는 매니페스트를 업로드해야 해요.
이 섹션은 레지스트리 API를 사용해 이미지를 푸시하는 기본 단계를 설명해요.
- 저장소에 대한 bearer 토큰을 얻어요.
- 각 블롭 다이제스트에 대한
HEAD요청으로 블롭이 존재하는지 확인해요. - 블롭이 존재하지 않으면, 모놀리식(monolithic)
PUT요청으로 블롭을 업로드해요. 먼저POST로 업로드를 시작해요. - 그런 다음
PUT으로 업로드하고 완료해요. 참고: 또는PATCH요청으로 각 청크를 보내고 마지막PUT요청으로 업로드를 완료하는 방식으로 블롭을 여러 청크로 업로드할 수 있어요. 이를 청크 업로드(chunked upload)라고 하며, 큰 블롭이나 중단된 업로드를 재개할 때 유용해요. PUT요청으로 구성과 레이어를 연결하는 이미지 매니페스트를 업로드해요.
다음 bash 스크립트 예시는 가짜 구성 블롭과 매니페스트를 Docker Hub의 yourusername/helloworld:latest에 푸시해요. yourusername을 여러분의 Docker Hub 사용자 이름으로, dckr_pat을 여러분의 Docker Hub 개인 액세스 토큰으로 바꿀 수 있어요.
#!/bin/bash
USERNAME=yourusername
PASSWORD=dckr_pat
REPO=yourusername/helloworld
TAG=latest
CONFIG=config.json
MIME_TYPE=application/vnd.docker.container.image.v1+json
# Step 1: Get a bearer token
TOKEN=$(curl -s -u "$USERNAME:$PASSWORD" \
"https://auth.docker.io/token?service=registry.docker.io&scope=repository:$REPO:push,pull" \
| jq -r .token)
# Create a dummy config blob and compute its digest
echo '{"architecture":"amd64","os":"linux","config":{},"rootfs":{"type":"layers","diff_ids":[]}}' > $CONFIG
DIGEST="sha256:$(sha256sum $CONFIG | awk '{print $1}')"
# Step 2: Check if the blob exists
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -I \
-H "Authorization: Bearer ***" \
https://registry-1.docker.io/v2/$REPO/blobs/$DIGEST)
if [ "$STATUS" != "200" ]; then
# Step 3: Upload blob using monolithic upload
LOCATION=$(curl -sI -X POST \
-H "Authorization: Bearer ***" \
https://registry-1.docker.io/v2/$REPO/blobs/uploads/ \
| grep -i Location | tr -d '\r' | awk '{print $2}')
curl -s -X PUT "$LOCATION&digest=$DIGEST" \
-H "Authorization: Bearer ***" \
-H "Content-Type: application/octet-stream" \
--data-binary @$CONFIG
fi
# Step 4: Upload the manifest that references the config blob
MANIFEST=$(cat <<EOF
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "$MIME_TYPE",
"size": $(stat -c%s $CONFIG),
"digest": "$DIGEST"
},
"layers": []
}
EOF
)
curl -s -X PUT \
-H "Authorization: Bearer ***" \
-H "Content-Type: application/vnd.docker.distribution.manifest.v2+json" \
-d "$MANIFEST" \
https://registry-1.docker.io/v2/$REPO/manifests/$TAG
echo "Pushed image to $REPO:$TAG"
이 예시는 레이어가 없는 최소 이미지를 푸시해요. 전체 이미지를 푸시하려면 각 레이어에 대해 2~3단계를 반복하고 매니페스트의 layers[] 필드에 레이어 다이제스트를 포함하세요.
이미지 삭제 (Deleting Images)
이미지를 삭제하려면 다이제스트로 매니페스트를 제거해야 해요. 먼저 매니페스트 다이제스트를 검색한 다음, 그 다이제스트로 DELETE 요청을 보내야 해요.
태그되지 않은(또는 다른 태그/이미지가 참조하지 않는) 매니페스트만 삭제할 수 있어요. 매니페스트가 여전히 참조되면 레지스트리는 403 Forbidden을 반환해요.
Note 매니페스트 삭제 작업은 지연이 있을 수 있고 삭제 중
500 Internal Server Error를 반환할 수 있어요. 시스템이 백그라운드에서 삭제를 자동으로 재시도하므로 매니페스트는 결국 제거돼요. 요청을 수동으로 재시도할 필요는 없어요.
이 섹션은 레지스트리 API로 이미지를 삭제하는 기본 단계를 설명해요.
- 저장소에 대한 bearer 토큰을 얻어요.
- 이미지의 태그로 매니페스트를 얻어요.
- 매니페스트 응답에서
Docker-Content-Digest헤더를 검색해요. 이 다이제스트는 매니페스트를 고유하게 식별해요. DELETE요청과 다이제스트로 매니페스트를 삭제해요.
다음 bash 스크립트 예시는 Docker Hub의 yourusername/helloworld에서 latest 태그를 삭제해요. yourusername을 여러분의 Docker Hub 사용자 이름으로, dckr_pat을 여러분의 Docker Hub 개인 액세스 토큰으로 바꾸세요.
#!/bin/bash
USERNAME=yourusername
PASSWORD=dckr_pat
REPO=yourusername/helloworld
TAG=latest
# Step 1: Get a bearer token
TOKEN=$(curl -s -u "$USERNAME:$PASSWORD" \
"https://auth.docker.io/token?service=registry.docker.io&scope=repository:$REPO:pull,push,delete" \
| jq -r .token)
# Step 2 and 3: Get the manifest and extract the digest from response headers
DIGEST=$(curl -sI -H "Authorization: Bearer ***" \
-H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
https://registry-1.docker.io/v2/$REPO/manifests/$TAG \
| grep -i Docker-Content-Digest | tr -d '\r' | awk '{print $2}')
echo "Deleting manifest with digest: $DIGEST"
# Step 4: Delete the manifest by digest
curl -s -X DELETE \
-H "Authorization: Bearer ***" \
https://registry-1.docker.io/v2/$REPO/manifests/$DIGEST
echo "Deleted image: $REPO@$DIGEST"
이 예시는 latest 태그의 매니페스트를 삭제해요. 이미지에 대한 모든 참조를 완전히 삭제하려면 같은 매니페스트 다이제스트를 가리키는 다른 태그나 참조자(referrer)가 없는지 확인하세요.
작업 (Operations)
| 메서드 | 경로 | 설명 |
|---|---|---|
| POST | /v2/{name}/blobs/uploads/ |
블롭 업로드 시작 또는 크로스 저장소 블롭 마운트 시도 |
| GET | /v2/{name}/blobs/uploads/{uuid} |
블롭 업로드 상태 조회 |
| PUT | /v2/{name}/blobs/uploads/{uuid} |
블롭 업로드 완료 |
| DELETE | /v2/{name}/blobs/uploads/{uuid} |
블롭 업로드 취소 |
| PATCH | /v2/{name}/blobs/uploads/{uuid} |
블롭 청크 업로드 |
| GET | /v2/{name}/blobs/{digest} |
블롭 검색 |
| HEAD | /v2/{name}/blobs/{digest} |
블롭 존재 확인 |
| GET | /v2/{name}/manifests/{reference} |
이미지 매니페스트 조회 |
| PUT | /v2/{name}/manifests/{reference} |
이미지 매니페스트 저장 |
| DELETE | /v2/{name}/manifests/{reference} |
이미지 매니페스트 삭제 |
| HEAD | /v2/{name}/manifests/{reference} |
매니페스트 존재 확인 |