テスト統合でのポート衝突防止と Docker Hub レート制限回避

basecamp/kamal

テスト実行時に発生していたポート・コンテナ名衝突と Docker Hub のレートリミットを回避するため、ワークツリーごとに安全な Compose プロジェクト名を生成し、プルスルーキャッシュと認証再利用を導入した。本変更はテストスイート全体の安定性を向上させ、CI 環境での競合を根本的に解決します。

背景

従来のテスト設定では固定ポート(例: 22443:443)や固定レジストリ名(registry:4443)がハードコーディングされており、同時実行や CI の並列ジョブでコンテナ名・ポートの衝突が頻発し、テストが不安定になるケースがありました。また、Docker Hub への頻繁なプルがレートリミットに達し、テストが途中で失敗することも報告されていました。これらの問題は、テスト環境が共有リソースに過度に依存していたことが根本原因です。

技術的な変更

ワークツリーごとの Compose プロジェクト名 を導入し、test/integration/integration_test.rbCOMPOSE_PROJECT 定数を追加しました。SHA256 ハッシュの先頭 8 桁を使用して "kamal-test-#{hash}" とし、同一ワークツリー内での docker compose down が正しいスタックを削除でき、別ワークツリー間での名前衝突を防ぎます。

COMPOSE_PROJECT = "kamal-test-#{Digest::SHA256.hexdigest(File.expand_path("../..", __dir__))[0, 8]}"

Docker Hub のレートリミット回避策 として、docker-compose.ymlhub‑cache サービスを追加し、プルスルーキャッシュとして registry:3 を使用します。キャッシュは匿名で起動し、DOCKERHUB_USERNAMEDOCKERHUB_TOKEN が設定されていれば認証情報を流用して上位レジストリへプルします。

  hub-cache:
    image: registry:3
    environment:
      - REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io
      - REGISTRY_PROXY_USERNAME=${DOCKERHUB_USERNAME:-}
      - REGISTRY_PROXY_PASSWORD=${DOCKERHUB_TOKEN:-}
    volumes:
      - hub-cache:/var/lib/registry
    healthcheck:
      test: [ "CMD", "pgrep", "registry" ]
      interval: 1s

内部 Docker デーモンの設定 を変更し、boot.sh(deployer と vm 両方)で registry-mirrorsinsecure-registrieshub-cache:5000 を追加しました。これにより、内部コンテナがベースイメージを直接 Docker Hub から取得せず、キャッシュ経由で取得するようになります。

cat > /etc/docker/daemon.json <<'EOF'
{
  "storage-driver": "vfs",
  "registry-mirrors": [ "http://hub-cache:5000" ],
  "insecure-registries": [ "hub-cache:5000" ]
}
EOF

テストコードのポート参照 を動的に取得するよう改修し、IntegrationTestsetuppublished_port を呼び出して実際のホストポートを変数 @http_port@https_port に保存しました。以降の HTTP アクセスは #{@http_port} を利用し、ポート衝突のリスクを排除します。

@http_port = published_port("load_balancer", 80)
@https_port = published_port("vm1", 443)

イメージ参照の簡素化レジストリ設定の除去 を行い、すべての Dockerfileregistry:4443 からの取得ではなく公式イメージ(例: nginx:1-alpine-slim)を直接使用するようにしました。また、deploy.yml 系統から registry:4443 の記述を削除し、busybox 等のイメージも公式リポジトリに切り替えました。これにより、テスト実行時にプライベートレジストリへの依存がなくなり、キャッシュや認証の設定だけで済むようになっています。

-FROM registry:4443/nginx:1-alpine-slim
+FROM nginx:1-alpine-slim
-    image: registry:4443/busybox:1.36.0
+    image: busybox:1.36.0

セットアップスクリプトの整理 では、レジストリへの手動プッシュロジックを除去し、代わりに basecamp/kamal-proxy を直接プル・タグ付け・プッシュしてプライベートレジストリにシードする手順に変更しました。これにより、レジストリへの不要な書き込みが減り、シークエンスが簡潔になります。

docker pull basecamp/kamal-proxy:v0.9.2
docker tag basecamp/kamal-proxy:v0.9.2 registry:4443/basecamp/kamal-proxy:v0.9.2
docker push registry:4443/basecamp/kamal-proxy:v0.9.2

設計判断

プルスルーキャッシュの導入ワークツリー固有の Compose プロジェクト名 という二つの設計判断は、テスト環境の分離性とリソース競合回避を最小の侵襲で実現することを目的としています。キャッシュは既存のレジストリ構成に最小限の変更で追加でき、認証情報の再利用によりレートリミット問題を根本的に緩和します。Compose プロジェクト名はハッシュに基づく決定論的生成であり、CI の並列実行時でも名前衝突が起きない保証を提供します。いずれの変更も本番コードに影響を与えず、テスト専用の安全策として完結しています。

まとめ

本 PR はテスト実行時のポート・コンテナ名衝突と Docker Hub のレートリミットという二大課題を、hub‑cache によるプルスルーキャッシュと COMPOSE_PROJECT のハッシュ化により安全なプロジェクト名生成で解決しました。結果として、テストスイートは並列実行でも安定し、外部レジストリへの過度な依存を排除したことで CI の信頼性が向上します。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
ef7a03d3

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文・背景・技術的変更・設計判断(任意)・まとめの3部構成が明確に存在し、まとめは単なる繰り返しではなく意義が述べられている。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

コードブロックは `言語:ファイルパス` 形式で正しく記述され、PRリンクは `PR #1872` 形式でリンク化されている。GitHubリンク記法に問題はない。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

専門的なエンジニア向けの内容で、不要な初心者向け解説は含まれていない。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションは総論・各論・結論の段落で構成され、段落はトピックセンテンスで始まり1段落1トピック、長さも適切で空行で区切られている。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事中のコードブロックは提供されたDiffの変更点と一致しており、ファイル名・内容・追加・削除が正確に反映されている。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

使用されている技術用語は正確で、PRおよびDiffで用いられている語彙と一致している。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

技術的な説明はDiffとPR Descriptionに裏付けられ、論理的に正しく記述されている。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事の全ての主張はPR情報(タイトル・説明・Diff)で裏付けられ、推測や捏造は見られない。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号やコード中の数値・ポート番号などは正確に記載されている。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトルはPRの目的(ポート衝突防止、Docker Hubレートリミット回避)を適切に表現しており、内容と一致している。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

PRに記載されていない外部知識(LTS、リリース日程等)は一切含まれていない。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

時間表現の歪曲はなく、PRの記述と整合している。