So the v2 implementation of the Docker Registry is out. You can find it here. As I continue to experiment with containerization I though it would be nice to have a private registry for me to work out of.
Before you begin!
In order for this to work you need to be running docker ~> 1.6. I'm using 1.8.3 in this example. You will also need an image to push so if you don't have one feel free to clone my chrome running in docker image.
Follow the instructions for how to build it...it's in the README.
Bring me a Registry!
If you didn't read that in the voice of the Knights Who Say Ni then go back and do that now. It's OK, I'll wait while you look them up...actually Let me google that for you. Can we move on now? Good. While you can build the registry from scratch it's actually easier to just pull it from the official Docker Repo, and for the purposes of this document that's what we are going to do. Fire up a ssh session to your favorite instance and:
The tag part is important because if you just pull the registry you are going to get v1 and who wants v1 of anything? We are containerizing people! Living on the bleeding edge!
Once you have the registry down we can quick launch it like so.
docker run -d -p 5000:5000 --restart=always --name registry registry:2
This starts our registry container, maps port 5000 on the host to 5000 in the container gives it a name of registry and also introduces us to the restart policies.
Container restart policies do exactly what you think they should. If your container crashes for any reason the Docker daemon will try to bring it back up. The default is no, but you can also specify max retries and always.
With our registry running let's tag an image to our local repo and push it.
docker tag docker-chrome localhost:5000/docker-chrome
Before you start complaining about the longish format of private container names remember that the root namespace, ie busybox, is really index.docker.io/library/busybox. Docker shortens that down for you so that you don't have to type it all out, but you need to get used to working with fully qualified image names or FQIN. FQIN's allow you to specify any private registry to push and pull from so whereas typing
docker pull busybox is going to get expanded to
docker pull index.docker.io/library/busybox typing
docker pull localhost:5000/busybox is going to get you the version that would be hosted internally if in fact you hosted library images internally, which you don't.
With our chrome image tagged go ahead and push it to the registry.
> docker push localhost:5000/docker-chrome
The push refers to a repository [localhost:5000] (len: 1)
0e16757e7b5d: Image already exists
9fb555344e55: Image already exists
223b636e1f84: Image already exists
0567a7a943c5: Image already exists
4a275333f760: Image already exists
50a59a17c41c: Image already exists
319c8b61759b: Image already exists
a8a49eee0527: Image already exists
abf780c5faaa: Image already exists
d64fc71e054c: Image already exists
302e187e53f6: Image already exists
f359075ce4d8: Image already exists
latest: digest: sha256:6390e332b841087a5ff94d25a82a0a675dc7ee92d5509893e245bd61efee897c size: 20487
Your push is going to look slightly different since you wont already have the image in your registry. Now delete the image from your system with
> docker rmi localhsot:5000/docker-chrome
and download it again with
> docker pull localhost:5000/docker-chrome
Using default tag: latest
latest: Pulling from docker-chrome
cea0f0c83002: Pull complete
e0c92a5263ea: Pull complete
5d1c42bc22e0: Pull complete
29bb38f6024f: Pull complete
5f7e11028271: Pull complete
57139ca9a9b7: Pull complete
617feda6b6d2: Pull complete
62ce07b6ddc0: Pull complete
aceddd13fdf9: Pull complete
f359075ce4d8: Already exists
302e187e53f6: Already exists
d64fc71e054c: Already exists
Status: Downloaded newer image for localhost:5000/docker-chrome:latest
To stop your registry you would
docker stop registry && docker rm -v registry
One big thing to pay attention to is the storage backend for registries. By default data is stored in a docker volume which is NOT persistent, meaning that if you rm -v your registry your content is gone. Docker has a bunch of storage drivers. The easiest thing to do is mount a data volume so you get something like this
docker run -d -p 5000:5000 -v /docker/registry:/var/lib/registry --restart=always --name registry registry:2
Having your own local registry is fun, but what if you want to run your own domain registry? The v2 registry lets you do this but also enforces the use of TLS, which means you are going to have to generate some SSL certs. You still need to get a real SSL cert for your registry though so go ahead and get one from somwhere like startssl. Until you do that make your life a little easier by pulling the openssl container from centurylink labs.
docker pull centurylink/openssl
This nifty little container already has the openssl bits you need to make your very own self signed certs. Run it like so
docker run --rm -e COMMON_NAME=<Common Name> -e KEY_NAME=<Cert File Names Prefix> -v /docker/certs:/certs centurylink/openssl
Where the common_name is the fqdn of your registry, reg.johnray.io in my case, and the Key_Name is just a prefix.
Now you should have a .key, .crt, and .csr in /docker/certs. Let's blow away our old insecure registry and replace it with a brand new one.
docker stop registry && docker rm -v registry
docker run -d -p 5000:5000 --restart=always --name registry -v /docker/certs:/certs -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/<prefix>.crt -e REGISTRY_HTTP_TLS_KEY=/certs/<prefix>.key registry:2
Using a self signed cert does have one itty bitty problem. You have to tell docker to explicity trust the cert.
sudo mkdir /etc/docker/certs.d/<fqdn>:5000 && sudo cp /docker/certs/<prefix>.crt /etc/docker/certs.d/<fqdn>:5000/ca.crt
sudo service docker restart
Remember when I told you to get a real SSL certs several paragraphs ago? This is why. You need to do this on EVERY docker host that will connect to your registry. Although once you do you will be able to push from other hosts to your fqdn:port.