原文链接:packagemain.tech/p/self-host...
原文作者:Alex Pliutau
译者:菜小鸟魔王
01 什么是容器镜像?
在探讨容器仓库之前,我们先来弄清楚容器镜像的概念。简单来说,容器镜像就是一个包含了运行容器所需全部文件、库和配置的打包文件。它由多个 layers 构成,每个 layer 代表了文件系统的一系列变更,涉及文件的添加、移除或修改。
通常,我们通过编写 Dockerfile 来创建容器镜像。
bash
# build an image
docker build -t pliutau/hello-world:v0 .
# check the images locally
docker images
# REPOSITORY TAG IMAGE ID CREATED SIZE
# hello-world latest 9facd12bbcdd 22 seconds ago 11MB
这样,就能创建一个存储在本地机器上的容器镜像。但如果想要将这个镜像分享给他人,或者在另一台机器上使用,这就需要借助容器仓库来实现。
02 什么是容器仓库?
容器仓库是一个存储系统,我们可以在这里上传和下载容器镜像。镜像被分类存放在不同的仓库中,每个仓库是一组具有相同名称的相关镜像。例如,在 Docker Hub 上,nginx这个仓库存放着不同版本的 nginx 镜像。
有些仓库是公开的,任何人都可以在互联网上访问这些仓库中的镜像。公共仓库,如Docker Hub,是托管开源项目的理想场所。
相对地,私有仓库则为企业存储容器镜像提供了一种较为安全和隐私的方法,无论是云服务还是本地部署。这些私有仓库通常配备了先进的安全功能和专业技术支持。市面上有许多私有仓库可供选择,比如Amazon ECR、GCP Artifact Registry、GitHub Container Registry,甚至 Docker Hub 也提供有私有仓库的功能。
开发人员可以使用 docker push 和 docker pull 命令与容器仓库进行交互。
bash
docker push docker.io/pliutau/hello-world:v0
# In case of Docker Hub we could also skip the registry part
docker push pliutau/hello-world:v0
让我们来看看容器镜像 URL 的构造。
ruby
docker pull docker.io/pliutau/hello-world:v0@sha256:dc11b2...
| | | |
↓ ↓ ↓ ↓
registry repository tag digest
03 为何要自行搭建容器仓库?
有时候,你或许希望不借助 AWS 或 GCP 等服务商,而是自行管理镜像。这样做可以将基础设施建立在企业内部,降低对外部供应商的依赖。在某些严格监管的行业中,这是必须遵守的规定。
自行搭建的容器仓库将在我们自己的服务器上运行,这让我们能够更自主地控制仓库的配置方式和镜像的存放位置。但与此同时,也意味着需要承担维护和保护仓库的额外成本。
04 如何自行搭建容器仓库?
目前市面上有几款开源的容器仓库解决方案。其中最受欢迎的是 Docker 官方支持的registry项目,它提供了存储和分发容器镜像及工件的功能。也就是说,我们可以在一个容器内运行自己的容器仓库。
以下是在服务器上搭建容器仓库的基本步骤:
- 在服务器上安装 Docker 和 Docker Compose。
- 配置并启动仓库容器。
- 运行 nginx 来处理 TLS 加密连接,并将请求转发至仓库容器。
- 安装 SSL 证书,并配置好域名。
05 Server
可以选用任何能够运行Docker的服务器。比如,可以选用带有Ubuntu系统的DigitalOcean Droplet。在本文中,我选择了Google Cloud Compute来创建一个装有Ubuntu系统的虚拟机。
ini
neofetch
# OS: Ubuntu 20.04.6 LTS x86_64
# CPU: Intel Xeon (2) @ 2.200GHz
# Memory: 3908MiB
进入虚拟机后,我们需要安装Docker和Docker Compose。虽然Docker Compose并非必需,但它能让我们更轻松地管理多容器应用程序。
bash
# install docker engine and docker-compose
sudo snap install docker
# verify the installation
docker --version
docker-compose --version
06 容器仓库的配置
接下来,我们需要配置 registry 容器。下面这个compose.yaml配置文件将创建一个 registry 容器,并为其分配两个卷,一个用于存放镜像,另一个用于存放密码文件。
yaml
services:
registry:
image: registry:latest
environment:
REGISTRY_AUTH: htpasswd
REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
REGISTRY_AUTH_HTPASSWD_PATH: /auth/registry.password
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
volumes:
# Mount the password file
- ./registry/registry.password:/auth/registry.password
# Mount the data directory
- ./registry/data:/data
ports:
- 5000
在配置中指定的REGISTRY_AUTH_HTPASSWD_PATH路径下的密码文件,将用于用户在推送或拉取镜像时进行身份验证。我们需要通过运行htpasswd命令来生成这个密码文件。同时,我们还需要创建一个目录来存放镜像文件。
bash
mkdir -p ./registry/data
# install htpasswd
sudo apt install apache2-utils
# create a password file. username: busy, password: bee
htpasswd -Bbn busy bee > ./registry/registry.password
配置完成后,我们就可以启动 registry 容器了。如果看到这条信息,说明一切正常。
arduino
docker-compose up
# successfull run should output something like this:
# registry | level=info msg="listening on [::]:5000"
07 SSL证书和Nginx
前面提到,我们可以利用Nginx来处理TLS加密连接,并将请求代理到仓库容器。Docker仓库在运行时需要有效的可信SSL证书。你可以选择使用Let's Encrypt来自动获取证书,或者手动申请。你需要确保有一个域名指向你的服务器(例如我的域名是registry.pliutau.com)。在这个示例中,我已经通过certbot工具获取了证书,并存放在了./nginx/certs目录下。
由于我们的Docker仓库是作为容器运行的,我们同样可以在compose.yaml文件中添加相应的服务,以便将Nginx也作为容器来运行。
yaml
services:
registry:
# ...
nginx:
image: nginx:latest
depends_on:
- registry
volumes:
# mount the nginx configuration
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
# mount the certificates obtained from Let's Encrypt
- ./nginx/certs:/etc/nginx/certs
ports:
- "443:443"
nginx.conf文件如下所示:
ini
worker_processes auto;
events {
worker_connections 1024;
}
http {
upstream registry {
server registry:5000;
}
server {
server_name registry.pliutau.com;
listen 443 ssl;
ssl_certificate /etc/nginx/certs/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/privkey.pem;
location / {
# important setting for large images
client_max_body_size 1000m;
proxy_pass http://registry;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 900;
}
}
}
08 Ready to go!
执行完上述步骤后,我们就可以运行自己的仓库和Nginx容器了。
docker-compose up
接下来,在客户端能够从私有仓库中推送和拉取镜像。在此之前,需要先登录到镜像仓库。
bash
docker login registry.pliutau.com
# Username: busy
# Password: bee
# Login Succeeded
现在,我们可以开始构建镜像,并将其推送到我们自行搭建的仓库了!
bash
docker build -t registry.pliutau.com/pliutau/hello-world:v0 .
docker push registry.pliutau.com/pliutau/hello-world:v0
# v0: digest: sha256:a56ea4... size: 738
同时,你可以在服务器上的存储目录中查看已上传的镜像。
bash
ls -la ./registry/data/docker/registry/v2/repositories/
09 其他选择
依照上面的例子,同样可以在Kubernetes上部署仓库。或者,可以选择使用Harbor这样的托管仓库服务,这是一个开源项目,提供高级安全功能,并且与Docker和Kubernetes无缝对接。
如果你希望为自己的私有仓库添加一个图形界面,可以尝试使用joxit/docker-registry-ui这样的项目,并在单独的容器中运行。
10 总结
自建容器仓库让我们能够全面掌控容器仓库及其部署过程。但这也意味着我们需要承担起维护和保护仓库的责任。
不管出于何种目的选择自建仓库,你现在应该已经掌握了必要的操作方法。接下来,你可以根据自身需求,比较不同的方案,做出最佳选择。
You can find the full source code for this demo on GitHub. Also, you can watch it as a video on our YouTube channel.