Tuesday, July 19, 2016

A Private Registry. Building and Using

Recently, I received some questions on how to create a private registry. Specifically when going to a recent version, building on your own might make sense. Since describing this last (here and here), this can even be done simpler.

Let's start the build:
git clone https://github.com/docker/distribution.git
cd distribution/
git checkout v2.4.1
There is a Dockerfile in that directory, which is used to build the registry. In the x86 space, a golang image based on alpine is used, but since alpine is not yet available on s390x, we'll go with Ubuntu. Therefore, we need to adapt the base image and the place in the Dockerfile, where packages are updated. I used an Ubuntu, and my Dockerfile looks like this (changes in italics, the first few lines):
FROM s390x/ubuntu

RUN apt-get update && \
    apt-get install -y librados-dev apache2-utils git golang && \
    rm -rf /var/lib/apt/lists/*


ENV GOPATH=/go

ENV PATH=$PATH:/go/bin
ENV DISTRIBUTION_DIR /go/src/github.com/docker/distribution
ENV DOCKER_BUILDTAGS include_oss include_gcs

WORKDIR $DISTRIBUTION_DIR
COPY . $DISTRIBUTION_DIR
COPY cmd/registry/config-dev.yml /etc/docker/registry/config.yml
RUN make PREFIX=/go clean binaries

VOLUME ["/var/lib/registry"]
EXPOSE 5000
ENTRYPOINT ["/go/bin/registry"]
CMD ["serve", "/etc/docker/registry/config.yml"]
This takes Ubuntu as a base and installs golang on it -- a good base for building it. Then
docker build -t distribution:2.4.1 .
starts the build. That is actually it.
Any images tagged with "hostname:5000/image-name" will now be pushed/pulled from/to that registry. However, by default, this is still an insecure registry, since no certificates are in place to avoid e.g. man-in-the-middle attacks. To tell docker you are aware of this, you need to start the docker daemon with "--insecure-registry hostname:5000".

A way out are signed certificates, and as long as we do not want to have them signed by some recognized CA, go with self-signed certificates:

mkdir certs
openssl req -newkey rsa:4096 -nodes -sha256 -keyout certs/hostname.key  -x509 -days 365 -out certs/hostname.crt

# enter your certificate data. hostname should be your hostname or FQDN
cp certs/hostname.crt /usr/local/share/ca-certificates/
Now the system certificates need to be updated. On SLES and Ubuntu systems, this can be done by executing "update-ca-certificates", on RHEL systems, it is "update-ca-trust". Note the command can take a while.
Copying the crt file into /usr/local/share/ca-certificates/ and updating the certificate list has to be done on every node using the registry (otherwise, the registry is still considered insecure from that node's view). After updating the certificate store on each node, the docker daemons needs to be restarted ("service docker restart"), and the insecure-registry option will be history.

Finally, let's have the registry store all data in a local directory called data (you might want to place it into a backed up location), and start the registry using:

docker run -d -p 5000:5000 --restart=always --name registry \
  -v `pwd`/certs:/certs \

  -v `pwd`/data:/var/lib/registry \
  -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/hostname.crt \
  -e REGISTRY_HTTP_TLS_KEY=/certs/hostname.key \
  distribution:2.4.1
Done, your registry is up.

As you will notice, there is no GUI for it like on Docker Hub. Either use additional tooling (Portus, Nexus 3, Docker Trusted Registry, ...) for that, or use your own curl scripts to operate on the registry:
curl -s -X GET https://hostname:5000/v2/_catalog
will display all the repositories on the registry. I leave the JSON parsing to you...
Accordingly, this will list all the tags of a repository "repo":
curl -s -X GET https://hostname:5000/v2/repo/tags/list
Enjoy managing your images.

No comments:

Post a Comment