自建容器仓库:Self-Hosting a Container Registry

原文链接: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 ECRGCP Artifact RegistryGitHub 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项目,它提供了存储和分发容器镜像及工件的功能。也就是说,我们可以在一个容器内运行自己的容器仓库。

以下是在服务器上搭建容器仓库的基本步骤:

  1. 在服务器上安装 Docker 和 Docker Compose。
  2. 配置并启动仓库容器。
  3. 运行 nginx 来处理 TLS 加密连接,并将请求转发至仓库容器。
  4. 安装 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.

相关推荐
薯条可乐16 分钟前
获取当前程序运行时的栈大小[C语言]
c语言·面试
久恙5023 小时前
一文学会docker中搭建kali
运维·数据库·学习·网络安全·docker·容器
懒大王敲代码3 小时前
快速搭建Android开发环境:Docker部署docker-android并实现远程连接
android·docker·容器
無言464 小时前
基于docker搭建mysql主从架构
mysql·docker·架构
猿java4 小时前
Java 中什么情况会导致死锁?如何避免?
java·后端·面试
阿伟*rui14 小时前
docker入门
运维·docker·容器
it噩梦16 小时前
k8s 中传递参数给docker容器
docker·容器·kubernetes
weixin_4381973816 小时前
k8s服务内容滚动升级以及常用命令介绍
linux·运维·docker·云原生·容器·kubernetes
.生产的驴17 小时前
Docker 部署Nacos 单机部署 MYSQL数据持久化
android·运维·spring boot·sql·mysql·docker·容器