如何在 Ubuntu 22.04 上设置私有 Docker 注册表
如果您在某个组织工作并希望将 Docker 映像保留在内部以便快速部署,那么托管私有 Docker 存储库是完美的选择。拥有私有的 docker 注册表可以让您拥有自己的镜像分发管道,并对镜像存储和分发进行更严格的控制。您可以将注册表与 CI/CD 系统集成,从而改善您的工作流程。
本教程将教您如何在使用 Amazon S3 作为存储位置的 Ubuntu 22.04 服务器上设置和使用私有 Docker 注册表。
先决条件
两台运行 Ubuntu 22.04 的 Linux 服务器。一台服务器将充当注册主机,而另一台服务器将用作客户端,发送请求并从主机接收图像。
指向主机服务器的注册域名。我们将在教程中使用 registry.example.com
。
在两台计算机上都具有 sudo 权限的非 root 用户。
确保一切都已更新。
$ sudo apt update
$ sudo apt upgrade
您的系统需要的软件包很少。
$ sudo apt install wget curl nano software-properties-common dirmngr apt-transport-https gnupg2 ca-certificates lsb-release ubuntu-keyring unzip -y
其中一些软件包可能已经安装在您的系统上。
第 1 步 - 配置防火墙
第一步是配置防火墙。 Ubuntu 默认带有 ufw(简单防火墙)。
检查防火墙是否正在运行。
$ sudo ufw status
您应该得到以下输出。
Status: inactive
允许 SSH 端口,以便防火墙在启用它时不会中断当前连接。
$ sudo ufw allow OpenSSH
还允许 HTTP 和 HTTPS 端口。
$ sudo ufw allow http
$ sudo ufw allow https
启用防火墙
$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup
再次检查防火墙的状态。
$ sudo ufw status
您应该看到类似的输出。
Status: active
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
80/tcp ALLOW Anywhere
443 ALLOW Anywhere
OpenSSH (v6) ALLOW Anywhere (v6)
80/tcp (v6) ALLOW Anywhere (v6)
443 (v6) ALLOW Anywhere (v6)
第 2 步 - 安装 Docker 和 Docker Compose
服务器和客户端计算机都需要此步骤。
Ubuntu 22.04 附带旧版本的 Docker。要安装最新版本,首先导入 Docker GPG 密钥。
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
创建 Docker 存储库文件。
$ echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
更新系统存储库列表。
$ sudo apt update
安装最新版本的 Docker。
$ sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin
验证它是否正在运行。
$ sudo systemctl status docker
? docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2023-04-13 09:37:09 UTC; 3min 47s ago
TriggeredBy: ? docker.socket
Docs: https://docs.docker.com
Main PID: 2106 (dockerd)
Tasks: 7
Memory: 26.0M
CPU: 267ms
CGroup: /system.slice/docker.service
??2106 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
默认情况下,Docker 需要 root 权限。如果您想避免每次运行 docker
命令时都使用 sudo
,请将您的用户名添加到 docker
组中。
$ sudo usermod -aG docker $(whoami)
您需要注销服务器并以同一用户身份重新登录才能启用此更改或使用以下命令。
$ su - ${USER}
确认您的用户已添加到 Docker 组。
$ groups
navjot wheel docker
第 3 步 - 配置 Docker 注册表
创建用户目录
创建一个用于注册表配置的目录。
$ mkdir ~/docker-registry
切换到 docker-registry 目录。
$ cd ~/docker-registry
创建一个目录,用于存放HTTP认证密码、Nginx配置文件和SSL证书。
$ mkdir auth
创建另一个目录来存储 Nginx 日志。
$ mkdir logs
创建 Amazon S3 存储桶
您可以将注册表数据和图像存储在服务器上或使用云托管服务。在我们的教程中,我们将使用 Amazon S3 云服务。
下一步是使用一些重要设置来设置配置文件。这些设置也可以在 docker-compose.yml 文件中定义,但有一个单独的文件会更好。
使用以下设置创建一个存储桶。
- 应禁用 ACL。
- 应禁用对存储桶的公共访问。
- 应禁用存储桶版本控制。
- 使用 Amazon S3 托管密钥启用存储桶加密。 (SSE-S3)
- 应禁用对象锁定。
使用以下策略创建 IAM 用户。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetBucketLocation",
"s3:ListBucketMultipartUploads"
],
"Resource": "arn:aws:s3:::S3_BUCKET_NAME"
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject",
"s3:ListMultipartUploadParts",
"s3:AbortMultipartUpload"
],
"Resource": "arn:aws:s3:::S3_BUCKET_NAME/*"
}
]
}
将 S3_BUCKET_NAME
替换为您的 S3 存储桶的名称。
记下密钥、密钥值以及稍后要使用的存储桶的存储桶区域。
创建 Docker 撰写文件
创建 docker-compose.yml 文件并将其打开进行编辑。
$ nano docker-compose.yml
将以下代码粘贴到其中。
services:
registry:
image: registry:2
restart: always
environment:
- REGISTRY_STORAGE=s3
- REGISTRY_STORAGE_S3_REGION=us-west-2
- REGISTRY_STORAGE_S3_BUCKET=hf-docker-registry
- REGISTRY_STORAGE_S3_ENCRYPT=true
- REGISTRY_STORAGE_S3_CHUNKSIZE=5242880
- REGISTRY_STORAGE_S3_SECURE=true
- REGISTRY_STORAGE_S3_ACCESSKEY=AKIA3FIG4NVFNXKQXMSJ
- REGISTRY_STORAGE_S3_SECRETKEY=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
- REGISTRY_STORAGE_S3_V4AUTH=true
- REGISTRY_STORAGE_S3_ROOTDIRECTORY=/image-registry
- REGISTRY_STORAGE_CACHE_BLOBDESCRIPTOR=inmemory
- REGISTRY_HEALTH_STORAGEDRIVER_ENABLED=false
nginx:
image: "nginx:alpine"
ports:
- 443:443
links:
- registry:registry
volumes:
- ./auth:/etc/nginx/conf.d
- ./auth/nginx.conf:/etc/nginx/nginx.conf:ro
- ./logs:/var/log/nginx
- /etc/letsencrypt:/etc/letsencrypt
按 Ctrl + X 并在出现提示时输入 Y 来保存文件。
让我们看一下我们在撰写文件中设置的内容。
- REGISTRY_STORAGE 设置存储类型。由于我们使用的是 Amazon S3,因此我们选择了 s3。
- REGISTRY_STORAGE_S3_REGION 设置 S3 存储桶的区域。
- REGISTRY_STORAGE_S3_BUCKET 设置您的 S3 存储桶的名称。
- REGISTRY_STORAGE_S3_ENCRYPT - 如果您已启用存储桶加密,请将其设置为 true。
- REGISTRY_STORAGE_S3_CHUNKSIZE 设置上传块的大小。它应该大于 5MB (5 * 1024 * 1024)。
- REGISTRY_STORAGE_S3_SECURE - 如果您要使用 HTTPS,请将其设置为 true。
- REGISTRY_STORAGE_S3_ACCESSKEY 和 REGISTRY_STORAGE_S3_SECRETKEY - 您在创建 IAM 用户后获取的用户凭证。
- REGISTRY_STORAGE_S3_V4AUTH - 如果您使用 v4 的 AWS 身份验证,请将其设置为 true。如果您收到与 S3 登录相关的错误,请将其设置为 false。
- REGISTRY_STORAGE_S3_ROOTDIRECTORY - 设置存储桶中存储注册表数据的根目录。
- REGISTRY_STORAGE_CACHE_BLOBDESCRIPTOR - 设置缓存的位置。在我们的例子中,我们将其存储在内存中。您还可以将其设置为使用 Redis。
- REGISTRY_HEALTH_STORAGEDRIVER_ENABLED - 将其设置为 false 以禁用注册表的存储运行状况检查服务。注册表存在一个错误,如果您不将其设置为 false,则可能会导致问题。
第一步是从中心获取 Docker 注册表版本 2 的最新映像。我们没有使用latest标签,因为它可能会在大版本升级的情况下引起问题。将其设置为 2 可以让您获取所有 2.x 更新,同时防止自动升级到下一个主要版本,这可能会带来重大更改。
注册表容器设置为在发生故障或意外关闭时始终重新启动。
我们为 Amazon S3 存储设置了各种环境变量。让我们快速浏览一下它们。
Docker 注册表通过端口 5000 进行通信,这是我们在服务器中向 Docker 公开的端口。
./auth:/etc/nginx/conf.d
映射确保所有 Nginx 的设置在容器中可用。
./auth/nginx.conf:/etc/nginx/nginx.conf:ro
将 Nginx 设置文件以只读模式从系统映射到容器中。
./logs:/var/log/nginx
允许通过映射到容器中的 Nginx 日志目录来访问系统上的 Nginx 日志。
Docker注册表的设置存储在容器中的/etc/docker/registry/config.yml
文件中,我们已将其映射到当前的config.yml
文件中目录,我们将在下一步中创建该目录。
设置身份验证
要设置 HTTP 身份验证,您需要安装 httpd-tools
软件包。
$ sudo apt install apache2-utils -y
在 ~/docker-registry/auth
目录中创建密码文件。
$ htpasswd -Bc ~/docker-registry/auth/nginx.htpasswd user1
New password:
Re-type new password:
Adding password for user user1
-c
标志指示命令创建一个新文件,-B
标志是使用 Docker 支持的 bcrypt 算法。将 user1
替换为您选择的用户名。
如果您想添加更多用户,请再次运行该命令,但不要使用 -c
标志。
$ htpasswd -B ~/docker-registry/auth/registry.password user2
现在,该文件将被映射到注册表容器以进行身份验证。
第 4 步 - 安装 SSL
我们需要安装 Certbot 来生成 SSL 证书。您可以使用 Ubuntu 的存储库安装 Certbot,也可以使用 Snapd 工具获取最新版本。我们将使用 Snapd 版本。
Ubuntu 22.04 默认安装了 Snapd。运行以下命令以确保您的 Snapd 版本是最新的。
$ sudo snap install core && sudo snap refresh core
安装证书机器人。
$ sudo snap install --classic certbot
使用以下命令确保可以通过创建到 /usr/bin
目录的符号链接来运行 Certbot 命令。
$ sudo ln -s /snap/bin/certbot /usr/bin/certbot
运行以下命令生成 SSL 证书。
$ sudo certbot certonly --standalone --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m [email -d registry.example.com
上述命令会将证书下载到服务器上的 /etc/letsencrypt/live/registry.example.com
目录中。
生成 Diffie-Hellman 组证书。
$ sudo openssl dhparam -dsaparam -out /etc/ssl/certs/dhparam.pem 4096
检查 Certbot 续订调度程序服务。
$ sudo systemctl list-timers
您会发现 snap.certbot.renew.service
是计划运行的服务之一。
NEXT LEFT LAST PASSED UNIT ACTIVATES
.....
Sun 2023-04-14 00:00:00 UTC 19min left Sat 2023-02-25 18:04:05 UTC n/a snap.certbot.renew.timer snap.certbot.renew.service
Sun 2023-04-14 00:00:20 UTC 19min left Sat 2023-02-25 10:49:23 UTC 14h ago apt-daily-upgrade.timer apt-daily-upgrade.service
Sun 2023-04-14 00:44:06 UTC 3h 22min left Sat 2023-02-25 20:58:06 UTC 7h ago apt-daily.timer apt-daily.service
对该过程进行一次演练,以检查 SSL 续订是否正常工作。
$ sudo certbot renew --dry-run
如果没有看到任何错误,则一切都已准备就绪。您的证书将自动更新。
将 Dhparam 文件复制到容器中
将Diffie-Hellman组证书复制到~/docker-registry/auth
目录,该目录将映射到容器。
$ sudo cp /etc/ssl/certs/dhparam.pem ~/docker-registry/auth
第 5 步 - 配置 Nginx
下一步涉及将 Nginx 服务器配置为 Docker 注册表服务器的前端代理。 Docker 注册表附带一个在端口 5000 运行的内置服务器。我们将其放在 Nginx 后面。
创建并打开文件 ~/docker-registry/auth/nginx.conf
进行编辑。
$ sudo nano ~/docker-registry/auth/nginx.conf
将以下代码粘贴到其中。
events {
worker_connections 1024;
}
http {
upstream docker-registry {
server registry:5000;
}
## Set a variable to help us decide if we need to add the
## 'Docker-Distribution-Api-Version' header.
## The registry always sets this header.
## In the case of nginx performing auth, the header is unset
## since nginx is auth-ing before proxying.
map $upstream_http_docker_distribution_api_version $docker_distribution_api_version {
'' 'registry/2.0';
}
server {
listen 443 ssl http2;
server_name registry.example.com;
# SSL
ssl_certificate /etc/letsencrypt/live/registry.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/registry.example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/registry.example.com/chain.pem;
access_log /var/log/nginx/registry.access.log;
error_log /var/log/nginx/registry.error.log;
# Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers on;
ssl_ecdh_curve X25519:prime256v1:secp384r1:secp521r1;
ssl_session_cache shared:SSL:10m;
ssl_dhparam /etc/nginx/conf.d/dhparam.pem;
resolver 8.8.8.8;
# disable any limits to avoid HTTP 413 for large image uploads
client_max_body_size 0;
# required to avoid HTTP 411: see Issue #1486 (https://github.com/moby/moby/issues/1486)
chunked_transfer_encoding on;
location /v2/ {
# 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;
}
# To add basic authentication to v2 use auth_basic setting.
auth_basic "Registry realm";
auth_basic_user_file /etc/nginx/conf.d/nginx.htpasswd;
## If $docker_distribution_api_version is empty, the header is not added.
## See the map directive above where this variable is defined.
add_header 'Docker-Distribution-Api-Version' $docker_distribution_api_version always;
proxy_pass http://docker-registry;
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;
}
}
}
完成后按 Ctrl + X 并在出现提示时输入 Y 来保存文件。
第 6 步 - 启动 Docker 注册表
切换到 Docker 注册表的目录。
$ cd ~/docker-registry
启动 docker 容器。
$ docker compose up -d
检查容器的状态。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3328b7e36bb2 nginx:alpine "/docker-entrypoint.…" About a minute ago Up 3 seconds 80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp docker-registry-nginx-1
bf7cdfc0e013 registry:2 "/entrypoint.sh /etc…" About a minute ago Up About a minute 5000/tcp docker-registry-registry-1
登录 Docker 注册表。
$ docker login -u=user1 -p=password https://registry.example.com
您将得到以下输出。
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /home/username/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
您还可以在浏览器中打开 URL https://registry.example.com/v2/
,它会要求输入用户名和密码。您应该会看到一个带有 {} 的空白页面。
您可以使用 curl
在终端上检查 URL。
$ curl -u user1 -X GET https://registry.example.com/v2/
Enter host password for user 'user1':
{}
下载最新的 Ubuntu docker 镜像。
$ docker pull ubuntu:latest
将此图像标记为私人注册表。
$ docker tag ubuntu:latest registry.example.com/ubuntu2204
将映像推送到注册表。
$ docker push registry.example.com/ubuntu2204
测试是否推送成功。
$ curl -u user1 -X GET https://registry.example.com/v2/_catalog
Enter host password for user 'user1':
{"repositories":["ubuntu2204"]}
出现提示时输入您的 Nginx 身份验证密码,您将看到通过注册表可用的存储库列表。
使用终端注销以清除凭据。
$ docker logout https://registry.example.com
Removing login credentials for registry.example.com
检查当前可用的 Docker 镜像列表。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry 2 8db46f9d7550 2 weeks ago 24.2MB
nginx alpine 8e75cbc5b25c 2 weeks ago 41MB
ubuntu latest 08d22c0ceb15 5 weeks ago 77.8MB
registry.example.com/ubuntu2204 latest 08d22c0ceb15 5 weeks ago 77.8MB
第 7 步 - 从客户端计算机访问并使用 Docker 注册表
登录到您的客户端服务器。在步骤 1 中,我们在客户端计算机上安装了 Docker。
从客户端计算机登录到私有 Docker 注册表。
$ docker login -u=user1 -p=password https://registry.example.com
从注册表中提取 Ubuntu 映像。
$ docker pull registry.example.com/ubuntu2204
列出客户端计算机上的所有图像。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry.example.com/ubuntu2204 latest 08d22c0ceb15 5 weeks ago 77.8MB
使用下载的映像创建并启动容器。
$ docker run -it registry.example.com/ubuntu2204 /bin/bash
您将登录到 Ubuntu 容器内的 Shell。
root@647899f255db:
执行以下命令查看Linux版本。
root@a2da49fdbea9$ cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.2 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.2 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
现在,您可以开始从客户端计算机使用 Docker 注册表。
结论
关于在使用 Amazon S3 作为存储的 Ubuntu 22.04 服务器上设置私有 Docker 注册表的教程到此结束。如果您有任何疑问,请在下面的评论中发表。