diff --git a/content/reference/_index.md b/content/reference/_index.md index b0b093cd70..d51c780f93 100644 --- a/content/reference/_index.md +++ b/content/reference/_index.md @@ -42,6 +42,10 @@ params: description: API for Docker Verified Publishers to fetch analytics data. icon: area_chart link: /reference/api/hub/dvp/ + - title: Registry API + description: API for Docker Registry. + icon: database + link: /reference/api/registry/latest/ --- This section includes the reference documentation for the Docker platform's diff --git a/content/reference/api/registry/_index.md b/content/reference/api/registry/_index.md new file mode 100644 index 0000000000..0d376d4a28 --- /dev/null +++ b/content/reference/api/registry/_index.md @@ -0,0 +1,5 @@ +--- +title: Registry API +build: + render: never +--- \ No newline at end of file diff --git a/content/reference/api/registry/auth.md b/content/reference/api/registry/auth.md new file mode 100644 index 0000000000..d395066014 --- /dev/null +++ b/content/reference/api/registry/auth.md @@ -0,0 +1,221 @@ +--- +title: Registry authentication +description: "Specifies the Docker Registry v2 authentication" +keywords: registry, images, tags, repository, distribution, Bearer authentication, advanced +--- + +This document outlines the registry authentication scheme: + +![v2 registry auth](./images/v2-registry-auth.png) + +1. Attempt to begin a push/pull operation with the registry. +2. If the registry requires authorization it will return a `401 Unauthorized` + HTTP response with information on how to authenticate. +3. The registry client makes a request to the authorization service for a + Bearer token. +4. The authorization service returns an opaque Bearer token representing the + client's authorized access. +5. The client retries the original request with the Bearer token embedded in + the request's Authorization header. +6. The Registry authorizes the client by validating the Bearer token and the + claim set embedded within it and begins the push/pull session as usual. + +## Requirements + +- Registry clients which can understand and respond to token auth challenges + returned by the resource server. +- An authorization server capable of managing access controls to their + resources hosted by any given service (such as repositories in a Docker + Registry). +- A Docker Registry capable of trusting the authorization server to sign tokens + which clients can use for authorization and the ability to verify these + tokens for single use or for use during a sufficiently short period of time. + +## Authorization server endpoint descriptions + +The described server is meant to serve as a standalone access control manager +for resources hosted by other services which want to authenticate and manage +authorizations using a separate access control manager. + +A service like this is used by the official Docker Registry to authenticate +clients and verify their authorization to Docker image repositories. + +As of Docker 1.6, the registry client within the Docker Engine has been updated +to handle such an authorization workflow. + +## How to authenticate + +Registry V1 clients first contact the index to initiate a push or pull. Under +the Registry V2 workflow, clients should contact the registry first. If the +registry server requires authentication it will return a `401 Unauthorized` +response with a `WWW-Authenticate` header detailing how to authenticate to this +registry. + +For example, say I (username `jlhawn`) am attempting to push an image to the +repository `samalba/my-app`. For the registry to authorize this, I will need +`push` access to the `samalba/my-app` repository. The registry will first +return this response: + +```text +HTTP/1.1 401 Unauthorized +Content-Type: application/json; charset=utf-8 +Docker-Distribution-Api-Version: registry/2.0 +Www-Authenticate: Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:samalba/my-app:pull,push" +Date: Thu, 10 Sep 2015 19:32:31 GMT +Content-Length: 235 +Strict-Transport-Security: max-age=31536000 + +{"errors":[{"code":"UNAUTHORIZED","message":"access to the requested resource is not authorized","detail":[{"Type":"repository","Name":"samalba/my-app","Action":"pull"},{"Type":"repository","Name":"samalba/my-app","Action":"push"}]}]} +``` + +Note the HTTP Response Header indicating the auth challenge: + +```text +Www-Authenticate: Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:samalba/my-app:pull,push" +``` + +This format is documented in [Section 3 of RFC 6750: The OAuth 2.0 Authorization Framework: Bearer Token Usage](https://tools.ietf.org/html/rfc6750#section-3) + +This challenge indicates that the registry requires a token issued by the +specified token server and that the request the client is attempting will +need to include sufficient access entries in its claim set. To respond to this +challenge, the client will need to make a `GET` request to the URL +`https://auth.docker.io/token` using the `service` and `scope` values from the +`WWW-Authenticate` header. + +## Requesting a token + +Defines getting a bearer and refresh token using the token endpoint. + +### Query parameters + +#### `service` + +The name of the service which hosts the resource. + +#### `offline_token` + +Whether to return a refresh token along with the bearer token. A refresh token +is capable of getting additional bearer tokens for the same subject with +different scopes. The refresh token does not have an expiration and should be +considered completely opaque to the client. + +#### `client_id` + +String identifying the client. This `client_id` does not need to be registered +with the authorization server but should be set to a meaningful value in order +to allow auditing keys created by unregistered clients. Accepted syntax is +defined in [RFC6749 Appendix +A.1](https://tools.ietf.org/html/rfc6749#appendix-A.1). + +#### `scope` + +The resource in question, formatted as one of the space-delimited entries from +the `scope` parameters from the `WWW-Authenticate` header shown previously. This +query parameter should be specified multiple times if there is more than one +`scope` entry from the `WWW-Authenticate` header. The previous example would be +specified as: `scope=repository:samalba/my-app:push`. The scope field may be +empty to request a refresh token without providing any resource permissions to +the returned bearer token. + +### Token response fields + +#### `token` + +An opaque `Bearer` token that clients should supply to subsequent +requests in the `Authorization` header. + +#### `access_token` + +For compatibility with OAuth 2.0, the `token` under the name `access_token` is +also accepted. At least one of these fields must be specified, but both may +also appear (for compatibility with older clients). When both are specified, +they should be equivalent; if they differ the client's choice is undefined. + +#### `expires_in` + +(Optional) The duration in seconds since the token was issued that it will +remain valid. When omitted, this defaults to 60 seconds. For compatibility +with older clients, a token should never be returned with less than 60 seconds +to live. + +#### `issued_at` + +(Optional) The [RFC3339](https://www.ietf.org/rfc/rfc3339.txt)-serialized UTC +standard time at which a given token was issued. If `issued_at` is omitted, the +expiration is from when the token exchange completed. + +#### `refresh_token` + +(Optional) Token which can be used to get additional access tokens for +the same subject with different scopes. This token should be kept secure +by the client and only sent to the authorization server which issues +bearer tokens. This field will only be set when `offline_token=true` is +provided in the request. + +### Example + +For this example, the client makes an HTTP GET request to the following URL: + +```text +https://auth.docker.io/token?service=registry.docker.io&scope=repository:samalba/my-app:pull,push +``` + +The token server should first attempt to authenticate the client using any +authentication credentials provided with the request. From Docker 1.11 the +Docker Engine supports both Basic Authentication and OAuth2 for +getting tokens. Docker 1.10 and before, the registry client in the Docker Engine +only supports Basic Authentication. If an attempt to authenticate to the token +server fails, the token server should return a `401 Unauthorized` response +indicating that the provided credentials are invalid. + +Whether the token server requires authentication is up to the policy of that +access control provider. Some requests may require authentication to determine +access (such as pushing or pulling a private repository) while others may not +(such as pulling from a public repository). + +After authenticating the client (which may simply be an anonymous client if +no attempt was made to authenticate), the token server must next query its +access control list to determine whether the client has the requested scope. In +this example request, if I have authenticated as user `jlhawn`, the token +server will determine what access I have to the repository `samalba/my-app` +hosted by the entity `registry.docker.io`. + +Once the token server has determined what access the client has to the +resources requested in the `scope` parameter, it will take the intersection of +the set of requested actions on each resource and the set of actions that the +client has in fact been granted. If the client only has a subset of the +requested access **it must not be considered an error** as it is not the +responsibility of the token server to indicate authorization errors as part of +this workflow. + +Continuing with the example request, the token server will find that the +client's set of granted access to the repository is `[pull, push]` which when +intersected with the requested access `[pull, push]` yields an equal set. If +the granted access set was found only to be `[pull]` then the intersected set +would only be `[pull]`. If the client has no access to the repository then the +intersected set would be empty, `[]`. + +It is this intersected set of access which is placed in the returned token. + +The server then constructs an implementation-specific token with this +intersected set of access, and returns it to the Docker client to use to +authenticate to the audience service (within the indicated window of time): + +```text +HTTP/1.1 200 OK +Content-Type: application/json + +{"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IlBZWU86VEVXVTpWN0pIOjI2SlY6QVFUWjpMSkMzOlNYVko6WEdIQTozNEYyOjJMQVE6WlJNSzpaN1E2In0.eyJpc3MiOiJhdXRoLmRvY2tlci5jb20iLCJzdWIiOiJqbGhhd24iLCJhdWQiOiJyZWdpc3RyeS5kb2NrZXIuY29tIiwiZXhwIjoxNDE1Mzg3MzE1LCJuYmYiOjE0MTUzODcwMTUsImlhdCI6MTQxNTM4NzAxNSwianRpIjoidFlKQ08xYzZjbnl5N2tBbjBjN3JLUGdiVjFIMWJGd3MiLCJhY2Nlc3MiOlt7InR5cGUiOiJyZXBvc2l0b3J5IiwibmFtZSI6InNhbWFsYmEvbXktYXBwIiwiYWN0aW9ucyI6WyJwdXNoIl19XX0.QhflHPfbd6eVF4lM9bwYpFZIV0PfikbyXuLx959ykRTBpe3CYnzs6YBK8FToVb5R47920PVLrh8zuLzdCr9t3w", "expires_in": 3600,"issued_at": "2009-11-10T23:00:00Z"} +``` + +## Using the Bearer token + +Once the client has a token, it will try the registry request again with the +token placed in the HTTP `Authorization` header like so: + +```text +Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IkJWM0Q6MkFWWjpVQjVaOktJQVA6SU5QTDo1RU42Ok40SjQ6Nk1XTzpEUktFOkJWUUs6M0ZKTDpQT1RMIn0.eyJpc3MiOiJhdXRoLmRvY2tlci5jb20iLCJzdWIiOiJCQ0NZOk9VNlo6UUVKNTpXTjJDOjJBVkM6WTdZRDpBM0xZOjQ1VVc6NE9HRDpLQUxMOkNOSjU6NUlVTCIsImF1ZCI6InJlZ2lzdHJ5LmRvY2tlci5jb20iLCJleHAiOjE0MTUzODczMTUsIm5iZiI6MTQxNTM4NzAxNSwiaWF0IjoxNDE1Mzg3MDE1LCJqdGkiOiJ0WUpDTzFjNmNueXk3a0FuMGM3cktQZ2JWMUgxYkZ3cyIsInNjb3BlIjoiamxoYXduOnJlcG9zaXRvcnk6c2FtYWxiYS9teS1hcHA6cHVzaCxwdWxsIGpsaGF3bjpuYW1lc3BhY2U6c2FtYWxiYTpwdWxsIn0.Y3zZSwaZPqy4y9oRBVRImZyv3m_S9XDHF1tWwN7mL52C_IiA73SJkWVNsvNqpJIn5h7A2F8biv_S2ppQ1lgkbw +``` + +This is also described in [Section 2.1 of RFC 6750: The OAuth 2.0 Authorization Framework: Bearer Token Usage](https://tools.ietf.org/html/rfc6750#section-2.1) \ No newline at end of file diff --git a/content/reference/api/registry/images/v2-registry-auth.png b/content/reference/api/registry/images/v2-registry-auth.png new file mode 100644 index 0000000000..0ea8a4205b Binary files /dev/null and b/content/reference/api/registry/images/v2-registry-auth.png differ diff --git a/content/reference/api/registry/latest.md b/content/reference/api/registry/latest.md new file mode 100644 index 0000000000..7df6e59716 --- /dev/null +++ b/content/reference/api/registry/latest.md @@ -0,0 +1,7 @@ +--- +layout: api +title: Supported registry API for Docker Hub +linktitle: Latest +description: "Supported registry API endpoints." +keywords: registry, on-prem, images, tags, repository, distribution, api, advanced +--- diff --git a/content/reference/api/registry/latest.yaml b/content/reference/api/registry/latest.yaml new file mode 100644 index 0000000000..c38c9ffd71 --- /dev/null +++ b/content/reference/api/registry/latest.yaml @@ -0,0 +1,1345 @@ +openapi: 3.0.3 +info: + title: Supported registry API for Docker Hub + description: | + Docker Hub is an OCI-compliant registry, which means it adheres to the open + standards defined by the Open Container Initiative (OCI) for distributing + container images. This ensures compatibility with a wide range of tools and + platforms in the container ecosystem. + + This reference documents the Docker Hub-supported subset of the Registry HTTP API V2. + It focuses on pulling, pushing, and deleting images. It does not cover the full OCI Distribution Specification. + + For the complete OCI specification, see [OCI Distribution Specification](https://github.com/opencontainers/distribution-spec). +servers: + - description: Docker Hub registry API + x-audience: public + url: https://registry-1.docker.io + +tags: + - name: overview + x-displayName: Overview + description: | + All endpoints in this API are prefixed by the version and repository name, for example: + + ``` + /v2// + ``` + + This format provides structured access control and URI-based scoping of image operations. + + For example, to interact with the `library/ubuntu` repository, use: + + ``` + /v2/library/ubuntu/ + ``` + + Repository names must meet these requirements: + 1. Consist of path components matching `[a-z0-9]+(?:[._-][a-z0-9]+)*` + 2. If more than one component, they must be separated by `/` + 3. Full repository name must be fewer than 256 characters + + + - name: authentication + x-displayName: Authentication + description: | + Specifies registry authentication. + externalDocs: + description: Detailed authentication workflow and token usage + url: https://docs.docker.com/reference/api/registry/auth/ + + - name: Manifests + x-displayName: Manifests + description: | + Image manifests are JSON documents that describe an image: its configuration blob, the digests of each layer blob, and metadata such as media‑types and annotations. + + - name: Blobs + x-displayName: Blobs + description: | + Blobs are the binary objects referenced from manifests: + the config JSON and one or more compressed layer tarballs. + + - name: pull + x-displayName: Pulling Images + description: | + Pulling an image involves retrieving the manifest and downloading each of the image's layer blobs. This section outlines the general steps followed by a working example. + + 1. [Get a bearer token for the repository](https://docs.docker.com/reference/api/registry/auth/). + 2. [Get the image manifest](#operation/GetImageManifest). + 3. If the response in the previous step is a multi-architecture manifest list, you must do the following: + - Parse the `manifests[]` array to locate the digest for your target platform (e.g., `linux/amd64`). + - [Get the image manifest](#operation/GetImageManifest) using the located digest. + 4. [Check if the blob exists](#operation/CheckBlobExists) before downloading. The client should send a `HEAD` request for each layer digest. + 5. [Download each layer blob](#operation/GetBlob) using the digest obtained from the manifest. The client should send a `GET` request for each layer digest. + + The following bash script example pulls `library/ubuntu:latest` from Docker Hub. + + ```bash + #!/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 $TOKEN" \ + -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 $TOKEN" \ + -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 $TOKEN" \ + https://registry-1.docker.io/v2/library/ubuntu/blobs/$DIGEST + + # Step 5: Download the layer blob + curl -L -H "Authorization: Bearer $TOKEN" \ + https://registry-1.docker.io/v2/library/ubuntu/blobs/$DIGEST + ``` + + This example pulls the manifest and the first layer for the `ubuntu:latest` image on the `linux/amd64` platform. Repeat steps 4 and 5 for each digest in the `.layers[]` array in the manifest. + + + - name: push + x-displayName: Pushing Images + description: | + Pushing an image involves uploading any image blobs (such as the config or layers), and then uploading the manifest that references those blobs. + + This section outlines the basic steps to push an image using the registry API. + + 1. [Get a bearer token for the repository](https://docs.docker.com/reference/api/registry/auth/) + + 2. [Check if the blob exists](#operation/CheckBlobExists) using a `HEAD` request for each blob digest. + + 3. If the blob does not exist, [upload the blob](#operation/CompleteBlobUpload) using a monolithic `PUT` request: + - First, [initiate the upload](#operation/InitiateBlobUpload) with `POST`. + - Then [upload and complete](#operation/CompleteBlobUpload) with `PUT`. + + **Note**: Alternatively, you can upload the blob in multiple chunks by using `PATCH` requests to send each chunk, followed by a final `PUT` request to complete the upload. This is known as a [chunked upload](#operation/UploadBlobChunk) and is useful for large blobs or when resuming interrupted uploads. + + + 4. [Upload the image manifest](#operation/PutImageManifest) using a `PUT` request to associate the config and layers. + + The following bash script example pushes a dummy config blob and manifest to `yourusername/helloworld:latest` on Docker Hub. You can replace `yourusername` with your Docker Hub username and `dckr_pat` with your Docker Hub personal access token. + + ```bash + #!/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 $TOKEN" \ + 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 $TOKEN" \ + 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 $TOKEN" \ + -H "Content-Type: application/octet-stream" \ + --data-binary @$CONFIG + fi + + # Step 4: Upload the manifest that references the config blob + MANIFEST=$(cat <` header. + + x-codeSamples: + - lang: Bash + label: cURL + source: | + # GET a manifest (by tag or digest) + curl -H "Authorization: Bearer $TOKEN" \ + -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \ + https://registry-1.docker.io/v2/library/ubuntu/manifests/latest + parameters: + - name: name + in: path + required: true + description: Name of the target repository + example: library/ubuntu + schema: + type: string + - name: reference + in: path + required: true + description: Tag or digest of the target manifest + examples: + by-tag: + summary: Tag + value: latest + by-digest: + summary: Digest + value: sha256:abc123def456... + schema: + type: string + - name: Authorization + in: header + required: true + description: RFC7235-compliant authorization header (e.g., `Bearer `). + schema: + type: string + - name: Accept + in: header + required: false + description: | + Media type(s) the client supports for the manifest. + + The registry supports the following media types: + - application/vnd.docker.distribution.manifest.v2+json + - application/vnd.docker.distribution.manifest.list.v2+json + - application/vnd.oci.image.manifest.v1+json + - application/vnd.oci.image.index.v1+json + schema: + type: string + + responses: + "200": + description: Manifest fetched successfully. + headers: + Docker-Content-Digest: + description: Digest of the returned manifest content. + schema: + type: string + Content-Type: + description: Media type of the returned manifest. + schema: + type: string + content: + application/vnd.docker.distribution.manifest.v2+json: + schema: + type: object + required: + - schemaVersion + - mediaType + - config + - layers + properties: + schemaVersion: + type: integer + example: 2 + mediaType: + type: string + example: application/vnd.docker.distribution.manifest.v2+json + config: + type: object + properties: + mediaType: + type: string + example: application/vnd.docker.container.image.v1+json + size: + type: integer + example: 7023 + digest: + type: string + example: sha256:a3f3e...c1234 + layers: + type: array + items: + type: object + properties: + mediaType: + type: string + example: application/vnd.docker.image.rootfs.diff.tar.gzip + size: + type: integer + example: 32654 + digest: + type: string + example: sha256:bcf2...78901 + examples: + docker-manifest: + summary: Docker image manifest (schema v2) + value: + { + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/vnd.docker.container.image.v1+json", + "size": 7023, + "digest": "sha256:123456abcdef..." + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 32654, + "digest": "sha256:abcdef123456..." + }, + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 16724, + "digest": "sha256:7890abcdef12..." + } + ] + } + + "400": + description: Invalid name or reference. + "401": + description: Authentication required. + "403": + description: Access denied. + "404": + description: Repository or manifest not found. + "429": + description: Too many requests. + + + put: + tags: + - Manifests + summary: Put image manifest + operationId: PutImageManifest + description: | + Upload an image manifest for a given tag or digest. This operation registers a manifest in a repository, allowing it to be pulled using the specified reference. + + This endpoint is typically used after all layer and config blobs have been uploaded to the registry. + + The manifest must conform to the expected schema and media type. For Docker image manifest schema version 2, use: + `application/vnd.docker.distribution.manifest.v2+json` + + Requires authentication via a bearer token with `push` scope for the target repository. + x-codeSamples: + - lang: Bash + label: cURL + source: | + # PUT a manifest (tag = latest) + curl -X PUT \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/vnd.docker.distribution.manifest.v2+json" \ + --data-binary @manifest.json \ + https://registry-1.docker.io/v2/library/ubuntu/manifests/latest + parameters: + - name: name + in: path + required: true + description: Name of the target Repository + example: library/ubuntu + schema: + type: string + - name: reference + in: path + required: true + description: Tag or digest to associate with the uploaded Manifest + examples: + by-tag: + summary: Tag + value: latest + by-digest: + summary: Digest + value: sha256:abc123def456... + schema: + type: string + - name: Authorization + in: header + required: true + description: RFC7235-compliant authorization header (e.g., `Bearer `). + schema: + type: string + - name: Content-Type + in: header + required: true + description: Media type of the manifest being uploaded. + schema: + type: string + example: application/vnd.docker.distribution.manifest.v2+json + + requestBody: + required: true + content: + application/vnd.docker.distribution.manifest.v2+json: + schema: + type: object + required: + - schemaVersion + - mediaType + - config + - layers + properties: + schemaVersion: + type: integer + example: 2 + mediaType: + type: string + example: application/vnd.docker.distribution.manifest.v2+json + config: + type: object + required: + - mediaType + - size + - digest + properties: + mediaType: + type: string + example: application/vnd.docker.container.image.v1+json + size: + type: integer + example: 7023 + digest: + type: string + example: sha256:123456abcdef... + layers: + type: array + items: + type: object + required: + - mediaType + - size + - digest + properties: + mediaType: + type: string + example: application/vnd.docker.image.rootfs.diff.tar.gzip + size: + type: integer + example: 32654 + digest: + type: string + example: sha256:abcdef123456... + + examples: + sample-manifest: + summary: Sample Docker image manifest (schema v2) + value: + { + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/vnd.docker.container.image.v1+json", + "size": 7023, + "digest": "sha256:123456abcdef..." + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 32654, + "digest": "sha256:abcdef123456..." + } + ] + } + + responses: + "201": + description: Manifest created successfully. + headers: + Docker-Content-Digest: + description: Digest of the stored manifest. + schema: + type: string + example: sha256:abcdef123456... + Location: + description: Canonical location of the uploaded manifest. + schema: + type: string + example: /v2/library/ubuntu/manifests/latest + Content-Length: + description: Always zero. + schema: + type: integer + example: 0 + "400": + description: Invalid name, reference, or manifest. + "401": + description: Authentication required. + "403": + description: Access denied. + "404": + description: Repository not found. + "405": + description: Operation not allowed. + "429": + description: Too many requests. + head: + tags: + - Manifests + summary: Check if manifest exists + operationId: HeadImageManifest + description: | + Use this endpoint to verify whether a manifest exists by tag or digest. + + This is a lightweight operation that returns only headers (no body). It is useful for: + - Checking for the existence of a specific image version + - Determining the digest or size of a manifest before downloading or deleting + + This endpoint requires authentication with pull scope. + + parameters: + - name: name + in: path + required: true + description: Name of the Repository + example: library/ubuntu + schema: + type: string + - name: reference + in: path + required: true + description: Tag or digest to check + examples: + by-tag: + summary: Tag + value: latest + by-digest: + summary: Digest + value: sha256:abc123def456... + schema: + type: string + - name: Authorization + in: header + required: true + schema: + type: string + description: Bearer token for authentication + - name: Accept + in: header + required: false + schema: + type: string + example: application/vnd.docker.distribution.manifest.v2+json + description: | + Media type of the manifest to check. The response will match one of the accepted types. + x-codeSamples: + - lang: Bash + label: cURL + source: | + # HEAD /v2/{name}/manifests/{reference} + curl -I \ + -H "Authorization: Bearer $TOKEN" \ + -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \ + https://registry-1.docker.io/v2/library/ubuntu/manifests/latest + responses: + "200": + description: Manifest exists. + headers: + Content-Length: + description: Size of the manifest in bytes + schema: + type: integer + example: 7082 + Docker-Content-Digest: + description: Digest of the manifest + schema: + type: string + example: sha256:abc123... + Content-Type: + description: Media type of the manifest + schema: + type: string + example: application/vnd.docker.distribution.manifest.v2+json + "404": + description: Manifest not found. + "401": + description: Authentication required. + "403": + description: Access denied. + "429": + description: Too many requests. + delete: + tags: + - Manifests + summary: Delete image manifest + operationId: DeleteImageManifest + description: | + Delete an image manifest from a repository by digest. + + Only untagged or unreferenced manifests can be deleted. If the manifest is still referenced by a tag or another image, the registry will return `403 Forbidden`. + + This operation requires `delete` access to the repository. + parameters: + - name: name + in: path + required: true + description: Name of the repository + example: yourusername/helloworld + schema: + type: string + - name: reference + in: path + required: true + description: Digest of the manifest to delete (e.g., `sha256:...`) + example: sha256:abc123def456... + schema: + type: string + - name: Authorization + in: header + required: true + description: Bearer token with `delete` access + schema: + type: string + x-codeSamples: + - lang: Bash + label: cURL + source: | + # DELETE a manifest by digest + curl -X DELETE \ + -H "Authorization: Bearer $TOKEN" \ + https://registry-1.docker.io/v2/yourusername/helloworld/manifests/sha256:abc123def456... + responses: + "202": + description: Manifest deleted successfully. No content returned. + "401": + description: Authentication required. + "403": + description: Access denied. The manifest may still be referenced. + "404": + description: Manifest or repository not found. + "405": + description: Only digest-based deletion is allowed. + "429": + description: Too many requests. + /v2/{name}/blobs/uploads/: + post: + tags: + - Blobs + summary: Initiate blob upload or attempt cross-repository blob mount + operationId: InitiateBlobUpload + description: | + Initiate an upload session for a blob (layer or config) in a repository. + + This is the first step in uploading a blob. It returns a `Location` URL where the blob can be uploaded using `PATCH` (chunked) or `PUT` (monolithic). + + Instead of uploading a blob, a client may attempt to mount a blob from another repository (if it has read access) by including the `mount` and `from` query parameters. + + If successful, the registry responds with `201 Created` and the blob is reused without re-upload. + + If the mount fails, the upload proceeds as usual and returns a `202 Accepted`. + + You must authenticate with `push` access to the target repository. + x-codeSamples: + - lang: Bash + label: cURL (Initiate Standard Upload) + source: | + # Initiate a standard blob upload session + curl -i -X POST \ + -H "Authorization: Bearer $TOKEN" \ + https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/ + + - lang: Bash + label: cURL (Cross-Repository Blob Mount) + source: | + # Attempt a cross-repository blob mount + curl -i -X POST \ + -H "Authorization: Bearer $TOKEN" \ + "https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/?mount=sha256:abc123def456...&from=library/busybox" + + parameters: + - name: name + in: path + required: true + description: Name of the target repository + example: library/ubuntu + schema: + type: string + - name: mount + in: query + required: false + description: Digest of the blob to mount from another repository + schema: + type: string + example: sha256:abc123def456... + - name: from + in: query + required: false + description: Source repository to mount the blob from + schema: + type: string + example: library/busybox + - name: Authorization + in: header + required: true + schema: + type: string + description: Bearer token for authentication with `push` scope + + responses: + "201": + description: Blob successfully mounted from another repository. + headers: + Location: + description: URL where the mounted blob is accessible + schema: + type: string + example: /v2/library/ubuntu/blobs/sha256:abc123... + Docker-Content-Digest: + description: Canonical digest of the mounted blob + schema: + type: string + example: sha256:abc123... + Content-Length: + description: Always zero + schema: + type: integer + example: 0 + "202": + description: Upload initiated successfully (fallback if mount fails). + headers: + Location: + description: Upload location URL for `PATCH` or `PUT` requests + schema: + type: string + example: /v2/library/ubuntu/blobs/uploads/abc123 + Docker-Upload-UUID: + description: Server-generated UUID for the upload session + schema: + type: string + example: abc123 + Range: + description: Current upload byte range (typically `0-0` at init) + schema: + type: string + example: 0-0 + Content-Length: + description: Always zero + schema: + type: integer + example: 0 + "401": + description: Authentication required. + "403": + description: Access denied. + "404": + description: Repository not found. + "429": + description: Too many requests. + /v2/{name}/blobs/{digest}: + head: + tags: + - Blobs + summary: Check existence of blob + operationId: CheckBlobExists + description: | + Check whether a blob (layer or config) exists in the registry. + + This is useful before uploading a blob to avoid duplicates. + + If the blob is present, the registry returns a `200 OK` response with headers like `Content-Length` and `Docker-Content-Digest`. + + If the blob does not exist, the response will be `404 Not Found`. + x-codeSamples: + - lang: Bash + label: cURL + source: | + # HEAD to check if a blob exists + curl -I \ + -H "Authorization: Bearer $TOKEN" \ + https://registry-1.docker.io/v2/library/ubuntu/blobs/sha256:abc123... + parameters: + - name: name + in: path + required: true + description: Name of the Repository + example: library/ubuntu + schema: + type: string + - name: digest + in: path + required: true + description: Digest of the blob + schema: + type: string + example: sha256:abc123def4567890... + - name: Authorization + in: header + required: true + description: Bearer token with pull or push scope + schema: + type: string + example: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6... + + responses: + "200": + description: Blob exists + headers: + Content-Length: + description: Size of the blob in bytes + schema: + type: integer + example: 32654 + Docker-Content-Digest: + description: Digest of the blob + schema: + type: string + example: sha256:abc123def4567890... + Content-Type: + description: MIME type of the blob content + schema: + type: string + example: application/octet-stream + content: + application/json: + examples: + blob-check-request: + summary: Sample request + value: + method: HEAD + url: /v2/library/ubuntu/blobs/sha256:abc123def4567890... + headers: + Authorization: Bearer + Accept: '*/*' + blob-check-response: + summary: Sample 200 response headers + value: + status: 200 OK + headers: + Docker-Content-Digest: sha256:abc123def4567890... + Content-Length: 32654 + Content-Type: application/octet-stream + + "404": + description: Blob not found + "401": + description: Authentication required + "403": + description: Access denied + "429": + description: Too many requests + get: + tags: + - Blobs + summary: Retrieve blob + operationId: GetBlob + description: | + Download the blob identified by digest from the registry. + + Blobs include image layers and configuration objects. Clients must use the digest from the manifest to retrieve a blob. + + This endpoint may return a `307 Temporary Redirect` to a CDN or storage location. Clients must follow the redirect to obtain the actual blob content. + + The blob content is typically a gzipped tarball (for layers) or JSON (for configs). The MIME type is usually `application/octet-stream`. + x-codeSamples: + - lang: Bash + label: cURL + source: | + # GET (download) a blob + curl -L \ + -H "Authorization: Bearer $TOKEN" \ + https://registry-1.docker.io/v2/library/ubuntu/blobs/sha256:abc123... \ + -o layer.tar.gz + parameters: + - name: name + in: path + required: true + description: Repository Name + example: library/ubuntu + schema: + type: string + - name: digest + in: path + required: true + description: Digest of the Blob + schema: + type: string + example: sha256:abc123def456... + - name: Authorization + in: header + required: true + schema: + type: string + description: Bearer token with pull scope + example: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6... + + responses: + "200": + description: Blob content returned directly + headers: + Content-Length: + description: Size of the blob in bytes + schema: + type: integer + example: 32768 + Content-Type: + description: MIME type of the blob + schema: + type: string + example: application/octet-stream + Docker-Content-Digest: + description: Digest of the returned blob + schema: + type: string + example: sha256:abc123def456... + content: + application/octet-stream: + schema: + type: string + format: binary + examples: + small-layer: + summary: Example binary blob (gzipped tar layer) + value: "" + + "307": + description: Temporary redirect to blob location + headers: + Location: + description: Redirect URL for blob download (e.g., S3 or CDN) + schema: + type: string + example: https://cdn.docker.io/blobs/library/ubuntu/abc123... + "401": + description: Authentication required + "403": + description: Access denied + "404": + description: Blob not found + "429": + description: Too many requests + /v2/{name}/blobs/uploads/{uuid}: + get: + tags: + - Blobs + summary: Get blob upload status + operationId: GetBlobUploadStatus + description: | + Retrieve the current status of an in-progress blob upload. + + This is useful for: + - Resuming an interrupted upload + - Determining how many bytes have been accepted so far + - Retrying from the correct offset in chunked uploads + + The response includes the `Range` header indicating the byte range received so far, and a `Docker-Upload-UUID` for identifying the session. + x-codeSamples: + - lang: Bash + label: cURL + source: | + # GET upload status + curl -I \ + -H "Authorization: Bearer $TOKEN" \ + https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/abc123 + parameters: + - name: name + in: path + required: true + description: Repository Name + example : library/ubuntu + schema: + type: string + - name: uuid + in: path + required: true + description: Upload session UUID + schema: + type: string + example: abc123 + - name: Authorization + in: header + required: true + schema: + type: string + example: Bearer eyJhbGciOi... + + responses: + "204": + description: Upload in progress. No body is returned. + headers: + Range: + description: Current byte range uploaded (inclusive) + schema: + type: string + example: 0-16383 + Docker-Upload-UUID: + description: UUID of the upload session + schema: + type: string + example: abc123 + Location: + description: URL to continue or complete the upload + schema: + type: string + example: /v2/library/ubuntu/blobs/uploads/abc123 + "401": + description: Authentication required + "403": + description: Access denied + "404": + description: Upload session not found + "429": + description: Too many requests + + put: + tags: + - Blobs + summary: Complete blob upload + operationId: CompleteBlobUpload + description: | + Complete the upload of a blob by finalizing an upload session. + + This request must include the `digest` query parameter and optionally the last chunk of data. When the registry receives this request, it verifies the digest and stores the blob. + + This endpoint supports: + - Monolithic uploads (upload entire blob in this request) + - Finalizing chunked uploads (last chunk plus `digest`) + + x-codeSamples: + - lang: Bash + label: cURL + source: | + # PUT – complete upload (monolithic or final chunk) + curl -X PUT \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/octet-stream" \ + --data-binary @layer.tar.gz \ + "https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/abc123?digest=sha256:abcd1234..." + + + parameters: + - name: name + in: path + required: true + description: Repository name + schema: + type: string + example: library/ubuntu + - name: uuid + in: path + required: true + description: Upload session UUID returned from the POST request + schema: + type: string + example: abc123 + - name: digest + in: query + required: true + description: Digest of the uploaded blob + schema: + type: string + example: sha256:abcd1234... + - name: Authorization + in: header + required: true + schema: + type: string + example: Bearer eyJhbGciOi... + + requestBody: + required: false + content: + application/octet-stream: + schema: + type: string + format: binary + examples: + layer-upload: + summary: Layer tarball blob + value: "" + + responses: + "201": + description: Upload completed successfully + headers: + Docker-Content-Digest: + description: Canonical digest of the stored blob + schema: + type: string + example: sha256:abcd1234... + Location: + description: URL where the blob is now accessible + schema: + type: string + example: /v2/library/ubuntu/blobs/sha256:abcd1234... + Content-Length: + description: Always zero for completed uploads + schema: + type: integer + example: 0 + "400": + description: Invalid digest or missing parameters + "401": + description: Authentication required + "403": + description: Access denied + "404": + description: Upload session not found + "416": + description: Requested range not satisfiable (if used in chunked mode) + "429": + description: Too many requests + + patch: + tags: + - Blobs + summary: Upload blob chunk + operationId: UploadBlobChunk + description: | + Upload a chunk of a blob to an active upload session. + + Use this method for **chunked uploads**, especially for large blobs or when resuming interrupted uploads. + + The client sends binary data using `PATCH`, optionally including a `Content-Range` header. + + After each chunk is accepted, the registry returns a `202 Accepted` response with: + - `Range`: current byte range stored + - `Docker-Upload-UUID`: identifier for the upload session + - `Location`: URL to continue the upload or finalize with `PUT` + x-codeSamples: + - lang: Bash + label: cURL + source: | + # PATCH – upload a chunk (first 64 KiB) + curl -X PATCH \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/octet-stream" \ + --data-binary @chunk-0.bin \ + "https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/abc123" + parameters: + - name: name + in: path + required: true + description: Repository name + schema: + type: string + example: library/ubuntu + - name: uuid + in: path + required: true + description: Upload session UUID + schema: + type: string + example: abc123 + - name: Authorization + in: header + required: true + schema: + type: string + example: Bearer eyJhbGciOi... + - name: Content-Range + in: header + required: false + schema: + type: string + example: bytes 0-65535 + description: Optional. Byte range of the chunk being sent + + requestBody: + required: true + content: + application/octet-stream: + schema: + type: string + format: binary + examples: + chunk-0: + summary: Upload chunk 0 of a blob + value: "" + + responses: + "202": + description: Chunk accepted and stored + headers: + Location: + description: URL to continue or finalize the upload + schema: + type: string + example: /v2/library/ubuntu/blobs/uploads/abc123 + Range: + description: Byte range uploaded so far (inclusive) + schema: + type: string + example: 0-65535 + Docker-Upload-UUID: + description: Upload session UUID + schema: + type: string + example: abc123 + "400": + description: Malformed content or range + "401": + description: Authentication required + "403": + description: Access denied + "404": + description: Upload session not found + "416": + description: Range error (e.g., chunk out of order) + "429": + description: Too many requests + delete: + tags: + - Blobs + summary: Cancel blob upload + operationId: CancelBlobUpload + description: | + Cancel an in-progress blob upload session. + + This operation discards any data that has been uploaded and invalidates the upload session. + + Use this when: + - An upload fails or is aborted mid-process + - The client wants to clean up unused upload sessions + + After cancellation, the UUID is no longer valid and a new `POST` must be issued to restart the upload. + + x-codeSamples: + - lang: Bash + label: cURL + source: | + # DELETE – cancel an upload session + curl -X DELETE \ + -H "Authorization: Bearer $TOKEN" \ + https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/abc123` + + parameters: + - name: name + in: path + required: true + description: Name of the repository + schema: + type: string + example: library/ubuntu + - name: uuid + in: path + required: true + description: Upload session UUID + schema: + type: string + example: abc123 + - name: Authorization + in: header + required: true + schema: + type: string + example: Bearer eyJhbGciOi... + + responses: + "204": + description: Upload session cancelled successfully. No body is returned. + headers: + Content-Length: + description: Always zero + schema: + type: integer + example: 0 + "401": + description: Authentication required + "403": + description: Access denied + "404": + description: Upload session not found + "429": + description: Too many requests + + +x-tagGroups: + - name: General + tags: + - overview + - authentication + - pull + - push + - delete + - name: API + tags: + - Manifests + - Blobs