如何在 Ubuntu 18.04 上设置私有 Docker 注册表

作者选择了 Apache Software Foundation作为 Write for Donations计划的一部分接受捐款。

介绍

Docker Registry是一个管理存储和交付 Docker 容器图像的应用程序。注册表集中容器图像并缩短开发人员的构建时间。Docker 图像通过虚拟化保证了相同的运行时间环境,但构建图像可能需要大量的时间。例如,而不是单独安装依赖和包来使用 Docker,开发人员可以从包含所有必要组件的注册表下载压缩图像。

Docker 还有一个免费的公共注册表 Docker Hub,可以托管您自定义的 Docker 图像,但有些情况下,您不希望您的图像公开可用。

在本教程中,您将设置和保护自己的私人Docker注册表. 您将使用 Docker Compose来定义运行Docker应用程序和 Nginx的配置,将服务器流量从HTTPS转移到运行Docker容器。

前提条件

在您开始本指南之前,您将需要以下内容:

一个服务器将托管您的私人Docker注册表,另一个服务器将是您的客户端服务器。Docker和Docker-Compose安装在两个服务器上,仅需完成本教程的第一步才能安装Docker Compose。本教程解释了如何安装Docker作为其先决条件的一部分。

  • Nginx安装在您的私人Docker注册表服务器上,如下 How to InstallDocker-Compose on Ubuntu 18.04教程。
  • Nginx以您的私人Docker注册表上的名称加密,随后将通过[How to SecureDocker_Inc1使用Docker注册表的流量以确保您的Docker的任何部分被安裝到Docks(LINK2))。

步骤 1 – 安装和配置 Docker 注册表

Docker 命令行工具有助于启动和管理一个或两个 Docker 容器,但为了实现完整的部署,大多数在 Docker 容器内运行的应用程序需要其他组件并行运行,例如,许多 Web 应用程序包括一个 Web 服务器,如 Nginx,它提供应用程序的代码,一个解释的脚本语言,如 PHP,和一个数据库服务器,如 MySQL。

使用 Docker Compose,您可以编写一个.yml 文件来设置每个容器的配置和容器需要相互通信的信息,然后您可以使用docker-compose命令行工具发出命令给构成您的应用程序的所有组件。

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

在您为托管私人 Docker 注册表创建的服务器上,您可以创建一个docker 注册表目录,移动到它,然后使用以下命令创建一个数据子文件夹:

1mkdir ~/docker-registry && cd $_
2mkdir data

使用文本编辑器创建docker-compose.yml配置文件:

1nano docker-compose.yml

将以下内容添加到文件中,描述了 Docker 注册表的基本配置:

 1[label docker-compose.yml]
 2version: '3'
 3
 4services:
 5  registry:
 6    image: registry:2
 7    ports:
 8    - "5000:5000"
 9    environment:
10      REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
11    volumes:
12      - ./data:/data

环境部分将环境变量设置在Docker注册表容器中的路径 /data. Docker注册表应用程序在启动时检查此环境变量,因此开始将其数据保存到 `/data’文件夹中。

但是,当您包含了卷: -. / 数据: / 数据行时,Docker 将开始将该容器中的 / 数据目录映射到您的注册表服务器上的 / 数据

端口部分,配置为5000:5000,告诉Docker在服务器上将端口5000地图到运行容器中的端口5000

现在您可以启动 Docker Compose 来检查设置:

1docker-compose up

您将在输出中看到下载栏,显示 Docker 从 Docker 自己的注册表中下载 Docker 注册表图像。

1[secondary_label Output of docker-compose up]
2Starting docker-registry_registry_1 ... done
3Attaching to docker-registry_registry_1
4registry_1  | time="2018-11-06T18:43:09Z" 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.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2
5registry_1  | time="2018-11-06T18:43:09Z" level=info msg="redis not configured" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2
6registry_1  | time="2018-11-06T18:43:09Z" level=info msg="Starting upload purge in 20m0s" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2
7registry_1  | time="2018-11-06T18:43:09Z" level=info msg="using inmemory blob descriptor cache" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2
8registry_1  | time="2018-11-06T18:43:09Z" level=info msg="listening on [::]:5000" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2

您将在本教程中稍后发出没有提供 HTTP 秘密警告消息,输出显示容器正在启动,输出的最后一行显示它已成功开始在端口5000上收听。

默认情况下,Docker Compose 将继续等待您的输入,因此按CTRL+C关闭您的 Docker 注册表容器。

您已经在端口5000上设置了完整的Docker注册表,此时注册表将不会启动,除非您手动创建注册表。此外,Docker注册表没有内置的身份验证机制,因此它目前不安全,并且完全向公众开放。

步骤 2 — 设置 Nginx 端口转发

您已经在您的 Docker 注册表服务器上设置了 HTTPS 与 Nginx,这意味着您现在可以设置从 Nginx 到 `5000 端口的端口转发。

作为 How to Secure Nginx With Let's Encrypt的前提条件的一部分,您已经设置了包含您的服务器配置的 /etc/nginx/sites-available/example.com 文件。

使用您的文本编辑器打开此文件:

1sudo nano /etc/nginx/sites-available/example.com

查找现有的位置线,它会看起来像这样:

1[label /etc/nginx/sites-available/example.com]
2...
3location / {
4  ...
5}
6...

您需要将流量转发到端口5000,在那里您的注册表将运行。您还希望将请求标题附加到注册表中,这些标题会为每个请求和响应提供服务器的额外信息。

 1[label /etc/nginx/sites-available/example.com]
 2...
 3location / {
 4    # Do not allow connections from docker 1.5 and earlier
 5    # docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents
 6    if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) {
 7      return 404;
 8    }
 9
10    proxy_pass http://localhost:5000;
11    proxy_set_header Host              $http_host;   # required for docker client's sake
12    proxy_set_header X-Real-IP         $remote_addr; # pass on real client's IP
13    proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
14    proxy_set_header X-Forwarded-Proto $scheme;
15    proxy_read_timeout 900;
16}
17...

$http_user_agent部分验证了客户端的Docker版本是否超过了1.5,并确保UserAgent不是一个Go应用程序,因为您正在使用注册表的版本2.0,所以不支持较旧的客户端。

保存和退出文件. 通过重新启动 Nginx 来应用更改:

1sudo service nginx restart

您可以通过运行注册表来确认 Nginx 正在将流量转发到端口 `5000’:

1cd ~/docker-registry
2docker-compose up

在浏览器窗口中,打开以下URL:

1https://example.com/v2

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

1{}

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

1[secondary_label Output of docker-compose up]
2registry_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
3registry_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/,这是您从您的浏览器发送请求的终端点。

现在您已经设置了端口转发,您可以继续改进您的注册表的安全性。

步骤三:设置身份验证

借助 Nginx 代理请求,您现在可以使用 HTTP 身份验证来保护您的注册表,以管理谁可以访问您的 Docker 注册表。 为了实现这一目标,您将创建一个具有htpasswd的身份验证文件,并添加用户。

您可以通过运行以下操作来安装htpasswd包:

1sudo apt install apache2-utils

现在,您将创建存储我们的身份验证凭证的目录,并将其更改为该目录。 $_ 扩展到上一个命令的最后一个参数,在这种情况下 ~/docker-registry/auth:

1mkdir ~/docker-registry/auth && cd $_

接下来,您将以以下方式创建第一个用户,将用户名替换为您想要使用的用户名。B标志指定了bcrypt加密,比默认加密更安全。

1htpasswd -Bc registry.password username

<$>[注] 注: 若要添加更多用户,请在没有 -c 选项的情况下重新运行之前的命令(c是为创建):

1htpasswd registry.password username

美元

接下来,您将编辑docker-compose.yml文件,告诉Docker使用您创建的文件来验证用户。

1cd ~/docker-registry
2nano docker-compose.yml

您可以为您创建的auth/目录添加环境变量和卷,通过编辑docker-compose.yml文件来告诉Docker如何验证用户。

 1[label docker-compose.yml]
 2version: '3'
 3
 4services:
 5  registry:
 6    image: registry:2
 7    ports:
 8    - "5000:5000"
 9    environment:
10      REGISTRY_AUTH: htpasswd
11      REGISTRY_AUTH_HTPASSWD_REALM: Registry
12      REGISTRY_AUTH_HTPASSWD_PATH: /auth/registry.password
13      REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
14    volumes:
15      - ./auth:/auth
16      - ./data:/data

对于REGISTRY_AUTH,您已指定htpasswd,即您正在使用的身份验证方案,并将REGISTRY_AUTH_HTPASSWD_PATH设置为身份验证文件的路径。

现在,您可以通过运行注册表来验证您的身份验证是否正确,并检查它是否要求用户提供用户名和密码。

1docker-compose up

在浏览器窗口中,打开`https://example.com/v2′′。

输入用户名和相应的密码后,您将再次看到{}。您已经确认了基本的身份验证设置:注册表只在您输入正确的用户名和密码后返回了结果。

步骤 4 – 启动 Docker 注册表作为服务

你想确保你的注册表每次系统启动时都会启动. 如果有任何意外的系统故障,你想确保注册表在服务器重新启动时重新启动。

1nano docker-compose.yml

注册表下添加以下内容行:

1[label docker-compose.yml]
2...
3  registry:
4    restart: always
5...

您可以开始注册表作为一个背景过程,这将允许您退出ssh会话并坚持这个过程:

1docker-compose up -d

随着您的注册表在背景中运行,您现在可以准备 Nginx 进行文件上传。

步骤 5 — 增加 Nginx 的文件上传大小

在您可以将图像推到注册表之前,您需要确保您的注册表能够处理大型文件上传,尽管Docker将大图像上传分为单独的层,但它们有时可能超过1GB

1sudo nano /etc/nginx/nginx.conf

找到http部分,然后添加以下行:

1[label /etc/nginx/nginx.conf]
2...
3http {
4        client_max_body_size 2000M;
5        ...
6}
7...

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

1sudo service nginx restart

您现在可以将大图像上传到您的Docker注册表,而无需 Nginx 错误。

步骤 6 – 发布到您的私人 Docker 注册表

现在你已经准备好将图像发布到你的私人Docker注册表,但首先你必须创建一个图像. 对于本教程,你将创建一个简单的图像,基于来自Docker Hub的ubuntu图像。 Docker Hub是一个公共托管的注册表,有很多预配置的图像,可以利用快速Dockerize应用程序。

从您的 客户端服务器创建一个小,空的图像来推到您的新注册表,-i-t旗帜为您提供交互式容器访问:

1[environment second]
2docker run -t -i ubuntu /bin/bash

完成下载后,您将进入 Docker 提示,请注意以下root@的容器 ID 会有所不同. 通过创建名为SUCCESS的文件快速更改文件系统。

1[environment second]
2touch /SUCCESS

退出 Docker 容器:

1[environment second]
2exit

下面的命令会创建一个名为测试图像的新图像,基于已经运行的图像以及您所做的任何更改。

承诺改变:

1[environment second]
2docker commit $(docker ps -lq) test-image

此时,该图像仅在本地存在,现在您可以将其推到您创建的新注册表。

1[environment second]
2docker login https://example.com

输入用户名和相应的密码从前面。接下来,你将标记图像与私人注册表的位置,以推动它:

1[environment second]
2docker tag test-image example.com/test-image

将新标记的图像推到注册表:

1[environment second]
2docker push example.com/test-image

您的输出将看起来如下:

 1[secondary_label Output]
 2[environment second]
 3The push refers to a repository [example.com/test-image]
 4e3fbbfb44187: Pushed
 55f70bf18a086: Pushed
 6a3b5c80a4eba: Pushed
 77f18b442972b: Pushed
 83ce512daaf78: Pushed
 97aae4540b42d: Pushed
10...

您已验证您的注册表处理用户身份验证,并允许身份验证的用户将图像推到注册表。

步骤 7 – 从您的私人 Docker 注册表中提取

返回您的注册表服务器,以便您可以测试从您的客户端服务器中提取图像,也可以从第三方服务器中测试。

使用您之前设置的用户名和密码登录:

1docker login https://example.com

您现在已经准备好拉动图像了,使用您在上一步标记的域名和图像名称:

1docker pull example.com/test-image

Docker将下载图像并将您返回提示. 如果您在注册表服务器上运行图像,您将看到您之前创建的SUCCESS文件在那里:

1docker run -it example.com/test-image /bin/bash

列出您的文件在 bash 壳中:

1ls

您将看到您为此图像创建的SUCCESS文件:

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

您已完成设置一个安全的注册表,用户可以推和拖动自定义图像。

结论

在本教程中,您设置了自己的私人Docker注册表,并发布了Docker图像。正如介绍中提到的,您还可以使用TravisCI(https://docs.travis-ci.com/user/docker/)或类似的CI工具来自动推送到私人注册表。通过将Docker和注册表应用于您的工作流程,您可以确保包含代码的图像在任何机器上产生相同的行为,无论是在生产中还是在开发中。

Published At
Categories with 技术
comments powered by Disqus