将 Docker Registry 设置为 Raspberry Pi 上的拉取式缓存

如果您的网速缓慢且有多个用户在下载 Docker 映像,为什么不使用它作为 Raspberry Pi 上的缓存呢?这样,在使用 Docker 时可以节省时间和带宽。Raspberry Pi 非常有用,它便携、经济且耗电量微乎其微。通过创建本教程中介绍的解决方案,每次下载映像时,它都会缓存在 Pi 上;然后对于所有后续请求,将从本地缓存提供同一个映像。

Docker 是一个流行的 DevOps 工具,它为开发人员和系统管理员提供了一个平台,使他们能构建、发布并在任何地方运行应用程序。这意味着,开发人员能在本地机器上构建 Docker 映像,将它们发布到注册表,然后在云服务器上运行它们。注册表之于 Docker 映像,就像 Git 之于编码。

“本教程中的设置有助于节省时间和带宽。Raspberry Pi 非常有用,它便携、经济且耗电量微乎其微。”

Docker Hub 是一个流行的注册表,它允许用户免费托管映像。如果您的开发小组在同一个网速缓慢或带宽有限的地方协同使用 Docker,而且所有人都从 Docker Hub 下载映像,您可能会面临一些性能挑战。可以将本地网络上的私有 Docker Registry 设置为拉取式缓存,以便每次您下载一个映像时都会缓存它,对于后续的每个请求,将从本地缓存提供该映像。这也可以节省宝贵的带宽和大量时间。例如,代理缓存的基于 Ubuntu 的映像可能被多次下载到不同机器上,但该映像仅从 Docker Hub 抓取一次。

在本教程中,您将使用 Raspberry Pi 作为 Docker Hub 的拉取式缓存。Raspberry Pi 是一种信用卡大小的小型计算机,它使用的电量非常少,完整 PC 能处理的许多工作它都能处理。我们将演示从头设置 Raspberry Pi,将 Golang 安装在 Raspberry Pi 上,以及编译 Go 二进制程序(因为 Docker Registry 是使用跨平台语言 Golang 编写的)。如果一切顺利,只需两小时即可完成所有设置。我们首先看看一些前提条件。

需要的硬件和软件

开始之前,确保您拥有以下硬件:

  • Raspberry 第 2 版或更高版本
  • 8GB 或更大的 SD 卡
  • 带以太网端口的 Web 路由器
  • LAN 线
  • 安装了 Docker 的机器

还需要安装以下软件:

  • 基本 Linux 命令行
  • Docker(在这里获取最新版本)

设置

首先设置 Raspberry Pi。如果有一个运行正常的 Raspberry Pi,可以跳过这一步。Raspberry Pi 有许多发行版,但本示例使用 Raspbian,这是 Raspberry Pi 网站上提供的官方发行版。

下载 Raspbian

打开一个新终端窗口,使用 wget 下载 Raspbian 映像,该工具已预先安装在大部分 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

这会将“~/rpi-registry”目录内的发行版映像下载到您的机器上。通过执行以下命令,使用 SHA 校验和与上游的 SHA 来验证下载的映像的完整性:

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

如果 SHA 校验和不匹配,则必须重新下载该映像。如果网速缓慢,在下载时应该使用 torrent 选项。

准备 SD 卡

要将 Raspbian 安装在 SD 卡上,可以使用 Etcher 工具,该工具可从 https://etcher.io 下载。Etcher 是一个将映像刻录到 SD 卡和 USB 驱动器上的应用程序。它可用于 Windows、Linux 和 Mac OS X。将 SD 卡插入笔记本电脑或台式机中,打开 Etcher。然后选择下载的 Raspbian 映像,确保它检测到您的 SD 卡后,单击Flash! (参见图 1)。将映像刻录到 SD 卡上需要花几分钟。

图 1. Etcher 将映像刻录到 SD 卡上

在这里设置无头 Pi,这意味着不会向 Raspberry Pi 连接键盘或显示器,所以需要在首次引导时启用 SSH。必须这么做,因为最新的 Raspbian 构建版默认已禁用 SSH。为此,在首次引导之前,在 SD 卡的引导分区中创建一个名为“SSH”的文件。该文件不得有任何扩展名,可以是空的,也可以是一个文本文件。
为此,可以在 File Explorer 中或从终端打开 SD 卡。在 Mac OS X 上,安装路径为 /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
...

SD 卡现在已准备好引导。将卡插入 Raspberry Pi 中并将它连接到家庭路由器。

SSH 登录

要登录,需要 Raspberry Pi 的 IP 地址,可以在路由器的管理页面上找到该信息。大多数路由的管理页面地址为 192.168.1.1,但您的可能不同,所以应手动查找您的路由器(参见图 2)。也可以使用 Nmap 等网络扫描工具找到此信息。

图 2. 您的路由器包含 Pi 的 IP 地址

拥有 IP 地址后,就可以使用 Secure Shell (SSH) 登录了,输入 pi 作为用户名和 raspberry 作为密码,这是使用 Pi 随带的 Raspbian 操作系统的默认用户名和密码:

$ 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:~ $

Raspbian 现在已在运行,所以您可以继续设置 Docker Registry。请注意,分配给 Pi 的 IP 地址可能更改,所以您可能需要向它分配一个静态 IP。

代理:分发 Docker 映像

Docker Registry 是一个无状态、容易扩展的服务器端应用程序,它存储并允许您分发 Docker 映像。Docker Hub 提供了一个可免费使用的托管注册表,这是所有 Docker 客户端的默认注册表,所以在执行 docker pull ubuntu 时,它会从 Docker Hub 抓取映像。可以运行一个注册表缓存来将这些映像存储在本地,而不是经常从互联网下载它们。为此,可以使用 Docker Registry 为您的家庭或组织自行托管一个私有注册表。这个开源应用程序是使用 Golang 编写的,可在 Github 上获得。可以将 Docker Registry 作为 Docker 容器运行,但我们将从头开始构建它并在裸机 Raspberry Pi 上执行该二进制程序。

工作原理

任何 Docker 客户端第一次拉入映像时,它都会从 Docker Hub 抓取映像,并在文件系统上存储一个副本。对于任何后续请求,将从本地注册表而不是 Docker Hub 提供副本。它非常聪明,在将映像提供给客户端之前,会检测上游对映像的任何更改并更新映像(参见图 3)。

图 3. docker_proxy 检测任何更改

操作说明

Golang 允许对多个架构执行交叉编译,这意味着可以在笔记本或台式机上执行以下步骤,构建 Docker Registry 的二进制程序并将它们复制到 Raspberry Pi。出于简单性考虑,我们将介绍如何在 Raspberry Pi 自身上执行构建流程。

首先安装 Golang。

安装 Golang

安装 Go 的最容易方式是使用 gvm (Golang Version Manager),该工具类似于用于 Ruby 的 rvm 或用于 Python 应用程序的 virtualenv。

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

您可能希望将源代码 /home/pi/.gvm/scripts/gvm 添加到 ~/.bashrc 文件中,以避免每次登录时都获取它:

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

备注:Go 1.5 C 无法用于编译,所以在安装 Go 1.8 之前,需要下载 Go 1.4。

创建注册表二进制程序

Docker Registry 存储库提供了一个 Makefile,用于构建这些二进制程序并将它们放在 bin 目录中。Registry 包含在 Docker 发行版存储库中,所以可以克隆它:

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

接下来,安装依赖项:

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

创建二进制程序:

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

设置 GOOS 和 GOARCH 环境变量,让编译器知道您正在 Linux 操作系统上针对 ARM 架构而构建。如果 make 命令成功运行,将会在 bin/ 目录中看到这些二进制程序。

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

测试二进制包

需要一个配置文件才能运行该注册表。创建 ~/registry-config.yml 并将以下内容复制到其中:

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

您现在已拥有运行注册表所需的所有资源,接下来运行您自己的私有注册表:

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. 
如果负载平衡器背后有多个注册表,这可能导致上传问题。要提供共享密钥,可将 http.secret 填入配置文件中,或者设置 
REGISTRY_HTTP_SECRET 环境变量。go.version=go1.8
 instance.id=a80670e6-d840-44f3-aefa-9f6863fb6a6e
INFO[0000] redis not configured
 go.version=go1.8 instance.id=a80670e6-d840-44f3-aefa-
9f6863fb6a6e
INFO[0000] Starting upload purge in 10m0s
go.version=go1.8 instance.id=a80670e6-d840-44f3-aefa-9f6863fb6a6e

INFO[0000] using inmemory blob descriptor cache
go.version=go1.8 instance.id=a80670e6-d840-44f3-aefa-9f6863fb6a6e

INFO[0000] Starting cached object TTL expiration scheduler...
go.version=go1.8 instance.id=a80670e6-d840-44f3-aefa-9f6863fb6a6e

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
INFO[0001] listening on [::]:5000
go.version=go1.8 instance.id=a80670e6-d840-44f3-aefa-9f6863fb6a6e

瞧!您自己的私有注册表正在您自己的 Raspberry Pi 上正常运行。您可能看到一些警告消息,但暂时可以安全地忽略它们。我们也检查一下来自笔记本电脑的连接:

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

响应代码 200 表明运行正常。

代理设置

我们测试了我们的注册表,它运行正常,但还无法执行我们希望它执行的操作。我们的目的是设置一个代理,以在首次下载时缓存映像,然后在本地为后续请求提供它们。这可以通过向配置文件中添加一个代理节来完成:

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

在这里,remoteurl 是 Docker Hub 注册表的 URL。如果愿意,也可以将端口从 5000 更改为任何其他端口。使用同一个命令运行该注册表:

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

请注意末尾的 &,它使该进程在后台运行。现在可以在笔记本电脑上配置 Docker 守护进程,以使用这个注册表镜像(参见图 4)。如果使用 Docker for Mac,可通过转到 Preferences > Registry mirrors 并添加 http://192.168.1.2:5000,然后重新启动 Docker 来实现此目的。如果在任何其他操作系统上使用 Docker,可以按照相关文档(参阅“相关主题”)更新 Docker 守护进程首选项。

图 4. Docker 守护进程配置

现在,每次您在笔记本电脑上下载映像,它都会缓存在 Raspberry Pi 上的 /var/lib/registry 目录中。您可能希望在该路径挂载一个外部驱动器。我们通过拉取 Mongo Docker 映像来检验此做法:

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

可以看到,第一次拉取花了 142 秒,而第二次在 60 秒内就完成了。

结束语

如果您的网络连接缓慢且有多个用户在下载 Docker 映像,本文中介绍的设置可以帮助您节省时间和带宽。Raspberry Pi 非常有用,它便携、经济且耗电量微乎其微。您已看到使用 Raspberry Pi 作为 Docker Hub 的拉取式缓存的好处:每次您下载一个映像,它都会缓存在 Pi 上,对于每个后续请求,会从本地缓存中提供该映像。

标签:缓存Docker 发布于:2019-11-03 16:07:20