容器 registry 是一個存放目錄,從這裡您可以推送和拉取容器映像。

開發者可以使用很多公開和私人的 registry,例如 Docker HubAmazon ECRGoogle Cloud Artifact Registry。但有时候,您可能會選擇不依賴於外部供應商,而是自己托管映像。這讓您能夠有更多控制權,決定 registry 的配置方式以及容器映像存放的位置。

本文將手把手教您如何自托管一個容器 registry。

目錄

如果您已經熟悉如Docker和NGINX等工具,並對容器有基本的認識,您將能從這篇文章中获得最多的資訊。

什麼是容器映像?

在我們討論容器註冊庫之前,讓我們先了解什麼是容器映像。简而言之,容器映像是一個包含所有文件、庫和配置以運行容器的包。它們由組成,每個層代表一組文件系統變動,用於添加、移除或修改文件。

創建容器映像最常見的方式是使用Dockerfile

# 建立映像
docker build -t pliutau/hello-world:v0 .

# 在本地檢查映像
docker images
# 倉庫地址    標籤       映像ID         創建時間          大小
# hello-world   latest    9facd12bbcdd   22 秒前          11MB

這會創造一個存儲在您本地電腦上的容器映像。但如果您想與他人分享此映像或在不同電腦上使用它該如何呢?這就是容器註冊庫发挥作用的地方。

什么是容器註冊庫?

容器註冊庫是一個存放庫,您可以從其中推送和拉取容器映像。這些映像被 分組 到庫中,庫是具有相同名稱的相關映像的集合。例如,在 Docker Hub 註冊庫上,nginx 是包含不同版本的 NGINX 映像的庫的名稱。

有些註冊庫是公開的,意味著存放在它們上面的映像可以向互聯網上的任何人開放。像 Docker Hub 這樣的公开註冊庫是托管開源項目的好選擇。

另一方面,私有註冊庫為企業容器映像存儲提供了一種實現安全和隱私的方式,無論是托管在雲還是本地。這些私有註冊庫通常配備了進階安全性功能和技術支持。

有越来越多的私有註冊庫可供選擇,例如 Amazon ECRGCP Artifact RegistryGitHub Container Registry,而 Docker Hub 也提供私有庫功能。

作為開發者,當你使用 docker pushdocker pull 命令時,你會與容器註冊庫互動。

docker push docker.io/pliutau/hello-world:v0

# 如果是 Docker Hub,我們也可以省略註冊庫部分
docker push pliutau/hello-world:v0

讓我們看一下容器映像URL的結構:

docker pull docker.io/pliutau/hello-world:v0@sha256:dc11b2...
                |            |            |          |
                ↓            ↓            ↓          ↓
             registry    repository      tag       digest

为什么您可能会想要自托管容器注册库

有时,您可能會想要像 AWS 或 GCP 這樣的提供商一樣,自己托管映像。這使得您的基礎設施保持內部化,並且使您對外部供應商的依賴減少。在某些嚴格的規範行業中,這甚至是一個要求。

自托管註冊庫在您自己的服務器上運行,這使您有更多的控制權來配置註冊庫以及托管容器映像的位置。同時,它也帶來了維護和保護註冊庫的費用。

如何自托管容器注册库

有幾個開源的容器註冊庫解決方案可供選擇。最受欢迎的一个是由 Docker 正式支持的,称为 registry,它用于存储和分发容器映像和工件。這意味著您可以在容器內運行自己的註冊庫。

以下是在服務器上運行註冊庫的主要步驟:

  • 在服務器上安装 Docker 和 Docker Compose。

  • 配置並運行 registry 容器。

  • 運行 NGINX 以處理 TLS 並將請求转发給註冊表容器。

  • 設置 SSL 憑證並配置域名。

步驟 1: 在伺服器上安裝 Docker 和 Docker Compose

您可以使用任何支持 Docker 的伺服器。例如,您可以使用 Ubuntu 的 DigitalOcean Droplet。為了這個示例,我使用 Google Cloud Compute 創建了運行 Ubuntu 的 VM。

neofetch

# 作業系統: Ubuntu 20.04.6 LTS x86_64
# CPU: Intel Xeon (2) @ 2.200GHz
# 記憶體: 3908MiB

一旦我們進入了我們的 VM,我們應該安裝 Docker 和 Docker Compose。Docker Compose 是選項,但它讓管理多容器應用程序變得更容易。

# 安裝 Docker 引擎和 Docker-Compose
sudo snap install docker

# 驗證安裝
docker --version
docker-compose --version

步驟 2: 配置並運行註冊表容器

接下來,我們需要配置我們的註冊表容器。以下 compose.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:
      # 挂载密碼文件
      - ./registry/registry.password:/auth/registry.password
      # 挂载數據目錄
      - ./registry/data:/data
    ports:
      - 5000

REGISTRY_AUTH_HTPASSWD_PATH defined 的密碼文件用於當用戶從註冊庫推送或拉取圖像時進行用戶驗證。我們應該使用 htpasswd 命令創建一個密碼文件。我們也應該創建一個用於存放圖像的文件夾。

mkdir -p ./registry/data

# 安裝 htpasswd
sudo apt install apache2-utils

# 創建密碼文件。用戶名: busy, 密碼: bee
htpasswd -Bbn busy bee > ./registry/registry.password

現在我們可以開始註冊庫容器。如果你看到這條消息,那麼一切都在正常工作:

docker-compose up

# 成功的運行應該輸出像這樣的内容:
# registry | level=info msg="listening on [::]:5000"

步驟 3:為處理 TLS 運行 NGINX

如前所述,我們可以利用 NGINX 來處理 TLS 並將請求转发到註冊庫容器。

Docker 註冊庫需要一個有效的可信 SSL 證書才能正常工作。你可以使用像 Let’s Encrypt 這樣的工具,或者手動獲得。確保你有一個指向您服務器的域名(在我這個例子中是 registry.pliutau.com)。對於這個示范,我已經使用 certbot 獲得了證書,並將其放在了 ./nginx/certs 目錄中。

因為我們正在容器中運行 Docker 註冊表,我們也可以通過在 compose.yaml 文件中添加以下服務來在容器中運行 NGINX:

services:
  registry:
    # ...
  nginx:
    image: nginx:latest
    depends_on:
      - registry
    volumes:
      # 掛载 nginx 配置
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      # 掛載從 Let's Encrypt 獲得的憑證
      - ./nginx/certs:/etc/nginx/certs
    ports:
      - "443:443"

我們的 nginx.conf 文件可能看起来像這樣:

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 / {
            # 對於大圖像的重要設定
            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;
        }
    }
}

準備好啦!

在這些步驟之後,我們可以運行我們的註冊表和 Nginx 容器。

docker-compose up

現在,在客戶端,您可以從您的註冊表推送和拉取圖像。但首先我們需要登錄到註冊表。

docker login registry.pliutau.com

# 用戶名:busy
# 密碼:bee
# 登錄成功

現在,是时候建立並將我們的圖像推送到我們自托管的註冊表了:

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

在您的服務器上,您可以在數據文件夾中查看上傳的圖像:

ls -la ./registry/data/docker/registry/v2/repositories/

其他選項

根據上面的示例,您也可以在 Kubernetes 上運行註冊表。或者,您可以使用像 Harbor 這樣的托管註冊表服務,這是一個開源註冊表,提供先進的安全功能,並與 Docker 和 Kubernetes 兼容。

亦して、もし自分用のホストされたレジストリにUIを持たせたい場合、joxit/docker-registry-uiのようなプロジェクトを使うことができ、別のコンテナ内で実行することができます。

結論

自ホストされたコンテナレジストリは、レジストリを完全にコントロールすることと、その実装方法を制御することができます。同時に、レジストリの保守とセキュリティの维护が必要です。

自ホストされたレジストリを運営する理由は何でもあまり、今までと同様に、どのような方法で行えばよいか比較することができ、ニーズに最も适合する方法を選ぶことができます。

このデモの完全なソースコードはGitHubにあります。また、または、YouTubeチャンネル上で動画で見ることもできます。