docker Docker Private Registry 103: Nginx front container

Serving your registry directly from the python app / registry container has several drawbacks. First, you can't bind it to a specific vhost. Second, if your ip is also used to serve something else (web), you won't be able to use port 80, forcing users to use an uggly :5000 in their image names. And last, you don't have a fine control over http serving stuff, like throttling, authentication, restrictions (ip ...) etc...

Although you may not need it for your specific needs, my advice is to use an nginx termination that will give fine control on your server. And the good news is that it's damn fucking easy to do, using a container, of course.

Create a container for nginx

You have two choices here (right, you have more than two, but I'll discuss only those two)

  • Throw in configuration at runtime: use nginx default image (https://registry.hub.docker.com/_/nginx/) and use docker volumes to add your specific configuration.
  • Throw in configuration at build time: create a Dockerfile that is based on the above image, and put your configuration in a new, custom, specific image for your exact usage.

Throw in configuration at runtime

The easiest (but less flexible) way is to start a nginx container, with a configuration file (or configuration directory) passed as a volume.

docker run --name my-nginx -v /my/configuration/directory:/etc/nginx/conf.d:ro -d nginx:1.7

Any file matching *.conf in this directory will be included by nginx main configuration file. Here is an example registry.conf (based on a simplified version of https://github.com/docker/docker-registry/blob/master/contrib/nginx/nginx.conf).

upstream docker-registry {
        server registry:5000;
}

server {
        listen 80 default;
        server_name my.docker.registry.example.com;

        client_max_body_size 0;

        location / {
                proxy_set_header  Host           $http_host;
                proxy_set_header  X-Real-IP      $remote_addr;
                proxy_set_header  Authorization  "";
                proxy_read_timeout               900;
                proxy_pass http://docker-registry;
        }
}

Container will refuse to run (or more precisely, will stop because of a nginx configuration problem) if you try to run it. This is because "registry" (used in upstream) is not resolvable from with the nginx container.

Now that we created a strong dependency between the two containers, we need to run them in the right order, and setup the links when running a dependant container.

docker run --name registry ...your conf here... registry
docker run --name my-nginx -v /my/configuration/directory:/etc/nginx/conf.d:ro --link registry:registry -d nginx:1.7

If a container already exist, you need to stop-kill-rm it before you can run it again, but it should sound familiar to anyone who played a bit with docker.

Build your own docker image

This is in my opinion a more flexible way to do it, and it's only a few minutes more to set it up.

First, create a repository for your front container.

mkdir nginx-front
cd nginx-front
git init

Then retrieve the default configuration that you can find in a bare nginx container. You need to run a nginx container once, to make the filesystem available, but you don't have to keep it running, so we'll just run true (which is much more optimistic than false, imho, although the result is the exact same).

docker pull nginx:1.7
docker run nginx:1.7 true
ID=`docker ps -ql`
docker cp $ID:/etc/nginx .
git add nginx
git commit -m 'import nginx config from container'

Great. Now just add the registry.conf file that we created before to the nginx/conf.d directory after emptying it.

rm nginx/conf.d/*
cp /path/to/my/registry.conf nginx/conf.d/

Add to git, commit (well if you want).

Let's add a Dockerfile to build our image.

FROM nginx:1.7
MAINTAINER John Doe <john@example.com>

COPY nginx /etc/nginx

Build an image...

docker build -t my-nginx-front .

And run it (note that you must have a registry running under the container name registry for this to work, docker will refuse links to non existent containers). You can change the destination port if you're working locally, I use 80 here as it's probably what you want on your target server, but you probably want a higher port on a local dev machine, for example with -p 8080:80.

docker run -d --name my-nginx --link registry:registry -p 80:80 my-nginx-front

Next in serie — Security, what's up? (writing in progress, coming soon!) →

Share the love!

Liked this article? Please consider sharing it on your favorite network, it really helps me a lot!

You can also add your valuable insights by commenting below.