コンテナーベースのテスト環境の扱いは複雑で、Docker-in-Docker (DinD) を活用する場合は特に難しいと言われています。このブログ記事では、Testcontainers Cloud がコンテナーベースのテスト方法をどのように革新し、新たな選択肢として注目されているのか、その理由をご紹介します。
Docker-in-Docker とは
Docker-in-Docker を使用すると、Docker コンテナー内で Docker を実行できます。これは、「マトリョーシカ (入れ子人形)」のようなもので、Docker コンテナー内で実行される Docker デーモンで、他のコンテナーをビルドして実行できます。
Docker-in-Docker の仕組み
- 入れ子になった Docker デーモン: 一般的な Docker セットアップでは、Docker デーモンはホスト マシン上で実行され、ホストのオペレーティング システム上でコンテナーを直接管理します。 DinD では、コンテナー内で Docker デーモンを起動します。 この内部の Docker デーモンは独立して動作し、コンテナーが独自のコンテナー セットを構築および管理できるようにします。
- 特権モードとホストリソースへのアクセス: Docker コンテナー内で Docker を実行するには、コンテナーに昇格された権限が必要です。これは、
--privileged
フラグを使用してコンテナーを特権モードで実行することで実現します。
1 | docker run --privileged -d docker:dind |
--privileged
フラグは、デバイス ファイルへのアクセスやシステム管理タスクを実行する機能など、ホスト マシンのほぼすべての機能をコンテナーに付与します。この設定により、内部の Docker デーモンが機能できるようになりますが、コンテナーがホスト システムに悪影響を与える可能性があるため、重大なセキュリティ リスクが生じます。
- ファイル システムに関する考慮事項: 内部の Docker デーモンは、イメージとコンテナーを DinD コンテナーのファイル システム内 (通常は
/var/lib/docker
未満) に格納します。 Docker はコピーオンライトレイヤーなどの高度なファイル システム機能を使用するため、コンテナー化されたファイル システム内で内部 Docker デーモン (それ自体がそのような機能を使用する場合があります) を実行すると、複雑な相互作用や潜在的な競合が発生する可能性があります。 - cgroups と名前空間の分離: Docker は、リソースの分離と管理のために cgroups や名前空間などの Linux カーネル機能に依存しています。コンテナー内で Docker を実行する場合、ネストを許可するには、これらの機能を正しく設定する必要があります。このプロセスにより、リソースの制限と分離が期待どおりに動作するようになるため、複雑さが増す可能性があります。
Docker-in-Docker を使用する理由
- 分離されたビルド環境: DinD では、各継続的インテグレーション (CI) ジョブをクリーンで分離された Docker 環境で実行できるため、ビルドとテストが前のジョブや同時に実行されている他のジョブの残留状態の影響を受けないようにします。
- 環境間の一貫性: Docker デーモンをコンテナー内にカプセル化することで、ローカル開発から CI/CD システムまで、開発パイプラインのさまざまな段階で同じ Docker 環境を複製できます。
DinD の課題
DinD にはメリットがありますが、次のような大きな課題も生じます。
- セキュリティ リスク:コンテナーを特権モードで実行すると、コンテナーがホスト リソースに広範囲にアクセスできるようになるため、ホスト システムがセキュリティの脆弱性にさらされる可能性があります。
- 安定性の問題: 入れ子になったコンテナーは、ストレージ ドライバーの競合やその他の不安定さの問題を引き起こし、予期しないビルド エラーを引き起こす可能性があります。
- 複雑なデバッグ: 入れ子になった Docker 環境での問題のトラブルシューティングは、抽象化と分離の複数のレイヤーが関与するため、複雑になる可能性があります。
現実世界の課題
Docker-in-Docker は魅力的に聞こえるかもしれませんが、解決できる数よりも多くの問題を引き起こします。これらの課題について解決策を紹介する前に、Testcontainers と最新のテスト手法におけるその役割について簡単に説明します。
Testcontainers とは
Testcontainers は、一般的なデータベース、Web ブラウザー、または Docker コンテナーで実行できる軽量で使い捨てのインスタンスを提供し、統合テストをサポートする人気のオープンソース ライブラリです。これにより、モックやスタブに頼るのではなく、外部リソースの実際のインスタンスと対話するテストを記述できます。
Testcontainers の主な機能
- 現実的なテスト環境: コンテナー内の実際のサービスを使用することで、テストの信頼性が向上し、実際のシナリオにより近づきます。
- 分離: 各テスト セッション、または各テストをクリーンな環境で実行できるため、共有状態による不安定さが軽減されます。
- 簡単な破棄:コンテナーは一時的であり、テスト後に自動的に破棄されるため、リソースの漏れを防ぎます。
Docker デーモンへの依存
Testcontainers の機能の中核となるコンポーネントは、 Docker デーモンとの相互作用にあります。 Testcontainers は、テストの必要に応じてコンテナーを開始および停止することで、Docker リソースを調整します。この統合は、テストが実行される場所に関係なく、Docker 環境へのアクセスが不可欠であることを意味します。
CI の Testcontainers を使用した DinD の課題
CI/CD パイプラインに Testcontainers ベースの統合テストを含めようとすると、CI 環境内で Docker にアクセスできなければいけないという課題に直面することがあります。Testcontainers はDocker デーモンとの通信が必要なため、CI ジョブ内で Docker 環境をエミュレートするために Docker-in-Docker を使用しています。
しかし、このアプローチでは Testcontainers の使用を組織全体に拡大しようとすると、大きな課題が生じます。
ケーススタディ~ CI パイプラインの悪夢
Docker では、統合テストに Testcontainers を利用する Jenkins CI パイプラインがありました。必要な Docker 環境を提供するために、DinD を実装し、最初はうまくいっているように見えましたが、すぐに次のことに遭遇しました。
- 不安定なビルド: ストレージ ドライバーの競合と入れ子になったコンテナー レイヤーの問題によるランダムなエラーが発生しました。入れ子になった Docker 環境がホストと衝突することがあり、予期しない動作を引き起こしていました。
- セキュリティ上の懸念: 特権モードでコンテナーを実行すると、セキュリティ監査中に危険信号が発生しました。DinD を正しく機能させるには特権モードが必要なため、重大なセキュリティ リスクが発生し、コンテナーがホスト システムにアクセスできる可能性があります。
- パフォーマンスのボトルネック: ビルドが遅く、リソースの消費が多くありました。Docker 内で Docker を実行するオーバーヘッドにより、フィードバック ループが長くなり、開発者の生産性が妨げられていました。
- 複雑なデバッグ: 入れ子になった コンテナーのトラブルシューティングに時間がかかりました。 ログとエラーは、コンテナーの複数のレイヤーを通じて追跡するのが困難であり、問題解決を困難にしていました。
これらの問題を解決するために数え切れないほどの時間を費やし、まるでモグラたたきのゲームをしているように感じました。
Testcontainers Cloud がより良い選択である理由
Testcontainers Cloud は、コンテナーベースのテストを簡素化、強化するために設計されたクラウドベースのサービスです。コンテナーの実行をクラウドにオフロードすることで、統合テストのための安全でスケーラブルで効率的な環境を提供します。
TestContainers Cloud が DinD の欠点にどのように対処するか
セキュリティの強化
- 特権モードは不要: コンテナーを特権モードで実行する必要がなくなり、攻撃対象領域が縮小します。
- 分離: テストは分離されたクラウド環境で実行され、ホスト システムへのリスクを最小限に抑えます。
- コンプライアンスに配慮: Docker ソケットを公開したり、昇格された権限を付与したりすることなく、セキュリティ監査に合格しやすくなります。
パフォーマンスの向上
- スケーラビリティ: クラウド リソースを活用して、テストをより高速に実行し、より高い負荷を処理します。
- リソース効率: 実行の負荷を軽減すると、ローカル リソースと CI/CD リソースが解放されます。
シンプルな構成
- プラグアンドプレイ統合: ローカルの Docker から Testcontainers Cloud に切り替えるために必要な変更は最小限です。
- 複雑さがない: 入れ子になった Docker デーモンの複雑さと落とし穴を避けます。
可観測性とデバッグ性の向上
- 詳細ログ:Testcontainers Cloud ダッシュボードから包括的なログにアクセスします。
- リアルタイム監視: コンテナーとリソースをリアルタイムで監視し、可視性を高めます。
Testcontainers Cloud の使用を開始する
Testcontainers Cloud を最大限に活用する方法を詳しく見ていきましょう。
Testcontainers Cloud に切り替えると、ローカルの Docker デーモンを必要とせずにテストを実行できます。
- ローカルの Docker は不要: Testcontainers Cloud は、クラウドでのコンテナーの実行を処理します。
- 一貫性のある環境: 異なるコンピュータ間でも同じ環境でテストを実行します。
さらに、Testcontainers Cloud を CI パイプラインに簡単に統合して、CI インフラストラクチャをスケーリングすることなく同じテストを実行できます。
GitHub Actions での Testcontainers Cloud の使用
ここでは、GitHub Actions ワークフローで Testcontainers Cloud を設定する方法をご紹介します。
1. 新しいサービス アカウントを作成する
- Testcontainers Cloud ダッシュボードにログイン
- [Service Accounts] に移動
- CI 環境専用の新しいサービス アカウントを作成
- アクセス トークンを生成
- アクセス トークンをコピー (一度しか表示できないため、安全に保管してください)
2. TC_CLOUD_TOKEN
環境変数を設定
- GitHub Actions で、次の操作を実行
- リポジトリの [設定] > [シークレットと変数] > [アクション] に移動
TC_CLOUD_TOKEN
という名前の新しいリポジトリ シークレットを追加し、アクセス トークンを貼り付ける
3. Testcontainers Cloud をワークフローに追加する
GitHub Actions ワークフロー (.github/workflows/ci.yml
) を更新して、Testcontainers Cloud のセットアップを含めます。
ワークフローの例:
123456789101112131415161718192021222324252627282930 | name: CI Pipeline on: push: branches: [ main ] pull_request: branches: [ main ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 # ... other preparation steps (dependencies, compilation, etc.) ... - name: Set up Java uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '17' - name: Setup Testcontainers Cloud Client uses: atomicjar/testcontainers-cloud-setup-action@v1 with: token: ${{ secrets.TC_CLOUD_TOKEN }} # ... steps to execute your tests ... - name: Run Tests run: ./mvnw test |
筆記:
atomicjar/testcontainers-cloud-setup-action
GitHub アクションは、CI 環境での Testcontainers Cloud Agent のインストールと認証を自動化します。- GitHub の暗号化されたシークレットを使用して、
TC_CLOUD_TOKEN
が安全に保たれていることを確認します。
コンポーネントの明確化: Testcontainers Cloud Agent と Testcontainers Cloud
コンポーネントを明確にするために:
- Testcontainers Cloud Agent (CI 環境の CLI): GitHub Actions などの CI 環境では、Testcontainers Cloud Agent (GitHub Action またはコマンドラインからインストール) を使用して CI ジョブを Testcontainers Cloud に接続します。
- Testcontainers Cloud: コンテナーを実行するクラウド サービスで、CI 環境からの実行をオフロードします。
CI 環境の場合:
- CI ジョブ内で Testcontainers Cloud Agent (CLI) を使用します。
TC_CLOUD_TOKEN
を使用して認証します。- CI 環境で実行されるテストは、Testcontainers Cloud を使用します。
監視とデバッグ
Testcontainers Cloud ダッシュボードを活用します。
- セッション ログ: 個々のテスト セッションのログを表示します。
- コンテナーの詳細: コンテナーのステータスとリソースの使用状況を検査します。
- デバッグ: トラブルシューティングのためにコンテナーのログと出力にアクセスします。
DinD よりも Testcontainers Cloud が好まれる理由
現実世界への影響
Testcontainers Cloud を統合した後、次のことが確認できました。
- ビルド時間の短縮: リソース使用率が最適化されているため、テストの実行速度が大幅に向上しました。
- メンテナンスの削減: CI パイプラインの問題のデバッグと修正に費やす時間を短縮しました。
- セキュリティの強化: 特権モードの必要性を排除し、セキュリティ監査を満たしました。
- 可観測性の向上: ログ記録と監視機能が向上しました。
一般的な懸念事項への対処
セキュリティとコンプライアンス
- データの分離: 各テストは分離された環境で実行します。
- 暗号化通信:安全にデータ伝送します。
- コンプライアンス: 業界標準のセキュリティ プラクティスに準拠します。
コストに関する考慮事項
- 効率の向上: メンテナンスにかかる時間が節約され、コストが相殺されます。
- リソースの最適化: 高価な CI インフラストラクチャの必要性が減ります。
互換性
- 多言語サポート: Java、Node.js、 Python、Go、.NET など。
- シームレスな統合:既存のテスト コードに必要な最小限の変更。
まとめ
Testcontainers Cloud Agent を活用して Testcontainers Cloud に切り替えたことは、Docker 社のチームだけでなく他組織の開発者にとってもゲームチェンジャーとなりました。Docker-in-Docker に関連する主要な問題点に対処し、安全で効率的、かつ開発者にとって使いやすい代替手段を提供します。
- セキュリティ: 特権コンテナーや Docker ソケットの露出が不要になります。
- パフォーマンス: スケーラブルなクラウド リソースでテストの実行を高速化します。
- シンプルさ: 構成が簡素化され、メンテナンスのオーバーヘッドを削減します。
- 可観測性: 詳細なログと監視ツールでデバッグを強化します。
これらの課題に直面している方は、Testcontainers Cloud を試してみることをお勧めします。
エクセルソフトは Docker の Preferred Reseller として、Docker Business を販売しています。Docker 製品のライセンスや機能に関するご質問、製品デモのご要望を承っています。お問い合わせはこちらから。
*本記事は、Docker 社が提供している以下の記事から抜粋・転載したものです。
Testcontainers CloudがDocker-in-Dockerと比較してテストシナリオのゲームチェンジャーである理由
Docker の最新情報をお届けするエクセルソフトのメールニュース登録はこちら。