Docker Registry v2: Adventures in Ambiguity
All I need is a private Docker registry that I can host myself.
If you're anything like me, you've been excitedly awaiting the release of the v2.0 Docker Registry. Version 1 was not very good. The company behind Docker is in no hurry to bite the hand that feeds them, and so development of the registry has been spotty at best. Among other things, the documentation is not great and the registry has no built-in authentication protocol. I understand that it's much better for business to get people frustrated with setting up their own private registry and then point them at your hosted services, where it's very easy to write a check to have someone else take care of this mess for you. But I am not in the habit of writing checks, and my check would probably bounce anyways.
The documentation available for deploying a v2 registry is specific to one situation. It is a set of instructions for using Compose (yet another Docker technology with a seemingly nebulous purpose at this time) to get both a v1 and a v2 registry working behind an Nginx proxy. But as I am using the Nginx Docker reverse proxy by Jason Wilder, so I don't need to bring in an external Nginx server. Nor do I need to answer requests for a v1 registry, as I am not using any Docker clients earlier than version 1.6.0.
All I need is a private Docker registry that I can host myself.
So... What we need to do is rip out all the extra stuff so that we're left with what we need. We don't need a v1 registry, so ignore all that. We're using jwilder/nginx-proxy to proxy our inbound requests, so ignore the instructions about pulling in the Nginx server. The average docker user right now doesn't really know what Compose is for or what it does -- though it will reduce complexity for most of us some day in the future -- so just ignore all the cruft about Compose. We're left with something close to what we're looking for.
First, clone the Distribution repository from Github and change into that directory:
git clone https://github.com/docker/distribution && cd distribution
We'll build our registry server from this repository:
docker build -t=registryv2 .
Now our container will build and should be listed in the output of docker images. We're almost there, but first we need to configure the registry. The future may include something I've talked about before called the docker vault, which is a cryptographically-secure, in-container, ephemeral storage mechanism which holds our sensitive configuration data. But for the moment, we don't have access to the vault because it doesn't exist. Here, we're going to have to rely on storing configuration data in a file, and then mount a volume on the host which exposes our config file to the container.
The v2 registry currently reads configuration data from cmd/registry/config.yml, so we need to map a directory on the host to this directory in the container. If you're trying to configure a v2 registry, just totally forget about everything related to configuring a v1 registry. The new configuration options are in the documentation. I'll include my own sanitized debug mode configuration file so you've got a sanity check reference:
version 0.1
log:
level: debug
fields:
service: registry
environment: staging
storage:
filesystem:
rootdirectory: /registry
cache:
layerinfo: inmemory
http:
addr: :5000
secret: somerandomstring
debug:
addr: localhost:5001
This is all pretty self-explanatory, if you've played with running any version of a docker registry. I'm running this on tcp/5000 during development for testing purposes. We are also running the server to listen on tcp/5001 (on local loopback only) if we need to connect and get some verbose debug information.
Now for production mode configuration, I use a different setup, which is more like something you'd expect to see out there in the real world:
version 0.1
log:
level: info
fields:
service: registry
environment: staging
storage:
s3:
accesskey: AKIA0Z6307DRPWJ5VH03F
secretkey: OgP2Yhk1ZjFFf+aYokvnqI3qTlenCxSW2nbb9zpB
region: us-west-1
bucket: example.com-docker-registry-v2
encrypt: false
secure: true
v4auth: true
chunksize: 5242880
rootdirectory: /registryv2
cache:
layerinfo: redis
http:
addr: :443
secret: ZpAedwVDFHK7mkNFFKSP8OQY
debug:
addr: localhost:5001
redis:
addr: localhost:6379
db: 0
Here, we're setting our registry to use an AWS S3 backend (that configuration data is of course dummy data, but feel free to try it, leet). We're also using a Redis container for caching, which speeds things up considerably. Again, the jwilder/nginx-proxy container auto-detects which port is exposed on a container, and I want this registry to listen on HTTPS (tcp/443), so I've changed its listen port appropriately.
So, because our registry is going to use Redis for caching, we need to spin up a Redis instance and link it to our registry container. Real quick, let's pull that Redis image:
docker pull sameersbn/redis
Now run it:
docker run -d --name="registryv2-redis" --restart="always" sameersbn/redis
And when I run my registry container, it looks something like this:
#!/bin/bash
docker run -d \
--name="registryv2" \
--restart="always" \
--link registryv2-redis:redis \
-v /var/docker/registryv2/config:/go/src/github.com/docker/distribution/cmd/registry \
registryv2
Finally, it's not clear in the documentation, but to create a repository on your new v2 registry, you've got to tag your images correctly. Let's suppose for a second you have just created an image called myContainer and you'd like to create that on your new v2 registry:
docker tag myContainer:latest registry.example.com:443/myContainer:latest
This command tags your container not only with the latest tag, but also specifies exactly which registry you want to use for your new repository. Now you can push this image to your new v2 registry. Enjoy!
