如何在 Ubuntu 20.04 上设置私有 Docker Registry

作为Write for DOnations计划的一部分,作者选择了免费和开源基金来接受捐赠

介绍

Docker Registry是一个管理存储和交付 Docker 容器镜像的应用程序。注册表集中容器映像并减少开发人员的构建时间。Docker 镜像通过虚拟化保证相同的运行时环境,但构建镜像可能需要大量时间投资。例如,开发人员无需单独安装依赖项和包来使用 Docker,而是可以从包含所有必要组件的注册表下载压缩映像。此外,开发人员可以使用持续集成工具(例如TravisCI)自动将图像推送到注册表,以在生产和开发期间无缝更新图像。

Docker 还有一个免费的公共注册表Docker Hub,它可以托管您的自定义 Docker 镜像,但在某些情况下,您不希望您的镜像公开可用。映像通常包含运行应用程序所需的所有代码,因此在使用专有软件时最好使用私有注册表。

在本教程中,您将设置并保护您自己的私有 Docker 注册表。您将使用Docker Compose定义运行 Docker 容器的配置,并使用 Nginx 将服务器流量从互联网转发到正在运行的 Docker 容器。完成本教程后,您将能够将自定义 Docker 映像推送到您的私有注册表,并从远程服务器安全地拉取该映像。

先决条件

第 1 步 – 安装和配置 Docker Registry

命令行上的 Docker 在启动和测试容器时很有用,但被证明对于涉及多个并行运行的容器的大型部署来说是笨拙的。

使用 Docker Compose,您可以编写一个.yml文件来设置每个容器的配置和容器相互通信所需的信息。您可以使用docker-compose命令行工具向构成应用程序的所有组件发出命令,并将它们作为一个组进行控制。

Docker Registry 本身就是一个具有多个组件的应用程序,因此您将使用 Docker Compose 来管理它。要启动注册表的实例,您将设置一个docker-compose.yml文件来定义它以及您的注册表将在磁盘上存储其数据的位置。

您将配置存储docker-registry在主服务器上调用的目录中通过运行创建它:

  • mkdir ~/docker-registry

导航到它:

  • cd ~/docker-registry

然后,创建一个名为 的子目录data,您的注册表将在其中存储其图像:

  • mkdir data

创建并打开一个docker-compose.yml通过运行调用的文件

  • nano docker-compose.yml

添加以下几行,它们定义了 Docker Registry 的基本实例:

~/docker-registry/docker-compose.yml
version: '3'

services:
  registry:
    image: registry:2
    ports:
    - "5000:5000"
    environment:
      REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
    volumes:
      - ./data:/data

首先,您命名第一个 service registry,并将其图像设置为registry, version 2然后,在 下ports5000将主机上的端口映射5000容器的端口这允许您向5000服务器上的端口发送请求,并将请求转发到注册表。

在该environment部分中,您将REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY变量设置/data,指定应将其数据存储在哪个卷中。然后,在该volumes部分中,您/data将主机文件系统上的目录映射/data容器中,作为传递数据实际上将存储在主机的文件系统上。

保存并关闭文件。

您现在可以通过运行以下命令启动配置:

  • docker-compose up

注册表容器及其依赖项将被下载并启动。

Output
Creating network "docker-registry_default" with the default driver Pulling registry (registry:2)... 2: Pulling from library/registry e95f33c60a64: Pull complete 4d7f2300f040: Pull complete 35a7b7da3905: Pull complete d656466e1fe8: Pull complete b6cb731e4f93: Pull complete Digest: sha256:da946ca03fca0aade04a73aa94b54ff0dc614216bdd1d47585f97b4c1bdaa0e2 Status: Downloaded newer image for registry:2 Creating docker-registry_registry_1 ... done Attaching to docker-registry_registry_1 registry_1 | time="2021-03-18T12:32:59.587157744Z" level=warning msg="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.11.2 instance.id=119fe50b-2bb6-4a8d-902d-dfa2db63fc2f service=registry version=v2.7.1 registry_1 | time="2021-03-18T12:32:59.587912733Z" level=info msg="redis not configured" go.version=go1.11.2 instance.id=119fe50b-2bb6-4a8d-902d-dfa2db63fc2f service=registry version=v2.7.1 registry_1 | time="2021-03-18T12:32:59.598496488Z" level=info msg="using inmemory blob descriptor cache" go.version=go1.11.2 instance.id=119fe50b-2bb6-4a8d-902d-dfa2db63fc2f service=registry version=v2.7.1 registry_1 | time="2021-03-18T12:32:59.601503005Z" level=info msg="listening on [::]:5000" go.version=go1.11.2 instance.id=119fe50b-2bb6-4a8d-902d-dfa2db63fc2f service=registry version=v2.7.1 ...

您将No HTTP secret provided在本教程后面解决警告消息。请注意,输出的最后一行显示它已成功开始侦听端口5000

您可以按CTRL+C停止其执行。

在这一步中,您已经创建了一个 Docker Compose 配置,它启动了一个侦听端口的 Docker Registry 5000在接下来的步骤中,您将在您的域中公开它并设置身份验证。

第 2 步 – 设置 Nginx 端口转发

作为先决条件的一部分,您已在您的域中启用 HTTPS。要在那里公开您的安全 Docker 注册表,您只需要配置 Nginx 以将流量从您的域转发到注册表容器。

您已经设置了包含服务器配置文件。通过运行打开它进行编辑:/etc/nginx/sites-available/your_domain

  • sudo nano /etc/nginx/sites-available/your_domain

查找现有location块:

/etc/nginx/sites-available/your_domain
...
location / {
  ...
}
...

您需要将流量转发到 port 5000,您的注册表将在那里监听流量。您还希望将标头附加到转发到注册表的请求中,它提供来自服务器的关于请求本身的附加信息。location以下几行替换的现有内容

/etc/nginx/sites-available/your_domain
...
location / {
    # Do not allow connections from docker 1.5 and earlier
    # docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents
    if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) {
      return 404;
    }

    proxy_pass                          http://localhost:5000;
    proxy_set_header  Host              $http_host;   # required for docker client's sake
    proxy_set_header  X-Real-IP         $remote_addr; # pass on real client's IP
    proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header  X-Forwarded-Proto $scheme;
    proxy_read_timeout                  900;
}
...

if块检查请求的用户代理并验证 Docker 客户端的版本是否高于 1.5,以及它不是Go尝试访问应用程序。有关这方面的更多解释,您可以nginxDocker 的注册表 Nginx 指南中找到标头配置

完成后保存并关闭文件。通过重新启动 Nginx 应用更改:

  • sudo systemctl restart nginx

如果出现错误,请仔细检查您添加的配置。

要确认 Nginx 正确地将流量转发到 port 上的注册表容器5000,请运行它:

  • docker-compose up

然后,在浏览器窗口中,导航到您的域并访问v2端点,如下所示:

https://your_domain/v2

您将看到一个空的 JSON 对象:

{}

在您的终端中,您将收到类似于以下内容的输出:

Output
registry_1 | time="2018-11-07T17:57:42Z" level=info msg="response completed" go.version=go1.7.6 http.request.host=cornellappdev.com http.request.id=a8f5984e-15e3-4946-9c40-d71f8557652f http.request.method=GET http.request.remoteaddr=128.84.125.58 http.request.uri="/v2/" http.request.useragent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/604.4.7 (KHTML, like Gecko) Version/11.0.2 Safari/604.4.7" http.response.contenttype="application/json; charset=utf-8" http.response.duration=2.125995ms http.response.status=200 http.response.written=2 instance.id=3093e5ab-5715-42bc-808e-73f310848860 version=v2.6.2 registry_1 | 172.18.0.1 - - [07/Nov/2018:17:57:42 +0000] "GET /v2/ HTTP/1.0" 200 2 "" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/604.4.7 (KHTML, like Gecko) Version/11.0.2 Safari/604.4.7"

您可以从最后一行看到GET请求是/v2/从您的浏览器发送到的端点,即您向其发送请求的端点。容器从端口转发收到您发出的请求,并返回{}. 200输出最后一行的代码表示容器成功处理了请求。

CTRL+C停止其执行。

现在您已经设置了端口转发,您将继续提高注册表的安全性。

第 3 步 – 设置身份验证

Nginx 允许您为其管理的站点设置 HTTP 身份验证,您可以使用它来限制对 Docker Registry 的访问。为此,您将创建一个身份验证文件,htpasswd并向其中添加将被接受的用户名和密码组合。

您可以htpasswd通过安装该apache2-utils软件包来获取该实用程序。运行:

  • sudo apt install apache2-utils -y

您将带有凭据的身份验证文件存储在~/docker-registry/auth. 通过运行创建它:

  • mkdir ~/docker-registry/auth

导航到它:

  • cd ~/docker-registry/auth

创建第一个用户,替换username为您要使用的用户名。-B标志命令使用bcryptDocker 要求算法:

  • htpasswd -Bc registry.password username

出现提示时输入密码,凭据组合将附加到registry.password.

注意:要添加更多用户,请在不使用 的情况下重新运行上一个命令-c,这会创建一个新文件:

  • htpasswd -B registry.password username

既然已创建凭据列表,您将进行编辑docker-compose.yml以命令 Docker 使用您创建的文件对用户进行身份验证。通过运行打开它进行编辑:

  • nano ~/docker-registry/docker-compose.yml

添加突出显示的行:

~/docker-registry/docker-compose.yml
version: '3'

services:
  registry:
    image: registry:2
    ports:
    - "5000:5000"
    environment:
      REGISTRY_AUTH: htpasswd
      REGISTRY_AUTH_HTPASSWD_REALM: Registry
      REGISTRY_AUTH_HTPASSWD_PATH: /auth/registry.password
      REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
    volumes:
      - ./auth:/auth
      - ./data:/data

您已经添加了指定使用 HTTP 身份验证的环境变量,并提供了所htpasswd创建文件的路径对于REGISTRY_AUTH,您已指定htpasswd其值,即您正在使用的身份验证方案,并设置REGISTRY_AUTH_HTPASSWD_PATH为身份验证文件的路径。REGISTRY_AUTH_HTPASSWD_REALM表示htpasswd领域的名称

您还安装了该./auth目录以使文件在注册表容器内可用。保存并关闭文件。

您现在可以验证您的身份验证是否正常工作。首先,导航到主目录:

  • cd ~/docker-registry

然后,通过执行以下命令运行注册表:

  • docker-compose up

在您的浏览器中,刷新您的域页面。系统会要求您输入用户名和密码。

提供有效的凭据组合后,您将看到一个空的 JSON 对象:

{}

这意味着您已成功通过身份验证并获得了对注册表的访问权限。按 退出CTRL+C

您的注册表现在是安全的,只有在身份验证后才能访问。您现在将其配置为作为后台进程运行,同时通过自动启动对重新启动具有弹性。

第 4 步 – 启动 Docker Registry as a Service

通过指示 Docker Compose 始终保持运行,您可以确保每次系统启动时或系统崩溃后注册表容器都启动。打开docker-compose.yml编辑:

  • nano docker-compose.yml

registry下添加以下行

docker-compose.yml
...
  registry:
    restart: always
...

设置restart为 always 可确保容器在重新启动后仍然存在。完成后,保存并关闭文件。

您现在可以通过传入以下内容将注册表作为后台进程启动-d

  • docker-compose up -d

在您的注册表在后台运行时,您可以自由关闭 SSH 会话,并且注册表不会受到影响。

由于 Docker 映像的大小可能非常大,您现在将增加 Nginx 可接受上传的最大文件大小。

第 5 步 – 增加 Nginx 的文件上传大小

在将映像推送到注册表之前,您需要确保您的注册表能够处理大文件上传。

Nginx 中文件上传的默认大小限制是1m,这对于 Docker 镜像来说远远不够。要提升它,您将修改位于/etc/nginx/nginx.conf. 通过运行打开它进行编辑:

  • sudo nano /etc/nginx/nginx.conf

找到该http部分,并添加以下行:

/etc/nginx/nginx.conf
...
http {
        client_max_body_size 16384m;
        ...
}
...

client_max_body_size参数现在设置为16384m,使最大上传大小等于 16GB。

完成后保存并关闭文件。

重新启动 Nginx 以应用配置更改:

  • sudo systemctl restart nginx

您现在可以将大图像上传到您的 Docker Registry,而 Nginx 不会阻止传输或出错。

第 6 步 – 发布到您的私有 Docker 注册表

现在您的 Docker Registry 服务器已启动并正在运行,并且可以接受大文件大小,您可以尝试向其推送映像。由于您没有任何现成的ubuntu图像,您将使用来自公共 Docker 注册表 Docker Hub图像进行测试。

从您的第二个客户端服务器,运行以下命令来下载ubuntu映像,运行它,并访问它的 shell:

  • docker run -t -i ubuntu /bin/bash

-i-t标志给你交互shell访问到容器中。

进入后,创建一个SUCCESS通过运行调用的文件

  • touch /SUCCESS

通过创建此文件,您已经自定义了您的容器。您稍后将使用它来检查您使用的是完全相同的容器。

运行以下命令退出容器外壳:

  • exit

现在,从您刚刚自定义的容器创建一个新图像:

  • docker commit $(docker ps -lq) test-image

新映像现在可在本地使用,您可以将其推送到新的容器注册表。首先,您必须登录:

  • docker login https://your_domain

出现提示时,输入您在本教程的第 3 步中定义的用户名和密码组合。

输出将是:

Output
... Login Succeeded

登录后,重命名创建的图像:

  • docker tag test-image your_domain/test-image

最后,将新标记的图像推送到您的注册表:

  • docker push your_domain/test-image

您将收到类似于以下内容的输出:

Output
The push refers to a repository [your_domain/test-image] 420fa2a9b12e: Pushed c20d459170d8: Pushed db978cae6a05: Pushed aeb3f02e9374: Pushed latest: digest: sha256:88e782b3a2844a8d9f0819dc33f825dde45846b1c5f9eb4870016f2944fe6717 size: 1150

您已验证您的注册表通过登录处理用户身份验证,并允许经过身份验证的用户将图像推送到注册表。您现在将尝试从您的注册表中提取图像。

第 7 步 — 从您的私有 Docker 注册表中提取

现在您已将映像推送到您的私有注册表,您将尝试从中提取。

在主服务器上,使用您之前设置的用户名和密码登录:

  • docker login https://your_domain

尝试test-image通过运行来拉动

  • docker pull your_domain/test-image

Docker 应该下载镜像。使用以下命令运行容器:

  • docker run -it your_domain/test-image /bin/bash

通过运行列出存在的文件:

  • ls

您将看到SUCCESS您之前创建文件,确认它与您创建的图像相同:

SUCCESS  bin  boot  dev  etc  home  lib  lib64  media   mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

运行以下命令退出容器外壳:

  • exit

现在您已经测试了推送和拉取镜像,您已经完成了一个安全注册表的设置,您可以使用它来存储自定义镜像。

结论

在本教程中,您将设置自己的私有 Docker Registry,并向其发布 Docker 映像。正如介绍中提到的,您还可以使用TravisCI或类似的 CI 工具直接自动推送到私有注册表。通过在您的工作流程中利用 Docker 容器,您可以确保包含代码的映像在任何机器上都会产生相同的行为,无论是在生产中还是在开发中。有关编写 Docker 文件的更多信息,您可以访问有关最佳实践官方文档

觉得文章有用?

点个广告表达一下你的爱意吧 !😁