Set up a Docker Registry as a pull-through cache on Raspberry Pi
Save time and bandwidth using the Pi with Docker
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:
- Raspberry version 2 or higher
- SD card 8GB or more
- Web router with ethernet port
- LAN cable
- A machine with Docker installed
You will also need to have the following software installed:
- Basic Linux command line
- Docker (get the latest version here)
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.
Open a new terminal window and download the Raspbian image with
wget, which comes preinstalled on most Linux
$ 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
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.
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
Once you have the IP address, you can use Secure Shell (SSH) by entering
pi as the username and by entering
the password, which is the default username and password for using the
Raspbian operating system that comes with the Pi:
$ ssh email@example.com firstname.lastname@example.org'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
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.
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
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
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 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 redis not configured go.version=go1.8 instance.id=a80670e6-d840-44f3-aefa- 9f6863fb6a6e version="v2.6.0+unknown" INFO Starting upload purge in 10m0s go.version=go1.8 instance.id=a80670e6-d840-44f3-aefa-9f6863fb6a6e version="v2.6.0+unknown" INFO using inmemory blob descriptor cache go.version=go1.8 instance.id=a80670e6-d840-44f3-aefa-9f6863fb6a6e version="v2.6.0+unknown" INFO Starting cached object TTL expiration scheduler... go.version=go1.8 instance.id=a80670e6-d840-44f3-aefa-9f6863fb6a6e version="v2.6.0+unknown" INFO Discovered token authentication URL: https://auth.docker.io/token go.version=go1.8 instance.id= a80670e6-d840-44f3-aefa-9f6863fb6a6e INFO 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 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.
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
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 &
& 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
Figure 4. 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.
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.
- Docker Registry documentation
- Raspberry Pi information
- How to set up a registry proxy cache with Docker open source registry
- Learn how to cache Docker Hub locally
- Obtaining, compiling, installing, and removing Nmap