作者选择了 自由和开源基金作为 写给捐款计划的一部分接受捐款。
介绍
Docker Registry是一个管理存储和交付 Docker 容器图像的应用程序。注册表集中容器图像并缩短开发人员的构建时间。Docker 图像通过虚拟化保证了相同的运行时间环境,但构建图像可能需要大量的时间。例如,而不是单独安装依赖和包来使用 Docker,开发人员可以从包含所有必要组件的注册表下载压缩图像。
Docker 还有一个免费的公共注册表 Docker Hub,可以托管您自定义的 Docker 图像,但有些情况下,您不希望您的图像公开可用。
在本教程中,您将设置和保护自己的私人Docker注册表. 您将使用Docker Compose(https://docs.docker.com/compose/)来定义运行Docker容器的配置,并使用 Nginx将服务器流量从互联网转移到运行Docker容器。
前提条件
- 通过遵循Ubuntu 20.04 初始服务器设置指南,包括一个 " sudo " 非终端用户和一个防火墙而设置的两个Ubuntu 20.04服务器。 一个服务器将 ** 主机 ** 您的私人 Docker 注册, 另一个将是 您的 ** 客户端 ** 服务器 。
- 两个服务器上都安装了多克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克
- Docker 编译器安装在host服务器上,方法是遵循Step 1 [如何安装和使用 Ubuntu 20.04] (https://andsky.com/tech/tutorials/how-to-install-and-use-docker-compose-on-ubuntu-20-04).
- Nginx 安装在您host 服务器上,方法是遵循 [How To Install Nginx on Ubuntu 20.04] (https://andsky.com/tech/tutorials/how-to-install-nginx-on-ubuntu-20-04)中的步骤.
- Nginx 通过遵循 [How To Secure Nginx with Let's Encrypt on Ubuntu 20.04] (https://andsky.com/tech/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-20-04) 教程,在您的服务器上为私人多克注册提供加密保障. 确保将所有流量从HTTP转向HTTPS在** 第4步**.
- 一个域名,可以解决您正在用于私人多克注册的服务器. 你把这个设定为"让我们加密"的先决条件 在这个教程中,我们将把它称为`你的域'. (英语)
步骤 1 – 安装和配置 Docker 注册表
命令行上的Docker在启动和测试集装箱时很有用,但对于涉及多个集装箱并行运行的更大部署来说,它显得不方便。
使用 Docker Compose,您可以编写一个.yml 文件来设置每个容器的配置和容器需要相互通信的信息. 您可以使用docker-compose
命令行工具发出命令给构成您的应用程序的所有组件,并控制它们作为一个组。
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:2
7 ports:
8 - "5000:5000"
9 environment:
10 REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
11 volumes:
12 - ./data:/data
首先,您将第一个服务命名为注册表
,并将其图像设置为注册表
,版本2
。然后,在端口
下,您将主机上的端口5000
地图到容器的端口5000
。
在环境
部分中,您将REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY
变量设置为/data
,指定它应该存储数据的体积。
保存并关闭文件。
您现在可以通过运行开始配置:
1docker-compose up
注册表容器及其依赖将下载并启动。
1[secondary_label Output]
2Creating network "docker-registry_default" with the default driver
3Pulling registry (registry:2)...
42: Pulling from library/registry
5e95f33c60a64: Pull complete
64d7f2300f040: Pull complete
735a7b7da3905: Pull complete
8d656466e1fe8: Pull complete
9b6cb731e4f93: Pull complete
10Digest: sha256:da946ca03fca0aade04a73aa94b54ff0dc614216bdd1d47585f97b4c1bdaa0e2
11Status: Downloaded newer image for registry:2
12Creating docker-registry_registry_1 ... done
13Attaching to docker-registry_registry_1
14registry_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
15registry_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
16registry_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
17registry_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
18...
请注意,输出的最后一行显示它已成功开始在端口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...
3location / {
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{}
在您的终端中,您将收到类似于以下的输出:
1[secondary_label Output]
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/
,这是您发送请求的终端点,来自您的浏览器。
按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
美元
现在创建了凭证列表,您将编辑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: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
您已添加了指定使用 HTTP 身份验证的环境变量,并提供了创建的 htpasswd
文件的路径。 对于 REGISTRY_AUTH
,您已指定 htpasswd
作为其值,即您正在使用的身份验证方案,并将 `REGISTRY_AUTH_HTPASSWD_PATH' 设置为身份验证文件的路径。
您还安装了 ./auth
目录,以使该文件在注册表容器中可用。
现在您可以验证您的身份验证是否正常工作. 首先,导航到主目录:
1cd ~/docker-registry
然后,运行注册表,执行:
1docker-compose up
在您的浏览器中,更新您的域名页面,您将被要求提供用户名和密码。
提供有效的凭证组合后,您将看到一个空的 JSON 对象:
1{}
这意味着您已经成功验证并获得了注册表的访问权限。
您的注册表现在是安全的,只能在身份验证后访问,您现在将其配置为作为背景流程运行,同时可以通过自动启动重新启动。
步骤 4 – 启动 Docker 注册表作为服务
您可以通过指示 Docker Compose 始终保持运行,确保注册表容器每次启动或系统崩溃后都启动。
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 图像来说几乎不够。 要提高它,您将修改位于 `/etc/nginx/nginx.conf 的主要 Nginx 配置文件。
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
您现在可以将大图像上传到您的Docker注册表,而无需 Nginx阻止传输或错误。
步骤 6 – 发布到您的私人 Docker 注册表
现在你的Docker注册表服务器正在运行,并接受大型文件大小,你可以尝试将图像推向它. 因为你没有任何可用的图像,你将使用公共Docker注册表的Docker Hub的ubuntu
图像来测试。
从您的第二个客户端服务器运行以下命令来下载ubuntu
图像,运行它,并访问其壳:
1[environment second]
2docker run -t -i ubuntu /bin/bash
i
和t
旗帜为您提供交互式容器进入容器。
一旦你进入,创建一个名为成功
的文件,运行:
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...
3Login 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]
3The push refers to a repository [your_domain/test-image]
4420fa2a9b12e: Pushed
5c20d459170d8: Pushed
6db978cae6a05: Pushed
7aeb3f02e9374: Pushed
8latest: digest: sha256:88e782b3a2844a8d9f0819dc33f825dde45846b1c5f9eb4870016f2944fe6717 size: 1150
您已验证您的注册表通过登录来处理用户身份验证,并允许已验证的用户将图像推到注册表。
步骤 7 – 从您的私人 Docker 注册表中提取
现在您已经将图像推到您的私人注册表,您将尝试从中提取。
在主服务器上,使用您之前设置的用户名和密码登录:
1docker login https://your_domain
尝试通过运行引导测试图像
:
1docker pull your_domain/test-image
Docker 应该下载图像. 使用以下命令运行容器:
1docker run -it your_domain/test-image /bin/bash
通过运行来列出当前的文件:
1ls
您将看到您之前创建的成功
文件,确认它是您创建的相同图像:
1SUCCESS bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
走出容器壳:
1exit
现在你已经测试了推和拉图像,你已经完成了设置一个安全的注册表,你可以使用它来存储自定义图像。
结论
在本教程中,您可以使用 TravisCI或类似的 CI 工具直接自动推送到私人注册表。通过在工作流中利用 Docker 容器,您可以确保包含代码的图像在任何机器上产生相同的行为,无论是在生产中还是在开发中。