When you need to push or pull a container image, the default answer is often an external registry - Docker Hub, GHCR, ECR, and so on. But there are plenty of situations where you want a registry of your own:
- An internal registry for the team to publish and consume images without leaving the corporate network.
- A mirror registry in an air-gapped environment.
- A registry alongside a
kindork3sKubernetes cluster so it can pull locally-built images. - A throwaway endpoint for an integration test that pushes and pulls images.
- A scratch sandbox for experimenting with image layouts, manifests, or signatures.
In this challenge, you'll stand up such an endpoint yourself. How you do it is up to you - the verifier doesn't care which implementation you pick, only that the endpoint behaves like a registry, and the pushed images persist across a stop/restart cycle.
The task
Expose an unauthenticated, plain-HTTP container registry on:
http://localhost:5000
The endpoint must be an OCI Distribution compatible registry.
Hint 1
A container registry is just an HTTP server that implements the OCI Distribution Spec API. In particular, the following endpoints are required:
GET /v2/- version probeGET /v2/<repo>/tags/list- list tags in a repositoryGET /v2/<repo>/manifests/<tag>- download a manifestPUT /v2/<repo>/manifests/<tag>- upload a manifest
Of course, you don't have to implement any of this yourself - there are plenty of off-the-shelf OCI-compatible registries available.
Hint 2
The most common approach is to run the upstream reference implementation -
the distribution/distribution project,
published as the registry container image on Docker Hub.
Other lightweight options:
zot- a vendor-neutral OCI-native registry written in Go.crane registry(part ofgo-containerregistry) - a simple registry meant for testing. Quick to spin up, but images don't persist across restarts (even when the--diskflag is used).
Pick whichever feels easiest. The verifier inspects the resulting HTTP endpoint as a black box - any implementation that behaves like a registry will do.
Once push, pull, and metadata checks are all green, take the registry down.
The localhost:5000 endpoint should stop responding entirely.
Now bring the registry back up on the same endpoint. After the restart, the previously pushed images must still be available - so the registry's storage has to survive a stop/restart cycle.
Hint 3
For the persistence step, the registry's storage has to outlive a single process or container:
- If you're running the
registry:3container,docker stopfollowed bydocker start(of the same container) preserves the data in the container's writable layer. Adocker rm+ freshdocker run, however, only keeps the data if you mounted a host directory or named volume at the registry's data path. - For
zot, mount a named volume or host directory at the path you set in itsstorage.rootDirectoryconfig field. The data will survive across stop/start, re-creation of the container, and host reboots. crane registry serve --disk <path>is not sufficient on its own - even with on-disk storage, it only persists the image blobs, not the tag-to-manifest index, so pulls by tag fail after a restart.