Composing a Docker Hub Mirror and Private Registry

Building on mirroring the Docker Hub, I next wanted a way to share private Docker images between my main Docker host and with Docker Machines on VMs. Of course, I could have gone the route of subscribing to a service like Quay or even Docker Hub's own private plans, but again I'm limited on my bandwidth supply and, this would also mean re-downloading images across VMs, which is very wasteful.

It turns out that I can also run local private registries on the same host as my mirror as its own container, and what's more, I can put these all together in a simple Docker Compose system.

A simple Registry Mirror container

Using a Docker Compose v3 configuration, I can set up a service like this:


  registry_mirror:
    container_name: registry-mirror
    restart: always
    image: registry:2
    environment:
      REGISTRY_STORAGE_DELETE_ENABLED: "true"
      REGISTRY_PROXY_REMOTEURL: "https://registry-1.docker.io"
    ports:
      - "50000:5000"
    volumes:
      - mirror:/var/lib/registry

Note that I give a proper name to the container instead of letting Docker Compose name it for me, so I can easily check on its status or logs via e.g docker logs -f registry-mirror.

I have a pretty simple configuration here, but if I need a more sophisticated one, I can just update the environment hash with new settings.

A private Docker Registry container for local

For building and sharing private images, I have this other service:


  registry_private:
    container_name: registry-private
    restart: always
    image: registry:2
    ports:
      - "50001:5000"
    volumes:
      - private:/var/lib/registry

Nearly zero customization on the registry config, other than a different exposed port.

Docker volumes for image storage

For the meantime, I keep the image storage of both registry services in simple Docker Compose named volumes:


volumes:
  mirror:
  private:

Putting it all together

I have this all down in a GitHub repo, such that starting the Compose system is as easy as a docker-compose up -d.

The only other thing to do next is to make your Docker host (or Docker Machine VMs) use these registries. For the registry mirror, we need to run dockerd with --registry-mirror, while for the private registry, we use --insecure-registry. On systems with a /etc/docker/daemon.json, the configuration would look like this:


  {
      "insecure-registries": ["127.0.0.1:50001"],
      "registry-mirrors": ["http://127.0.0.1:50000"]
  }

Extra: Using the same Registries on all Docker Machines

Perhaps the best use case for setting this all up is when you want to have several Docker Machines using these registries. In my case, all I have to do is to deploy these like this:


docker-machine create --driver=kvm --engine-registry-mirror=http://192.168.122.1:50000 --engine-insecure-registry http://192.168.122.1:50001 my-machine

In my reference libvirt/KVM setup, my Docker host running this Registry Compose system is listening on 192.168.122.1 as well a localhost. This means that on my-machine, I can pull private images like e.g. docker pull 192.168.122.1:50001/my-private-image:4.2 while still being able to fetch Docker Hub hosted images like normal.