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

作者选择了 自由和开源基金作为 写给捐款计划的一部分接受捐款。

介绍

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

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

在本教程中,您将设置和保护自己的私人Docker注册表. 您将使用Docker Compose(https://docs.docker.com/compose/)来定义运行Docker容器和Nginx的配置,将服务器流量从互联网转移到运行Docker容器。

前提条件

要完成本教程,您将需要以下内容:

  • 两个 Ubuntu 22.04 服务器是按照 Ubuntu 22.04 初始服务器设置指南设置的,包括一个sudo非根用户和一个防火墙. 一个服务器将 托管您的私人 Docker 注册表,另一个将是您的 客户端服务器。

host 服务器上,您需要设置:

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

在命令行上运行Docker在启动和测试集装箱时是有用的,但在涉及多个集装箱并行运行的更大部署时,它可能会变得模糊。

使用 Docker Compose,您可以编写一个.yml 文件来设置每个容器的配置和容器需要相互通信的信息。

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

您将将配置存储在主机服务器上的名为docker-registry的目录中。

1mkdir ~/docker-registry

导航它:

1cd ~/docker-registry

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

1mkdir data

创建并打开名为 'docker-compose.yml' 的文件,运行:

1nano docker-compose.yml

添加以下行,这些行定义了 Docker 注册表的基本实例:

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

首先,您将第一个服务命名为注册表,并将其图像设置为注册表,使用最新版本。然后,在端口下,您将主机上的端口5000地图到容器的端口5000,这将允许您将请求发送到服务器上的端口5000,并将请求发送到注册表。

环境部分中,您将REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY变量设置为/data,指定它应该存储数据的体积。

保存并关闭文件。

您现在可以通过运行开始配置:

1docker compose up

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

 1[secondary_label Output]
 2[+] Running 2/2
 3  Network docker-registry_default Created 0.1s
 4  Container docker-registry-registry-1 Created 0.1s
 5Attaching to docker-registry-registry-1
 6docker-registry-registry-1  | time="2022-11-19T14:31:20.40444638Z" 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.16.15 instance.id=4fb8d420-eaf8-4a69-b740-bdc94fa52d91 service=registry version="v2.8.1+unknown"
 7docker-registry-registry-1  | time="2022-11-19T14:31:20.404960549Z" level=info msg="redis not configured" go.version=go1.16.15 instance.id=4fb8d420-eaf8-4a69-b740-bdc94fa52d91 service=registry version="v2.8.1+unknown"
 8docker-registry-registry-1  | time="2022-11-19T14:31:20.412312462Z" level=info msg="using inmemory blob descriptor cache" go.version=go1.16.15 instance.id=4fb8d420-eaf8-4a69-b740-bdc94fa52d91 service=registry version="v2.8.1+unknown"
 9docker-registry-registry-1  | time="2022-11-19T14:31:20.412803878Z" level=info msg="Starting upload purge in 52m0s" go.version=go1.16.15 instance.id=4fb8d420-eaf8-4a69-b740-bdc94fa52d91 service=registry version="v2.8.1+unknown"
10docker-registry-registry-1  | time="2022-11-19T14:31:20.41296431Z" level=info msg="listening on [::]:5000" go.version=go1.16.15 instance.id=4fb8d420-eaf8-4a69-b740-bdc94fa52d91 service=registry version="v2.8.1+unknown"
11...

您将在本教程中稍后解决没有提供 HTTP 秘密的警告消息。

输出的最后一行表示它已经成功启动,听到端口5000

您可以按「CTRL + C」來停止執行。

在此步骤中,您创建了一个 Docker Compose 配置,该配置将启动 Docker 注册表在端口5000上聆听。

步骤 2 — 设置 Nginx 端口转发

作为先决条件的一部分,您在您的域中启用了 HTTPS. 要将您的安全 Docker 注册表暴露在那里,您需要配置 Nginx 来将流量从您的域转移到注册表容器。

您已经设置了包含您的服务器配置的 /etc/nginx/sites-available/your_domain 文件。

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

查找现有的位置块:

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

您需要将流量转发到端口5000,您的注册表将听取流量。您还希望将标题附加到向注册表转发的请求中,该请求由服务器提供有关请求本身的额外信息。

 1[label /etc/nginx/sites-available/your_domain]
 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...

如果块检查请求的用户代理,并验证 Docker 客户端的版本高于 1.5,并且它不是试图访问的Go应用程序。

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

1sudo systemctl restart nginx

如果您收到错误消息,请双重检查您添加的配置。

要确认 Nginx 正在正确地将流量转移到您的注册表容器上的端口5000,请运行它:

1docker compose up

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

1https://your_domain/v2

浏览器会加载一个空的 JSON 对象:

1[environment third]
2{}

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

1[secondary_label Output]
2docker-registry-registry-1  | time="2022-11-19T14:32:50.082396361Z" level=info msg="response completed" go.version=go1.16.15 http.request.host=your_domain http.request.id=779fe265-1a7c-4a15-8ae4-eeb5fc35de98 http.request.method=GET http.request.remoteaddr=87.116.166.89 http.request.uri="/v2" http.request.useragent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36" http.response.contenttype="text/html; charset=utf-8" http.response.duration="162.546µs" http.response.status=301 http.response.written=39
3docker-registry-registry-1  | 172.19.0.1 - - [19/Nov/2022:14:32:50 +0000] "GET /v2 HTTP/1.0" 301 39 "" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36"
4docker-registry-registry-1  | 172.19.0.1 - - [19/Nov/2022:14:32:50 +0000] "GET /v2/ HTTP/1.0" 200 2 "" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36"
5docker-registry-registry-1  | time="2022-11-19T14:32:50.132472674Z" level=info msg="response completed" go.version=go1.16.15 http.request.host=your_domain http.request.id=0ffb17f0-c2a0-49d6-94f3-af046cfb96e5 http.request.method=GET http.request.remoteaddr=87.116.166.89 http.request.uri="/v2/" http.request.useragent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36" http.response.contenttype="application/json; charset=utf-8" http.response.duration=2.429608ms http.response.status=200 http.response.written=2
6docker-registry-registry-1  | 172.19.0.1 - - [19/Nov/2022:14:32:50 +0000] "GET /favicon.ico HTTP/1.0" 404 19 "your_domain/v2/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36"

从最后一行,你知道一个GET请求被发送到/v2/,这是你发送请求的终端。

CTRL+C停止执行。

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

步骤三:设置身份验证

Nginx 允许您为其管理的网站设置 HTTP 身份验证,您可以使用它来限制访问您的 Docker 注册表. 为了实现这一点,您将创建一个使用 `htpasswd’ 的身份验证文件,并添加用户名和密码组合,这些组合将被接受. 该过程将允许对您的注册表进行身份验证。

您可以通过安装apache2-utils包来获取htpasswd实用程序。

1sudo apt install apache2-utils -y

您将存储身份验证文件与凭证在 ~/docker-registry/auth 下。

1mkdir ~/docker-registry/auth

导航它:

1cd ~/docker-registry/auth

创建第一个用户,用你想要使用的用户名替换用户名B旗下命令使用bcrypt算法, Docker 需要:

1htpasswd -Bc registry.password username

提示时输入密码. 认证组合将附加到 registry.password

<$>[注] 注: 若要添加更多用户,请重新运行以前的命令而无需 -c:

1htpasswd -B registry.password username

-c 会创建一个新的文件,因此删除它会更新现有文件。

现在创建了凭证列表,您将编辑docker-compose.yml,命令Docker使用您创建的文件来验证用户。

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

添加突出的线条:

 1[label ~/docker-registry/docker-compose.yml]
 2version: '3'
 3
 4services:
 5  registry:
 6    image: registry:latest
 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

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

您还安装了 ./auth 目录,以使文件在注册表容器中可用。

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

1cd ~/docker-registry

然后,运行注册表,执行:

1docker compose up

在您的浏览器中,更新您的域名页面,您将被要求提供用户名和密码。

提供有效的凭证组合后,您将访问带有空JSON对象的页面:

1[environment third]
2{}

您已成功身份验证并获得访问注册表. 通过在您的终端中按CTRL+C退出。

您的注册表现在是安全的,只能在身份验证后访问,然后将其配置为作为背景流程运行,同时可以通过自动启动重新启动。

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

您可以通过指示 Docker Compose 始终保持运行,确保注册表容器每次启动或系统崩溃后启动。

打开docker-compose.yml进行编辑:

1nano docker-compose.yml

将下列行添加到注册表块中:

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

重新启动设置为始终,确保容器能够存活在重新启动中。

您现在可以通过输入 -d 来启动您的注册表作为背景过程:

1docker compose up -d

随着您的注册表在背景中运行,您可以自由关闭SSH会话,终端和注册表不会受到影响。

由于 Docker 图像的大小可能非常大,您将进一步增加 Nginx 将接受上传的最大文件大小。

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

在您可以将图像推到注册表之前,您需要确保您的注册表能够处理大型文件上传。在 Nginx 中,文件上传的默认大小限制为1m,这对于 Docker 图像来说并不足够。

打开它来编辑:

1sudo nano /etc/nginx/nginx.conf

将突出的行添加到http部分:

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

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

保存并关闭文件。

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

1sudo systemctl restart nginx

在此步骤中,您更新了 Nginx 允许的文件大小,您现在可以将大图像上传到您的 Docker 注册表,而不让 Nginx 阻止传输或错误。

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

现在你的Docker注册表服务器正在运行并接受大型文件大小,你可以尝试将图像推到它上,因为你没有任何可用的图像,你会使用公共Docker注册表的Docker Hub的ubuntu图像来测试这一点。

在您的客户端服务器的新终端会话中,运行以下命令来下载ubuntu图像,运行它,并访问其壳:

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

it旗帜为您提供交互式容器进入容器。

一旦你进入,创建一个名为成功的文件,运行:

1[environment second]
2touch /SUCCESS

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

走出容器壳:

1[environment second]
2exit

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

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

新图像现在在本地可用,您将将其推到您的容器注册表。

1[environment second]
2docker login https://your_domain

当被提示时,输入您在步骤 3 中定义的用户名和密码凭证。

产量将是:

1[secondary_label Output]
2[environment second]
3...
4Login Succeeded

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

1[environment second]
2docker tag test-image your_domain/test-image

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

1[environment second]
2docker push your_domain/test-image

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

1[secondary_label Output]
2[environment second]
3Using default tag: latest
4The push refers to a repository [your_domain/test-image]
51cf9c9034825: Pushed
6f4a670ac65b6: Pushed
7latest: digest: sha256:95112d0af51e5470d74ead77932954baca3053e04d201ac4639bdf46d5cd515b size: 736

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

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

现在您已经将图像推到您的私人注册表,您将尝试从中提取。

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

1docker login https://your_domain

尝试通过运行引导测试图像:

1docker pull your_domain/test-image

Docker 将下载图像. 使用以下命令运行容器:

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

它将为容器加载壳。

通过运行来列出当前的文件:

1ls

文件列表将包含您之前创建的SUCCESS文件,确认此容器使用您创建的相同图像:

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

输出容器壳:

1exit

您已经测试了拍摄和拍摄图像,并完成了安全注册表的设置,您可以使用它来存储自定义图像。

结论

在本教程中,您设置了自己的私人 Docker 注册表并发布了 Docker 图像,正如介绍中提到的,您还可以使用 TravisCI或类似的 CI 工具来自动推送到私人注册表。

通过在工作流中使用 Docker 容器,您可以确保包含代码的图像在任何机器上都具有相同的行为,无论是在生产中还是在开发中。

Published At
Categories with 技术
comments powered by Disqus