CI/CDでビルドしたDockerイメージを,どこに置いてVPSに配るか── これを解決するのがDockerレジストリだ.公開サービスもあるが,VPSに自前のプライベートレジストリを立てる選択肢を知っておくと,運用の自由度が大きく上がる.

自前レジストリがあれば,プライベートなイメージを自分の管理下で配布でき,外部サービスの制限やコストにも縛られない.CI/CDでビルドしたイメージをpushし,本番VPSがpullする── という現代的なデプロイの要になる.

この記事は,CI/CDでイメージを配布したい個人開発者・小規模チームに向けている.registryコンテナの構築から,HTTPS・認証・CI連携・イメージの掃除までを実践的に解説する.

読み終えたとき,あなたは自前のイメージ配布基盤を持ち,ビルドしたイメージを安全にpush/pullできるようになっている.

なぜ自前レジストリを立てるのか

Dockerイメージの配布には,イメージを保管するレジストリが要る.公開のレジストリサービスもあるが,プライベートなイメージの保管・転送量・容量・速度に制約やコストがかかることがある.

自前レジストリなら,自分のVPS内で完結する.CI/CDでビルドしたイメージを自前レジストリにpushし,本番VPSが同じネットワーク/近い場所からpullすれば,速くて制限のないデプロイができる.

またプライベートなコードを含むイメージを,自分の管理下に置ける安心感もある.外部サービスにイメージを預けたくない場合の選択肢になる.

ただし自前で運用する責任(HTTPS・認証・バックアップ・掃除)も負う.この記事ではそれらを安全に組む方法を示す.

レジストリの全体像 ― push と pull

Dockerレジストリは,イメージを保管し,push(アップロード)とpull(ダウンロード)を受け付けるサーバーだ.Docker公式のregistryイメージを使えば,VPS上に簡単に立てられる.

典型的なフローは,(1)CI/CDでイメージをビルド (2)自前レジストリにpush (3)本番VPSがpullしてデプロイだ.これにより「ビルド」と「実行」の場所を分離できる(イメージ最適化・CI/CDの記事も参照).

registryコンテナを立てる ― 最小構成

まずは基本のregistryコンテナを起動する.データ(イメージ)はvolumeに永続化するのを忘れずに(さもないとコンテナ再作成でイメージが消える).

registryの最小起動(compose)

services:
  registry:
    image: registry:2
    restart: always
    volumes:
      - registrydata:/var/lib/registry   # イメージを永続化
    # 直接公開せず,後段でNginxにHTTPS終端させる
    ports:
      - "127.0.0.1:5000:5000"
volumes:
  registrydata:

ポイントはレジストリ自体は127.0.0.1:5000でlocalhostバインドし,外部に直接晒さないことだ.次のステップで,前段のNginxにHTTPS終端と認証を担わせる.イメージデータはregistrydata volumeに永続化する.

HTTPSと認証 ― 公開レジストリを安全にする

Dockerはデフォルトで,HTTPSでないレジストリへのpush/pullを拒否する(insecure registryの例外設定はあるが非推奨).そのため,前段のNginxでHTTPS終端し,さらにBasic認証で保護する.

Nginxで前段にHTTPS+Basic認証

# Basic認証ファイルを作成(htpasswd)
# htpasswd -Bc /etc/nginx/registry.htpasswd myuser

server {
    listen 443 ssl;
    server_name registry.example.com;
    # ... Let's Encryptの証明書 ...
    client_max_body_size 0;     # 大きなイメージpushのため
    location / {
        auth_basic "Registry";
        auth_basic_user_file /etc/nginx/registry.htpasswd;
        proxy_pass http://127.0.0.1:5000;
        proxy_set_header Host $host;
    }
}

client_max_body_size 0は重要だ.イメージは大きいため,これを設定しないと大きなレイヤーのpushが413エラーで失敗する.Basic認証+HTTPSにより,認証した人だけが安全にpush/pullできる(SSL記事・リバースプロキシ記事も参照).

push と pull ― ログインして使う

レジストリができたら,docker loginで認証し,イメージにレジストリのホスト名を付けてpush/pullする.

ログイン・push・pull

# 認証
docker login registry.example.com
# イメージにレジストリ名をタグ付けしてpush
docker tag myapi registry.example.com/myapi:1.0
docker push registry.example.com/myapi:1.0
# 本番VPSでpull
docker pull registry.example.com/myapi:1.0

イメージ名の頭にレジストリのホスト名を付けるのがポイントだ(registry.example.com/myapi:1.0).これでDockerはどのレジストリにpush/pullするかを判断する.本番のcomposeでは,このフルネームでイメージを指定すれば,自前レジストリからpullしてデプロイできる.

CI/CD連携 ― ビルドしてpushを自動化

真価が出るのがCI/CDとの連携だ.GitHub Actions等でイメージをビルドし,自前レジストリにpush,本番VPSがpullする(CI/CDの記事も参照).

CIでビルド→自前レジストリへpush(概念)

# CI(GitHub Actions等)の中で
# 認証情報はSecretsから
docker login registry.example.com -u $REG_USER -p $REG_PASS
docker build -t registry.example.com/myapi:$GITHUB_SHA .
docker push registry.example.com/myapi:$GITHUB_SHA
# 本番VPSでは pull して up -d

認証情報は必ずCIのSecretsに置き,ログに出さない(シークレット管理の記事参照).コミットハッシュ($GITHUB_SHA)をタグにすると,どのコミットのイメージかが明確になり,問題時に特定のバージョンへ戻すのも容易になる.

イメージの掃除 ― ストレージを溢れさせない

レジストリは放置すると古いイメージでディスクを食い尽くす.CI/CDで毎回pushすると,タグの数がどんどん増える.不要なイメージを定期的に掃除(ガベージコレクション)する.

レジストリのガベージコレクション

# 不要なタグを削除した後,GCで実体を回収
docker exec registry bin/registry garbage-collect 
  /etc/docker/registry/config.yml

# 定期的にディスク使用量を確認
docker system df

GCは「参照されなくなったレイヤーの実体を回収」する.運用では「最新数バージョンだけ残して古いタグを削除→GC」を定期化するとよい.加えてレジストリのvolume自体もバックアップ対象に含める(イメージは再ビルドできるが,再ビルドコストを考えると保管しておく価値がある).

補論:自前レジストリは「容量・速度・戻せる安心」のあるVPSで

自前レジストリは便利だが,イメージを保管する容量と,push/pullの速度,そして運用の安全性が前提になる.イメージは数百MB単位で積み上がるため,ディスク容量と速度が効く.

高速NVMe・50種類以上のOSテンプレートに対応した国内VPS─シン・VPS─ はNVMe SSDでイメージのpush/pull・GCが高速で,プラン選択で十分なストレージを確保できる.スナップショットでレジストリのvolumeごと退避できるため,レジストリの設定変更やアップグレードも安全に試せる.自前イメージ配布基盤の土台に向く.

レジストリはregistry.example.comのようなサブドメインで公開するのが一般的だ.取り扱い400種類以上のドメイン取得サービス─ムームードメイン─ で取得したドメインにサブドメインを切り,HTTPS+認証で保護すれば,安全な自前レジストリが完成する.

よくある質問(FAQ)

Q1.自前レジストリは個人開発でも要る?

必須ではないが,CI/CDでイメージを配布したい・プライベートイメージを自分の管理下に置きたい・外部サービスの制限を避けたい場合に有効だ.まず公開サービスで始め,必要を感じたら自前化するのもよい.

Q2.HTTPSは必須?

実質必須だ.DockerはHTTPSでないレジストリへのpush/pullを既定で拒否する.前段のNginxでHTTPS終端し,Basic認証も併せて設定するのが標準的な構成だ.

Q3.pushが413エラーで失敗する

前段Nginxのclient_max_body_size 0(無制限)を設定する.イメージのレイヤーは大きいため,既定の上限では弾かれる.

Q4.イメージのバージョン管理はどうする?

コミットハッシュやバージョン番号をタグにする(myapi:1.0myapi:$GITHUB_SHA).どのコードのイメージかが明確になり,問題時に特定バージョンへ戻せる.

Q5.ディスクが一杯になる

古いタグを削除してガベージコレクション(GC)を定期実行する.CI/CDで毎回pushするとタグが増えるため,「最新数世代だけ残す」運用を仕込む.

Q6.レジストリのバックアップは要る?

イメージは再ビルドできるが,再ビルドコストを考えるとvolumeのバックアップは有用だ.スナップショットや外部保管に含めておくと,復旧が速い.

まとめ ― 自前レジストリでデプロイの自由を得る

プライベートレジストリは,registryコンテナ+HTTPS+認証で構築でき,CI/CDからのpushと本番のpullを自分の管理下で回せる.イメージの掃除を仕込めば,ストレージも溢れない.

今日やるべきことは,registryコンテナをvolume付きで起動し,前段にHTTPS+Basic認証を組むこと.そして1つイメージをpush/pullしてみる.自前の配布基盤を持つ手応えが掴める.

イメージ配布を自分の手に握れば,デプロイの自由度が上がる.容量と速度のあるVPSなら,自前レジストリは個人開発の強力な武器になる.