Skip to content

Instantly share code, notes, and snippets.

@mmdriley
Last active April 15, 2019 14:57
Show Gist options
  • Save mmdriley/0ed2129a93fd0c15ff36 to your computer and use it in GitHub Desktop.
Save mmdriley/0ed2129a93fd0c15ff36 to your computer and use it in GitHub Desktop.
Docker Registry API walkthrough

Docker Registry API V1 walkthrough

Matthew Riley (mattdr@google.com)

This document summarizes the interactions between the Docker client and the Docker Hub during push and pull commands through version 1 of the registry API. It was compiled to aid in writing a compatible registry server implementation after the existing API documentation proved occasionally incomplete or inaccurate.

Behavior and code links were as of Docker v1.2.0.

docker {push|pull} H:P/R[:T]
Host, Port, Repository ([namespace/]image), Tag

Life of a docker pull

TagStore.pullRepository

Session.GetRepositoryData

GET H:P/v1/repositories/R/images
Authorization: Basic abc
X-Docker-Token: true

Response
X-Docker-Token: xyz
X-Docker-Endpoints: server1, server2
Split list on commas, then trim spaces from entries. (ref)

[{"checksum": "abc", "id": "123"}, ...]
JSON array of objects, one per image

Session.GetRemoteTags

GET server1/v1/repositories/R/tags
server is from X-Docker-Endpoints returned above
Authorization: Token xyz
token is from X-Docker-Token returned above

Response
{"tagname1": "image_id1", ...}
JSON object, one field per tag

Compute the union of the images list and the set of tagged images.

If no tag was specified, download all images with tags. Otherwise only download the one with a matching tag. Untagged images are ignored.

For each image:

TagStore.pullImage

Session.GetRemoteHistory

GET server1/v1/images/IMAGEID/ancestry
Authorization: Token xyz

Response
["self_imageid", "parent_imageid", ..., "root_imageid"]
JSON array of image IDs as strings. Order is important! Starts with self, ends with root.

Session.GetRemoteImageJSON

GET server1/v1/images/IMAGEID/json
Authorization: Token xyz

Response
X-Docker-Size: 123
Size of corresponding layer. Older Docker clients require this; newer ones allow it to be absent and substitute -1.

Response body is a JSON-formatted Image object.

Session.GetRemoteImageLayer

GET server1/v1/images/IMAGEID/layer
Authorization: Token xyz

Response
Image contents
The Docker client will try to do a resumable transfer if the server returns "Accept-Ranges: bytes".

Life of a docker push

TagStore.pushRepository

TagStore.getImageList

Prepare a list of all images in repository, with parents before children. From the returned list, create an array of ImgData values with Id and Tag set.

If an image is tagged multiple times then there is an (ID, Tag) pair for each tag. If an image is untagged, it is implicitly tagged as "". (The Tag field is omitted in JSON if it's empty, so what’s the point?)

Session.PushImageJSONIndex (validate = false)

PUT H:P/v1/repositories/R/
Content-Type: application/json
Authorization: Basic abc
X-Docker-Token: true

Request is a JSON array of ImgData values. Only ID (as "id") and Tag are set. In encoding, Tag is omitted if empty.

Response
X-Docker-Token: xyz
X-Docker-Endpoints: server1, server2

Manually handles arbitrarily many redirects (300 <= ResponseCode < 400). Each redirect sends the request as before. Server response code must be 200 or 201 for success.

For each image:

Session.LookupRemoteImage

GET server1/v1/images/IMAGEID/json
Authorization: Token xyz

TagStore.pushImage (if the request to /json in LookupRemoteImage did not return 200)

Session.PushImageJSONRegistry

PUT server1/v1/images/IMAGEID/json
Content-Type: application/json
Authorization: Token xyz

Body is JSON formatted Image object.

Session.PushImageLayerRegistry

PUT server1/v1/images/IMAGEID/layer
Content-Type: application/octet-stream
Transfer-Encoding: chunked
Content-Length: -1
Authorization: Token xyz

Layer (.tar.gz) is read through TarSum.Read to create request body.
TarSum is frightening. Let's never use it for image authentication or identity.

Session.PushImageChecksumRegistry

PUT server1/v1/images/IMAGEID/checksum
Authorization: Token xyz
X-Docker-Checksum: tarsum+sha256:a0b1c2...
The TarSum calculated above.
X-Docker-Checksum-Payload: sha256:a0b1c2...
Payload checksum is "sha256:" + SHA256(json + "\n" + PAYLOAD), where PAYLOAD is the tar+gz’d layer that was actually sent as the request body.

For each of the image's tags:

Session.PushRegistryTag

PUT server1/v1/repositories/R/tags/T
Authentication: Token xyz
Content-Type: application/json

Request body is "IMAGEID" (with quotes).

Session.PushImageJSONIndex (validate = true)

PUT H:P/v1/repositories/R/images
Authentication: Basic abc
There doesn't seem to be a good reason here to use Basic authentication rather than the existing Token.

Request body is an array of ImgData values, same as before, except only images with a checksum set are included -- i.e. only the images uploaded this session.

Response
Server must return 204 on success.

Common infrastructure

Cookies

The Docker client keeps a per-session set of cookies that is used and updated on each request. Cookies are not persisted across sessions.

The Docker Hub used to use these cookies for authentication, but stopped -- see the discussion in issue 330 for some context. As of this writing, quay.io still uses cookies for authentication. Since Docker Hub doesn't use cookies, there's some question as to whether they'll be tested or keep working in future Docker client versions. It may be more robust to return data in the authentication token.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment