Docker Registry: 安全かつ効率的なプライベートレジストリのセルフホスト

Docker tutorial - IT technology blog
Docker tutorial - IT technology blog

プライベートDocker Registryの概要

Dockerを扱う際、私たちは頻繁にアプリケーションをビルドし、Dockerイメージとしてパッケージ化します。これらのイメージは、開発、ステージング、プロダクションなどの他の環境が簡単にプルして利用できるように保存される必要があります。

Docker Hubは一般的な公開レジストリであり、オープンソースまたはパブリックなイメージに最適です。しかし、内部アプリケーションを開発する場合、機密データを含む場合、またはイメージを外部と共有したくない場合、プライベートDocker Registryの使用が不可欠になります。プライベートレジストリは、Dockerイメージの保存と配布を完全に制御するのに役立ちます。

Dockerイメージ管理方法の比較

Dockerイメージを保存および管理するには、いくつかの主要な選択肢があります。

1. Docker Hub

利点:

  • 使いやすさ: 開始は非常に簡単で、ほとんどのDockerユーザーにとってデフォルトの選択肢です。
  • パブリックリポジトリは無料: 無制限の数のパブリックイメージを保存できます。
  • 大規模なコミュニティ: ベースイメージや一般的なライブラリを簡単に見つけることができます。

欠点:

  • プライベートリポジトリの制限: 有料プランでない場合、限られた数のプライベートリポジトリしか利用できません(現在1つ)。
  • レート制限: イメージのプル回数に制限があります。例えば、匿名ユーザーは6時間ごとに100回までで、特に無料ユーザーに影響します。
  • サードパーティへの依存: データの完全な制御権はありません。

2. クラウド上のコンテナレジストリサービス (AWS ECR, GCP GCR/Artifact Registry, Azure ACR)

利点:

  • マネージドサービス: クラウドプロバイダーがインフラ、スケーリング、セキュリティ、バックアップなど、あらゆる側面を管理します。
  • スケーラブル: 利用ニーズに応じて自動的に拡張します。
  • 深い統合: 他のクラウドサービス (CI/CD, Kubernetes) と密接に連携します。
  • 優れたセキュリティ: 通常、高度なセキュリティ機能が付属しています。

欠点:

  • コスト: 特に大量のデータを保存したり、アクセス量が多い場合は、かなり高額になることがあります。
  • ベンダーロックイン: クラウドプロバイダー間で移行したい場合、より困難になります。
  • プロバイダーへの依存: セルフホストのように完全に制御できるわけではありません。

3. プライベートDocker Registryのセルフホスト

利点:

  • 完全な制御: イメージデータを完全に所有し、制御できます。
  • 最大限のセキュリティ: 内部ネットワークやファイアウォールの背後でデプロイできます。これにより、最も厳しいセキュリティおよびコンプライアンス要件を満たすことができます。
  • 無制限: 容量とリポジトリの数は、ハードウェアとインフラにのみ依存します。
  • コスト最適化: 大規模な場合、セルフホストはクラウドサービスよりも安価になる可能性があります。

欠点:

  • 労力が必要: 設定、構成、メンテナンス、バックアップ、トラブルシューティングには時間と知識が必要です。
  • 知識要件: Docker、ネットワーク、セキュリティ、システム管理に関する知識が必要です。

プライベートDocker Registryをセルフホストすべきタイミングはいつか?

上記の分析に基づき、以下のケースでプライベートDocker Registryのセルフホストを検討することをお勧めします。

  • 高いセキュリティとコンプライアンス要件: 内部セキュリティや法的規制(GDPR、HIPAAなど)の理由により、イメージを公共サービスに保存できない場合。
  • データの絶対的な制御: イメージデータをどこに保存するか、誰がアクセスできるか、どのような方法でアクセスするかを完全に決定したい場合。
  • 大規模なコスト最適化: 大量のイメージと多数のプル/プッシュがある場合、既存のインフラでセルフホストすることで、クラウドサービスと比較して帯域幅とストレージコストを大幅に節約できます。
  • 内部/オフライン環境: インターネット接続のない内部ネットワークでレジストリを運用する必要がある場合、または同じデータセンター内のサーバー間で非常に高速なプル/プッシュ速度が必要な場合。

以前、私のチームには30以上のコンテナを実行するプロダクションクラスターがありました。当時、Docker Hubやクラウドレジストリからイメージをプルすることは、帯域幅と時間の両方でコストがかかりました。私はローカルサーバー上にプライベートレジストリをセルフホストすることを決めました。その結果、外部レジストリからインターネットを経由する場合と比較して、イメージのプル/プッシュにおけるリソース使用量を40%削減し、デプロイ速度を大幅に向上させることができました。これはシステムパフォーマンスに大きな違いをもたらしました。

安全なプライベートDocker Registryのデプロイガイド

次に、HTTPSセキュリティとユーザー認証を備えたプライベートDocker Registryをデプロイする手順を詳しく見ていきましょう。従いやすいように、各ステップを詳細にガイドします。

ステップ1: 環境の準備

Linuxサーバー(UbuntuまたはCentOSのいずれでも可)とDockerがインストールされている必要があります。サービスをより簡単に管理するために、Docker Composeの使用をお勧めします。

1.1. Dockerのインストール(まだの場合):


sudo apt update
sudo apt install apt-transport-https ca-certificates curl gnupg lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.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
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin

# sudoを使用せずにdockerグループにユーザーを追加
sudo usermod -aG docker $USER
newgrp docker

1.2. Docker Compose (v2) のインストール:

上記の指示に従ってDockerをインストールした場合、Docker Compose Plugin (v2) も同時にインストールされています。docker-composeではなく、docker compose(スペースあり)と入力するだけで済みます。

ステップ2: 基本的なDocker Registryの実行 (HTTP – 安全ではない)

まず、HTTP経由で基本的なRegistryを実行します。これはテストの最初のステップに過ぎず、セキュリティがないため本番環境では使用すべきではありません

2.1. データ保存ディレクトリの作成:

Registryはディスクにイメージを保存します。コンテナが停止または削除されてもデータが失われないように、ホスト上のディレクトリをコンテナにマウントすることをお勧めします


sudo mkdir -p /var/lib/registry

2.2. Registryコンテナの実行:


docker run -d -p 5000:5000 --restart=always --name registry -v /var/lib/registry:/var/lib/registry registry:2

このコマンドは、registry:2イメージ(Docker Registryの最も安定したバージョン)をプルし、ポート5000で実行し、ホストの/var/lib/registryディレクトリをコンテナ内にマウントします。

2.3. 不安全なレジストリを許可するためのDockerデーモン設定(テスト用のみ):

デフォルトでは、DockerデーモンはHTTPS接続のみを許可します。HTTPでテストするには、/etc/docker/daemon.jsonファイルを編集する必要があります。


sudo nano /etc/docker/daemon.json

以下のようにコンテンツを追加または編集してください(your_server_ip:5000をあなたのIPまたはドメインに置き換えてください):


{
  "insecure-registries": [
    "your_server_ip:5000"
  ]
}

その後、Dockerサービスを再起動します:


sudo systemctl restart docker

2.4. イメージのプッシュ/プルをテスト:


docker pull hello-world
docker tag hello-world your_server_ip:5000/hello-world
docker push your_server_ip:5000/hello-world
docker rmi your_server_ip:5000/hello-world hello-world # プルをテストするためにローカルイメージを削除
docker pull your_server_ip:5000/hello-world

すべてが機能すれば、hello-worldイメージが正常にプッシュおよびプルされたことがわかります。このステップのテストが完了したら、daemon.jsonからinsecure-registriesを削除し、Dockerを再起動することを忘れないでください。

ステップ3: HTTPSによるセキュリティ保護 (Nginx Reverse Proxy + Let’s Encrypt)

これは、プライベートレジストリのセキュリティを確保するために非常に重要なステップです。Nginxをリバースプロキシとして使用し、Let’s Encryptで無料のSSL証明書を発行します。

3.1. ドメインとDNSの準備:

ドメイン名(例: registry.yourdomain.com)を用意し、そのAレコード(またはCNAME)をサーバーのパブリックIPアドレスにポイントする必要があります。

3.2. 古いRegistryを停止し、Docker Composeを準備する:

古いregistryコンテナを停止し、削除します:


docker stop registry
docker rm registry

docker-compose.ymlファイルを作成します:


version: '3.8'

services:
  registry:
    image: registry:2
    volumes:
      - /var/lib/registry:/var/lib/registry
    environment:
      REGISTRY_HTTP_ADDR: 0.0.0.0:5000
    restart: always

注: ポート5000はもうホストの外部に公開しません。Nginxがその役割を果たします。

3.3. Nginxのインストール:


sudo apt update
sudo apt install nginx

3.4. CertbotのインストールとSSL証明書の取得 (Let’s Encrypt):


sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d registry.yourdomain.com

CertbotはNginxを自動的に設定し、証明書を更新します。

3.5. Nginxをリバースプロキシとして設定:

ドメインのNginx設定ファイルは/etc/nginx/sites-available/registry.yourdomain.com(または類似)にあり、Certbotによって既に作成されています。必要に応じて確認および編集し、レジストリコンテナのポート5000へのリクエストを転送していることを確認してください。

基本的な設定は以下のようになります(CertbotがSSL部分を自動的に追加します):


server {
    listen 80;
    listen [::]:80;
    server_name registry.yourdomain.com;

    location / {
        # HTTPからHTTPSへのリダイレクト
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name registry.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/registry.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/registry.yourdomain.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    client_max_body_size 0; # 大容量イメージのアップロードを許可

    location / {
        proxy_pass http://localhost:5000;
        proxy_set_header Host $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 900s; # 大規模なプッシュ/プル操作のタイムアウトを延長

        # Docker Registryに必要なヘッダーを強制
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_buffering off;
        chunked_transfer_encoding on;
    }
}

Nginxの設定を確認し、再起動します:


sudo nginx -t
sudo systemctl restart nginx

3.6. Docker ComposeでRegistryを実行:

docker-compose.ymlファイルがあるディレクトリに移動し、以下を実行します:


docker compose up -d

これで、RegistryはHTTPS経由で実行されます。再度プッシュ/プルをテストできます。今回はあなたのドメインを使用し、--insecure-registryは不要です。


docker pull hello-world
docker tag hello-world registry.yourdomain.com/hello-world
docker push registry.yourdomain.com/hello-world

ステップ4: ユーザー認証の追加 (Basic Authentication)

不正アクセスを防ぐために、RegistryにBasic認証を追加します。

4.1. apache2-utilsのインストール (htpasswdを使用するため):


sudo apt install apache2-utils

4.2. htpasswdファイルの作成:

ユーザー情報とパスワードを含むファイルを作成します(例: /etc/nginx/conf.d/registry.password)。最初に作成する場合は-cを使用し、以降は新しいユーザーを追加する場合は-cを省略します。


sudo htpasswd -c /etc/nginx/conf.d/registry.password your_username

プロンプトが表示されたらパスワードを入力します。

4.3. 認証を要求するようにNginxを設定:

Registry用のNginx設定ファイル(/etc/nginx/sites-available/registry.yourdomain.com)を編集し、HTTPSサーバーブロック内のlocation / {}ブロックに次の2行を追加します:


    auth_basic "Registry Restricted";
    auth_basic_user_file /etc/nginx/conf.d/registry.password;

その後、Nginxの設定を確認し、再起動します:


sudo nginx -t
sudo systemctl restart nginx

4.4. Registryへのログイン:

これで、プッシュ/プルする際にDockerはログインを要求します:


docker login registry.yourdomain.com

htpasswdで作成したユーザー名とパスワードを入力します。ログインに成功すると、通常通りイメージをプッシュ/プルできます。

ステップ5: ストレージの管理 (Persistent Volume)

ステップ2で/var/lib/registryボリュームを設定しました。このディレクトリに十分な容量があり、定期的にバックアップされていることを確認することが重要です。VPS上で実行している場合、このボリュームが耐久性の高いリカバリ可能なディスクにマウントされていることを確認してください。

ステップ6: 最適化とメンテナンス

Registryのセルフホストは、単なるインストールだけでなく、定期的なメンテナンスも含まれます:

  • Garbage Collection: Registryからイメージを削除しても、そのレイヤーはディスク上に残ります。容量を解放するには、ガーベージコレクションコマンドを実行する必要があります。ただし、このコマンドを実行する際は、プッシュ/プル操作が実行されていないことを確認してください

docker compose stop registry
docker run --rm -v /var/lib/registry:/var/lib/registry registry:2 garbage-collect /etc/docker/registry/config.yml
docker compose start registry

Registryのデフォルト設定を使用していない場合、設定ファイルをマウントする必要があるかもしれません。

  • ネットワークアクセスの制限: ファイアウォール(UFW、firewalld)を使用して、特定のIPまたはIP範囲のみがRegistryのポート443にアクセスできるようにします。
  • バックアップ: /var/lib/registryディレクトリの定期的なバックアップ計画を設定し、データ損失を防ぎます。

結論

プライベートDocker Registryをセルフホストすることで、Dockerイメージに対する柔軟性、セキュリティ、および高度な制御が得られます。セットアップと構成には多少の初期労力が必要ですが、この詳細なガイドがあれば、安全で効率的なRegistryをうまくデプロイできると確信しています。これは、情報セキュリティ、インフラストラクチャの最適化、およびアプリケーションライフサイクルの完全な制御が必要なプロジェクトにとって最適なソリューションです。

Share: