Contents


Set up a Docker Registry as a pull-through cache on Raspberry Pi

Save time and bandwidth using the Pi with Docker

Comments

If you have a slow internet connection and multiple users downloading Docker images, then why not use it as a cache on a Raspberry Pi? This can save you time and bandwidth when using Docker. Raspberry Pi is amazing, because it is portable, cheap, and consumes negligible power. By creating the solution described in this tutorial, every time you download an image, it will be cached on the Pi; then, for all subsequent requests, the same image will be delivered from the local cache.

Docker is a popular DevOps tool that provides a platform for developers and sysadmins to build, ship, and run applications anywhere. This means that a developer can build Docker images on a local machine, ship them to a registry, and run them on the cloud server. A registry is to Docker images what Git is to code.

The setup covered in this tutorial can help you save time as well as bandwidth. Raspberry Pi is amazing because it is portable, cheap, and consumes negligible power.

Docker Hub is a popular registry that allows its users to host images for free. If you have a group of developers who are working together with Docker in the same location with a slow internet connection or limited bandwidth, and all pulling images from Docker Hub, then you may face some performance challenges. You can set up a private Docker Registry on the local network as a pull-through cache, so that every time you download an image it will be cached, and for every subsequent request the image will be delivered from the local cache. This can save you precious bandwidth and a lot of time, too. For example, an Ubuntu-based image that's cached by the proxy can be downloaded multiple times on different machines, but will be fetched only once from Docker Hub.

In this tutorial, you will use Raspberry Pi as a pull-through cache for Docker Hub. Raspberry Pi is a small, credit-card-sized computer that consumes very little power and is capable of handling much of what a full PC can do. We will walk through setting up a Raspberry Pi from scratch, installing Golang on Raspberry Pi, and compiling Go binaries (since Docker Registry is written in Golang, a cross-platform language). If all goes well, you can set up everything in a couple of hours. Let’s start by going over some prerequisites.

Required hardware and software

Before getting started, make sure you have the following hardware available:

You will also need to have the following software installed:

Setup

Let's begin by setting up the Raspberry Pi. If you have a running Raspberry Pi, then you can skip this step. There are many distros available for Raspberry Pi, but in this example we use Raspbian, the official distro provided on the Raspberry Pi website.

Download Raspbian

Open a new terminal window and download the Raspbian image with wget, which comes preinstalled on most Linux distributions:

$ mkdir -p ~/rpi-registry
$ cd ~/rpi-registry
$ wget https://downloads.raspberrypi.org/raspbian_lite/images/
raspbian_lite-2017-04-10/2017-04-10-raspbian-jessie-lite.zip

This will download the distro image inside the "~/rpi-registry" directory on your machine. Verify the integrity of the downloaded image using the SHA checksum with the upstream SHA by doing the following:

$ shasum 2017-04-10-raspbian-jessie-lite.zip
c24a4c7dd1a5957f303193fee712d0d2c0c6372d  
2017-04-10-raspbian-jessie-lite.zip

If there is a mismatch in the SHA checksum, then you must re-download the image. If you are on a slow internet connection, then you should use the torrent option for download.

Prepare the SD card

To install the Raspbian on the SD card, you will use a tool called Etcher, which you can download from https://etcher.io. Etcher is an application that burns images onto SD cards and USB drives. It is available for Windows, Linux, and Mac OS X. Attach the SD card to your laptop or desktop and open Etcher. Then select the downloaded Raspbian image and ensure that it has detected your SD card before you click on Flash! (see Figure 1). It will take a few minutes to burn the image onto your SD card.

Figure 1. Etcher burns an image to the SD card
Screen capture of Etcher burning an image to the SD card
Screen capture of Etcher burning an image to the SD card

Here you are setting up a headless Pi, which means you won't be attaching a keyboard or a monitor to your Raspberry Pi, so you need to enable SSH on your first boot. This is required because the latest Raspbian builds disable SSH by default. To do this, create a file named "SSH" in the boot partition of the SD card before the first boot. The file must not have any extension and can be empty or a text file.

You can do this by opening the SD card in File Explorer or from the terminal. On Mac OS X, the mount path is /Volumes/boot:

$ cd /Volumes/boot
$ touch ssh
$ ls -la
...
-rwxrwxrwx  1 kn330  staff  4235224 Mar  2 16:52 kernel7.img
drwxrwxrwx  1 kn330  staff     8704 Apr 10 09:57 overlays
-rwxrwxrwx  1 kn330  staff        0 Jun 11 03:04 ssh
-rwxrwxrwx  1 kn330  staff  2848068 Apr  7 14:39 start.elf
...

The SD card is now ready to boot. Insert the card into the Raspberry Pi and attach it to your home router.

SSH login

To login, you will need the IP address of Raspberry Pi, which you can find on the router’s admin page. Most routers have admin pages served on 192.168.1.1, but it can be different for you so you should manually look up your router (see Figure 2). You can also use network scanning tools like Nmap for this.

Figure 2. Your router contains the Pi’s IP address
Your router contains the Pi’s IP address
Your router contains the Pi’s IP address

Once you have the IP address, you can use Secure Shell (SSH) by entering pi as the username and by entering raspberry as the password, which is the default username and password for using the Raspbian operating system that comes with the Pi:

$ ssh pi@192.168.1.2
pi@192.168.1.2's password:
The programs included with the Debian GNU/Linux system are free
software; the exact distribution terms for each program are described
in the individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
SSH is enabled and the default password for the 'pi' user has not
been changed.
This is a security risk - please login as the 'pi' user and type
'passwd' to set a new password.
pi@raspberrypi:~ $

The Raspbian is now live, so you can move on to setting up the Docker Registry. Note that the IP address assigned to the Pi might change, so you may want to assign it a static IP.

The Proxy: Distributing Docker images

Docker Registry is a stateless, highly scalable server-side application that stores and allows you to distribute Docker images. Docker Hub provides a free-to-use, hosted registry that is the default for all Docker clients, so when you do a docker pull ubuntu, it fetches the image from Docker Hub. You can run a registry cache to store these images locally, instead of constantly pulling them from the internet. To do this, you can self-host a private registry for your home or organization with Docker Registry. This open-source application is written in Golang and available on Github. You can run Docker Registry as a Docker container, but you will be building it from source and executing the binary on bare metal Raspberry Pi.

How it works

The first time any Docker client tries to pull an image, it will fetch the image from Docker Hub and also store a copy on the filesystem. On any subsequent request, you will get served from the local registry rather than Docker Hub. It is smart enough to detect any changes to the image upstream and update the image before serving it to the client (see Figure 3).

Figure 3. The docker_proxy detects any changes
The docker_proxy detects any changes
The docker_proxy detects any changes

Instructions

Golang allows cross-compiling for multiple architectures, which means that you can perform the following steps on your laptop or desktop to build the binaries for Docker Registry and copy them over to the Raspberry Pi. For the sake of simplicity, we will show you how to perform the build process on the Raspberry Pi itself.

Let's start with installing Golang.

Install Golang

The easiest way to install Go is to use gvm (Golang Version Manager), which is similar to rvm for Ruby or virtualenv for Python applications.

pi@raspberrypi:~ $ sudo apt-get update   pi@raspberrypi:~ $ sudo
 apt-get install -y curl git mercurial make  binutils bison gcc 
build-essential pi@raspberrypi:~ $ bash < <(curl -s -S -L
 https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/
gvm-installer) pi@raspberrypi:~ $ source /home/pi/.gvm/scripts/gvm

You may want to add the source /home/pi/.gvm/scripts/gvm to the ~/.bashrc file to avoid sourcing it at every login:

pi@raspberrypi:~ $ go install go1.4
pi@raspberrypi:~ $ go install go1.8
pi@raspberrypi:~ $ gvm use go1.8 [--default]
pi@raspberrypi:~ $ go -v
pi@raspberrypi:~ $ go version
 go version go1.4 linux/arm

Note: Go 1.5 C is not used for compiling, so you need to download Go 1.4 before installing Go 1.8.

Make registry binaries

The Docker Registry repository provides a Makefile that builds the binaries and places them inside the bin directory. Registry is a part of the Docker Distribution repo, so go ahead and clone it:

pi@raspberrypi:~ $ git clone https://github.com/docker/distribution.git
pi@raspberrypi:~ $ cd distribution

Next, install the dependencies:

pi@raspberrypi:~ $ go get ./...

And make the binaries:

pi@raspberrypi:~ $ GOOS=linux GOARCH=arm make binaries

The GOOS and GOARCH environment variables are set to let the compiler know that you are building for the ARM architecture on the Linux operating system. If the make command runs successfully, you will see the binaries in the bin/ directory.

pi@raspberrypi:~/distribution $ ls bin/
digest  registry  registry-api-descriptor-template

Test the binary package

You will need a configuration file to run the registry. Create ~/registry-config.yml and copy the following content into it:

version: 0.1
storage:
  cache:
    blobdescriptor: inmemory
  filesystem:
    rootdirectory: /var/lib/registry
http:
  addr: :5000

You now have everything needed to run the registry, so go ahead and run your own private registry:

pi@raspberrypi:~ $ sudo mkdir -p /var/lib/registry
pi@raspberrypi:~ $ sudo chown $USER /var/lib/registry
pi@raspberrypi:~/distribution $ ~/distribution/bin/registry
 serve ~/registry-config.yml
WARN[0000] No HTTP secret provided - generated random secret. 
This may cause problems with uploads if multiple registries are 
behind a load-balancer. To provide a shared secret, fill in 
http.secret in the configuration file or set the 
REGISTRY_HTTP_SECRET environment variable.  go.version=go1.8
 instance.id=a80670e6-d840-44f3-aefa-9f6863fb6a6e
 version="v2.6.0+unknown"INFO[0000] redis not configured
 go.version=go1.8 instance.id=a80670e6-d840-44f3-aefa-
9f6863fb6a6e version="v2.6.0+unknown"
INFO[0000] Starting upload purge in 10m0s
go.version=go1.8 instance.id=a80670e6-d840-44f3-aefa-9f6863fb6a6e
 version="v2.6.0+unknown"
INFO[0000] using inmemory blob descriptor cache
go.version=go1.8 instance.id=a80670e6-d840-44f3-aefa-9f6863fb6a6e
 version="v2.6.0+unknown"
INFO[0000] Starting cached object TTL expiration scheduler...
go.version=go1.8 instance.id=a80670e6-d840-44f3-aefa-9f6863fb6a6e
 version="v2.6.0+unknown"
INFO[0001] Discovered token authentication URL:
https://auth.docker.io/token  go.version=go1.8 instance.id=
a80670e6-d840-44f3-aefa-9f6863fb6a6e
INFO[0001] Registry configured as a proxy cache to 
https://registry-1.docker.io  go.version=go1.8 instance.id=
a80670e6-d840-44f3-aefa-9f6863fb6a6e version="v2.6.0+unknown"
INFO[0001] listening on [::]:5000
go.version=go1.8 instance.id=a80670e6-d840-44f3-aefa-9f6863fb6a6e
version="v2.6.0+unknown"

Voila! Your own private registry is up and running on your very own Raspberry Pi. You might see some warning messages, but you can safely ignore them for now. Let's also check the connectivity from a laptop:

local-osx $  curl -I 192.168.1.2:5000/v2/
HTTP/1.1 200 OK
Content-Length: 2
Content-Type: application/json; charset=utf-8
Docker-Distribution-Api-Version: registry/2.0
Date: Sun, 11 Jun 2017 13:26:18 GMT

A 200 response means that things are good.

Proxy setup

We tested our registry and it works fine, but it doesn't yet do what we want it to do. The goal is to set up a proxy that caches images on the first pull and then serves them locally on subsequent requests. This can be done by adding a proxy section to the config file:

version: 0.1
storage:
  cache:
    blobdescriptor: inmemory
  filesystem:
    rootdirectory: /var/lib/registry
http:
  addr: :5000
proxy:
 remoteurl: https://registry-1.docker.io

Here the remoteurl is the URL for the Docker Hub registry. You can also change the port from 5000 to any other port if you wish. Run the registry with the same command:

pi@raspberrypi:~/distribution $ ~/distribution/bin/registry serve
 ~/registry-config.yml &

Notice the & at the end, which makes the process run in the background. Now it's time to configure the Docker daemon on a laptop to use this registry mirror (see Figure 4). If you are using Docker for Mac then you can do it by going to Preferences > Registry mirrors and adding http://192.168.1.2:5000, and then restarting Docker. If you are using Docker on any other OS, then follow the relevant docs (see Related topics) to update the Docker daemon preferences.

Figure 4. The Docker daemon configuration
The Docker daemon configuration
The Docker daemon configuration

Now, every time you pull an image on your laptop, it will be cached on your Raspberry Pi in the /var/lib/registry directory. You might want to mount an external drive to the path. Let's verify this by pulling the Mongo Docker image:

local-osx $ time docker pull mongo
Using default tag: latest
latest: Pulling from library/mongo
56c7afbcb0f1: Pull complete
...
e233325a655e: Pull complete
Digest:
sha256:c4bc4644b967a4b58022a79cf5c9afcd25ed08180c958a74df57b7753cfc8649
Status: Downloaded newer image for mongo:latest
docker pull mongo  0.15s user 0.18s system 0% cpu 2:22.28 total

local-osx $ docker rmi mongo

local-osx $ time docker pull mongo
Using default tag: latest
latest: Pulling from library/mongo
56c7afbcb0f1: Pull complete
...
e233325a655e: Pull complete
Digest: sha256:c4bc4644b967a4b58022a79cf5c9afcd25ed08180c958a74df57b7753cfc8649
Status: Downloaded newer image for mongo:latest
docker pull mongo  0.15s user 0.13s system 0% cpu 51.303 total

As you can see, the first pull takes 142 seconds, while the second one completes in under 60 seconds.

Conclusion

If you have a slow internet connection and multiple users downloading Docker images, then the setup covered in this tutorial can help you save time as well as bandwidth. Raspberry Pi is amazing because it is portable, cheap, and consumes negligible power. You have seen the benefits of using Raspberry Pi as a pull-through cache for Docker Hub, so that every time you download an image, it will be cached on the Pi, and for every subsequent request the image is delivered from the local cache.


Downloadable resources


Related topics


Comments

Sign in or register to add and subscribe to comments.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Cloud computing
ArticleID=1048299
ArticleTitle=Set up a Docker Registry as a pull-through cache on Raspberry Pi
publish-date=08152017