We all know and love Docker, a platform to create, manage and distribute application containers across multiple machines. Docker Inc. provides a service to host open source containers to be downloaded (or pulled) like a git repository known as the “Docker Registry.” Think of it like a GitHub for Docker containers.
But what if you want to host your own registry separated from the public one? Well, Docker Inc. has open sourced their Registry application on GitHub.
This tutorial will take you though the process of setting up a private Docker registry using CoreOS on a new VPS.
CoreOS + Docker
We won’t be spending a ton of time going over exactly what Docker and CoreOS can do, as it’s outside the scope of this tutorial. In essence, CoreOS is designed for massive server clusters, it’s small, fast and gets regular security updates automatically. Its root file system is also read-only, meaning you must use Docker to run any kind of software that is not included with the base install.
This makes Core OS a perfect host system for Docker!
Pulling and running the latest registry
Docker Inc. has provided the Registry as a top level image, this means that we can pull it down with a simple:
docker pull registry
This can take a few minutes depending on the connection speed.
A plus of being a top level image also means it gets regular support and updates.
Now let’s test out the registry. We can create a new container using the registry image:
docker run -p 5000:5000 -d --name=basic_registry registry
For those who haven’t used Docker too much, the
-p flag stands for
PORT, meaning we are exposing port 5000 on from the container onto host port 5000.
-d flag stands for
daemon, this will cause the container to run in the background and not print output to the current SSH session, we also want to name this basic test container using the
--name option so that we can easily manage it later.
Make sure that your basic registry container is running using
docker ps. The output should look similar to:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES edfb54e4a8c4 registry:0.8.1 "/bin/sh -c 'exec do 7 seconds ago Up 6 seconds 0.0.0.0:5000->5000/tcp basic_registry
http://YOUR_IP:5000 in your web browser, and you should get a message like the following:
"docker-registry server (dev) (v0.8.1)"
Notice the word
devin the parenthesis. This means that the server is currently running the dev config. We’ll look over more configuration soon.
You now have your own (very basic) container registry running! But we’re not done yet.
Maybe you want to keep this private from prying eyes, or maybe store your images on Amazon S3 instead of local storage. Let’s go over the various configuration options in the next section.
Before we move on, let’s kill the test container so that we don’t run into conflicting ports.
docker kill basic_registry
There are two ways that we can pass configuration to the Docker Registry. One way is by passing environment variables to a new container, and the other is to add a configuration file.
Here’s a few of the common configuration options we’ll be using:
loglevel– The minimum amount of information to log to the console. Default is
standalone– Should this Registry act on its own? (Never queries the public registry.) Default is
index_endpoint– If not standalone, what other index will we query? Default
cache_lru– Options pertaining to using a Redis cache for small files, we’ll touch on this later.
storage– What storage backend should we use for this server? (In this tutorial we’ll be using local).
storage_path– If using local storage, what directory should we use to keep files in?
Before we get working with the configuration, we need a base file to work with. The file from the Docker Registry repository on GitHub will work just fine:
The file should save successfully with an output such as:
2014-09-14 14:09:01 (156 MB/s) - 'config_sample.yml' saved [5384/5384]
Great! Now we can modify this file to fit our needs.
The only text editor that comes with Core OS is
vim, but don’t worry if you’ve never used it before, this will explain step by step what to edit and how to do it.
Once you have the file open, hit the
I and the bottom right corner should display:
-- INSERT -- for insert mode. Scroll all the way to the bottom of the file using your arrow keys, you should see a section labeled
We’ll be changing the two lines, the changes are below
prod: <<: *local storage_path: _env:STORAGE_PATH:/data
What we’ve done is change the
prod configuration to derive from the
local section instead of the
s3 section. Then we overwrote the
storage_path to use the path
/data inside the new container.
Once you’ve confirmed that all the changes are correct, hit
ESC to exit insert mode and type
:wq (this means write the changes to the file, and quit vim.)
Now let’s rename the file to just
mv config_sample.yml config.yml
Redis caching (optional)
If you’d like to use redis to speed up your container registry, it’s as simple as pulling a new container from the public registry and adding a few more lines of configuration.
First, pull the top level image of Redis:
docker pull redis
Once the image is pulled successfully, we can run it and name it just like we did with the test registry:
docker run -d --name registry-redis redis
Because redis is in memory, we don’t need to do any configuration for it, as we will link it to the registry container in later steps.
Once again, ensure it’s running by using
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 54f65641eccf redis:2.8 "redis-server" 2 seconds ago Up 1 seconds 6379/tcp registry-redis
Now re-open the
vim and enter insert mode just like the first time we edited it.
Add the following lines below the
prod section, being sure to indent properly. This time we’re only adding
cache: host: _env:REDIS_PORT_6379_TCP_ADDR port: _env:REDIS_PORT_6379_TCP_PORT db: 0 cache_lru: host: _env:REDIS_PORT_6379_TCP_ADDR port: _env:REDIS_PORT_6379_TCP_PORT db: 1
The environment variables
REDIS_PORT_6379_TCP_PORT are passed to the registry container upon linkage with the Redis container.
With that, you now have setup a Redis container that will work hand-in-hand with your registry container. Now onto building the registry!
Building the container
We have all the configuration set and ready, now we need to build the actual registry container.
vim Dockerfile to create a new Dockerfile. Enter insert mode and follow the edits below.
FROM registry:latest # Add the custom configuration file we made ADD ./config.yml /docker-registry/config/config.yml # Create the data directory RUN mkdir /data # Set the configuration file to config.yml env DOCKER_REGISTRY_CONFIG /docker-registry/config/config.yml # Make sure we use the prod configuration settings env SETTINGS_FLAVOR prod
What we’ve done above is essentially extend the registry image so it will use our configuration file and settings. A Dockerfile is a set of build instructions for Docker to read and build. If you’d like to learn more on Dockerfiles and their syntax, take a look at the official Docker site documentation.
Next we need to build the container for use.
docker build -t my_registry . Sending build context to Docker daemon 13.82 kB Sending build context to Docker daemon Step 0 : FROM registry ---> e42d15ec8417 Step 1 : ADD ./config.yml /docker-registry/config/config.yml ---> 4339f026d459 Removing intermediate container 2d5138fbcd34 Step 2 : RUN mkdir /data ---> Running in a090f0bdbfd1 ---> 8eb27ba6e12a Removing intermediate container a090f0bdbfd1 Step 3 : env DOCKER_REGISTRY_CONFIG /docker-registry/config/config.yml ---> Running in 565b5bfb2b22 ---> 914462e46dc0 Removing intermediate container 565b5bfb2b22 Step 4 : env SETTINGS_FLAVOR prod ---> Running in 31a92847b851 ---> b5949575c374 Removing intermediate container 31a92847b851 Successfully built b5949575c374
Now we are ready to run!
Let’s make a directory on our host system to mount in the container as the
Now we can spin up a new container. If you plan on using the Redis cache, use the 2nd command below.
# For a non-Redis cache registry docker run -d -p 5000:5000 -v /home/core/registry-data:/data --name=private_reg my_registry # For a Redis cached registry (Must have followed Redis Caching section above) docker run -d -p 5000:5000 -v /home/core/registry-data:/data --name=private_reg --link registry-redis:redis my_registry
To ensure that your server is running correctly, visit
http://YOUR_IP:5000. You will see the following message:
"docker-registry server (prod) (v0.8.1)"
(prod) meaning our configuration changes were successful!
Configure your local Docker client
Now that we have our own running registry, we want the Docker client on our local machines to start using it. Usually you would use the command:
docker login, but for our use, we need to add one more argument to the login command:
docker login YOUR_IP:5000
Enter a username and password (think of this like making a new account) and ignore the message that states you must activate it.
Next, let’s pull a stock image, and push it up to our own repository.
# Pull the busybox image from the public registry docker pull busybox # Tag it with our IP/URL docker tag busybox YOUR_IP:5000/busybox # Push it to our newly made registry docker push YOUR_IP:5000/busybox
If everything pushes correctly the final message should be along the lines of:
Pushing tag for rev [a9eb17255234] on
Congratulations! You have setup your very own docker repository.
Here’s some ideas on how to improve your new private registry:
- Reverse proxy using Nginx or Apache to place additional security in front of it, like simple HTTP auth.
- Get a domain for your server and setup it up so you may access your registry with something like: registry.mysite.com
- Purchase (or self-sign) an SSL certificate to add even more protection if your containers contain sensitive information.