C4 Container図:実例で学ぶ完全ガイド
もしシステムのアーキテクチャ図を1枚だけ描くなら、コンテナ図にしてください。これはC4モデルのレベル2であり、実際には4つのレベルの中で最もよく使われるものです。なぜなら、エンジニアリングチームが実際に構築し、デプロイし、運用するもの、つまりWebアプリ、API、データベース、メッセージブローカーに直接対応するからです。
本ガイドは、優れたC4コンテナ図を作成するために必要なすべてを扱います。それが何か(そして何でないか — いいえ、C4のコンテナはDockerコンテナではありません)、何を含めるべきか、典型的なSaaSプロダクトの完全な実例、ほとんどのコンテナ図を台無しにする間違い、そして手作業またはコードベースからの生成によってコンテナ図を作成する方法です。
C4モデルがまったく初めての方は、まずC4モデルの完全ガイドから始めて、それからここに戻ってきてください。
C4 Container図とは?
コンテナ図は、Simon Brownが作成したC4モデルのレベル2です。これはSystem Context図であなたのシステムを表していた単一のボックスにズームインし、その内部の高レベルな技術的構成要素を明らかにします。
C4の用語では、コンテナとは、個別にデプロイまたは実行可能なあらゆるユニットです。コードを実行するかデータを保存するもので、独自のプロセス(または独自のストレージライフサイクル)で動作し、原理的にはシステムの他の部分から独立してデプロイできるものです。
この定義は次のようなものをカバーします。
- ユーザーのブラウザで動作するシングルページアプリケーション(React、Vue、Angular)
- サーバーサイドWebアプリケーション(Next.js、Rails、Django)
- モバイルアプリケーション(iOSアプリ、Androidアプリ)
- バックエンドAPIサービス(Go API、Node.jsサーバー、Spring Bootサービス)
- データベース(PostgreSQL、MongoDB、MySQL)
- キャッシュ(Redis、Memcached)
- メッセージブローカーまたはキュー(Kafka、RabbitMQ、SQS)
- バックグラウンドワーカーまたはスケジュールされたジョブプロセス
- ファイルまたはBLOBストア(S3バケット、MinIO)
- サーバーレス関数(AWS Lambda、Cloud Functions)
判断基準はシンプルです。それは独自のプロセスで動作するか、独自のデータを保持するか? 1つのバイナリにコンパイルされた2つのGoパッケージは、同じコンテナに属します。独立してデプロイされる2つのサービスは、たとえリポジトリを共有していても、2つのコンテナです。
簡潔な参照定義については、用語集のコンテナ図の項目をご覧ください。
C4のコンテナはDockerコンテナではない
これは最もよくある混乱のポイントなので、明示的に決着をつけましょう。
C4モデルはDockerの主流採用よりも前に生まれており、C4における「コンテナ」という言葉はもっと広い意味を持ちます。システムのランタイムレベルの構成要素です。Dockerとの重なりは偶然かつ部分的なものです。
- C4コンテナはDockerコンテナの内部で動作するかもしれません。あなたのGo APIはおそらくそうでしょう。
- C4コンテナは、素のOSプロセス、ブラウザのタブ、モバイルアプリ、マネージドなクラウドサービスとして動作するかもしれません。それらのどれもDockerコンテナではありません。
- 1つのDockerコンテナが複数のC4コンテナをホストすることさえあり得ます(開発用イメージのアプリと組み込みデータベースなど)。これは珍しいことですが。
別の言い方をすれば、Dockerコンテナはパッケージングとデプロイの技術です。C4コンテナはアーキテクチャの抽象化です。Chrome上で動作するReactのSPAはC4コンテナであり、Dockerコンテナになることは決してありません。RDSのPostgreSQLインスタンスはC4コンテナであり、Dockerはどこにも見当たりません。
C4図でボックスに「コンテナ」とラベルを付けるとき、あなたは「これは私のシステムの個別に実行またはデプロイ可能な部分だ」と言っているのです。それ以上でも以下でもありません。
コンテナ図に含めるべきもの
優れたコンテナ図は、ちょうど3つのカテゴリの情報を示します。
1. コンテナそのもの
システム境界内のすべてのデプロイ可能または実行可能なユニットで、それぞれに名前、責務、そして技術選択がラベル付けされています。「Order Service (Go)」「Session Cache (Redis)」「Web App (React SPA)」。技術ラベルは飾りではありません。それは図の価値の半分です。新しいエンジニアやプラットフォームチームが、12個のリポジトリを開かずにシステムを理解できるようにするものです。
2. 関係とプロトコル
コンテナ間の矢印で、それぞれ何がどう流れるかがラベル付けされています。「注文を読み書きする (SQL)」「イベントを発行する (AMQP)」「APIコールを行う (HTTPS/JSON)」。通信プロトコルはこのレベルで重要です。なぜなら、それが運用上の懸念事項を左右するからです。ネットワークポリシー、レイテンシ予算、リトライのセマンティクス、障害モードなどです。
3. 直近のコンテキスト
コンテキスト図に登場したユーザーと外部システムを、リクエストがどうシステムに入り、出ていくかを読者が見られるよう、端に残しておきます。詳細に再ドキュメント化するのではなく、それらはアンカーです。
この図は誰のためのものか?
コンテナ図のオーディエンスは技術者です。チームに加わる開発者、構造的な決定を行うアーキテクト、そしてデプロイ、監視、キャパシティを計画する運用/プラットフォームエンジニアです。これは「この2つのサービスはデータベースを共有すべきか?」や「Redisが落ちたら何が壊れるか?」といった会話が実際に起きるレベルです。技術に明るくないステークホルダーは、代わりにコンテキスト図を見るべきです。
含めるべきでないもの
- 内部のモジュール、クラス、パッケージ — それらはコンポーネント図(レベル3)に存在します
- ロードバランサー、VPC、Kubernetesノードといったインフラの詳細 — それらはデプロイメント図に属します
- すべての細かな相互作用 — アーキテクチャ上意味のない関係は除外する
コンテナ図の実例:SaaS Webプロダクト
架空のSaaSプロダクト、Webベースの請求書ツール「InvoiceHub」の完全なコンテナ図の例を構築してみましょう。この形(SPA + API + データベース + キャッシュ + ワーカー + キュー)は、現実世界のWebプロダクトの大きな割合を記述するので、おそらくそのまま応用できるでしょう。
コンテナ
| コンテナ | 技術 | 責務 |
|---|---|---|
| Web Application | React SPA | 顧客が請求書を作成・送信するために使うUI |
| API Application | Go (Fiber) | ビジネスロジック、認証、SPAが利用するREST API |
| Database | PostgreSQL | アカウント、請求書、支払いの記録システム |
| Cache | Redis | セッションストレージと請求書サマリのホットパスキャッシュ |
| Message Queue | RabbitMQ | 遅い処理(PDFレンダリング、メール)をAPIリクエストから切り離す |
| Background Worker | Go | キューメッセージを消費:PDFレンダリング、メール送信、支払いステータス同期 |
関係
[Customer] --> [Web Application (React SPA)] : Uses (HTTPS)
[Web Application] --> [API Application (Go)] : Makes API calls (HTTPS/JSON)
[API Application] --> [Database (PostgreSQL)] : Reads/writes invoices and accounts (SQL/TCP)
[API Application] --> [Cache (Redis)] : Reads/writes sessions and cached summaries (RESP)
[API Application] --> [Message Queue (RabbitMQ)] : Publishes invoice.created, email.requested (AMQP)
[Background Worker (Go)] --> [Message Queue] : Consumes jobs (AMQP)
[Background Worker] --> [Database (PostgreSQL)] : Updates job and payment status (SQL/TCP)
[Background Worker] --> [Email Service (SendGrid)] : Sends invoice emails (HTTPS/REST)
[API Application] --> [Payment Gateway (Stripe)] : Creates payment links, receives webhooks (HTTPS/REST)
この図が教えてくれること
そのリストを読み返して、いかに多くの具体的なエンジニアリングの問いに答えているかに注目してください。
- 状態はどこに存在するか? 2か所:PostgreSQL(永続的)とRedis(一時的)。セッションがRedisの再起動を生き延びるかどうかを議論したことがあるなら、図はその問いを可視化します。
- 障害の影響範囲は? ワーカーとAPIはデータベースを共有しています。RabbitMQがダウンしても請求書は作成され続けますが、メールはキューに溜まります。これは設計どおりです。
- 信頼境界は何か? SPAは信頼できないクライアントデバイスで動作します。SPAができるすべてはAPIの認証を通ります。
- 運用に必要なものは? 6つで、それぞれのプロトコル付き。それがあなたの監視チェックリストであり、だいたいあなたのdocker-composeファイルです。
新しい開発者はこれを2分で吸収できます。それがC4モデルのレベル2の全目的です。
コンテナ図でよくある間違い
ほとんどのコンテナ図は、いくつかの予測可能な形のいずれかで失敗します。
コンテナとコンポーネントの混同
コンテナ図に「OrderController」「InvoiceRepository」「AuthMiddleware」が示されているなら、1つ深いレベルにズームインしすぎています。それらはコンポーネント、つまりコンテナの内部の内部構成要素であり、レベル3のコンポーネント図に属します。判断基準:それは単独でデプロイまたは実行できるか?リポジトリクラスはできません。各図を1つのズームレベルに保ってください。レベルの混在は、判読不能な図を作る最速の方法です。
データストアの省略
チームはしばしば、自分でコードを書いたものだけを描き、データベース、キャッシュ、キューもコンテナであることを忘れます。データストアのないコンテナ図は、まさにアーキテクトと運用エンジニアが最も必要とする情報を隠してしまいます。状態がどこに存在するか、何が共有されているか、何が単一障害点か。システムがPostgreSQL、Redis、S3を使うなら、3つとも図に載せます。
ランタイム構造の代わりにデプロイメントを描く
コンテナ図はインフラ図ではありません。ロードバランサー、Kubernetesポッド、オートスケーリンググループ、アベイラビリティゾーン、レプリカ数はデプロイメントの懸念事項です。C4にはそのための別個の補足的なデプロイメント図があります。コンテナ図は「論理的なランタイムの部品は何で、どう通信するか?」に答えるものであり、「いくつのインスタンスがどこで動くか?」ではありません。3つのレプリカを動かしているからといって3つの同一の「API」ボックスを描くのは、情報ではなくノイズを加えます。
ラベルのない、または曖昧な関係
ただ「uses」と書いてあるだけの矢印は、図の潜在能力を無駄にします。「APIコールを行う (HTTPS/JSON)」「注文イベントを発行する (AMQP)」「セッションを読み書きする (RESP)」 — 動詞とプロトコルが、絵をドキュメントに変えます。
腐らせる
最も有害な間違いは、図そのものにはありません。18ヶ月前に描かれ、その後4つのサービスに分割したモノリスをいまだに示しているコンテナ図は、すべての新しい読者を積極的に誤解させます。陳腐化したアーキテクチャドキュメントは、何もないより悪いのです。だからこそ、図をコードと同期させ続けることが、見た目がどれほど美しいかよりも重要なのです。
コンテナ図の作り方
手作業で
しっかりしたコンテナ図は1時間以内に構築できます。
- コンテキスト図から始める。 ユーザーと外部システムを端に保つ。
- デプロイ可能なユニットを列挙する。 リポジトリ、docker-composeファイル、クラウドコンソールを確認する。独自のプロセスとして動作するか、データを保存するものはすべて候補です。
- データストアを明示的に追加する。 データベース、キャッシュ、キュー、BLOBストレージ。
- 関係を描く。 通信するコンテナのペアごとに、動詞句とプロトコルを付けた矢印を追加する。
- 技術をラベル付けする。 すべてのボックスに名前と技術を。
- チームでレビューする。 これが引き起こす議論(「待って、ワーカーがStripeと直接話してる?」)は、たいてい図そのものよりも価値があります。
どんなツールでも構いません。Structurizr、C4拡張付きのPlantUML、draw.io、ホワイトボードでさえ。表記法は、内容と最新に保つ規律よりはるかに重要ではありません。
Archylで
手作業のアプローチには1つの構造的な弱点があります。それはスナップショットを捉えるのであって、ソフトウェアはじっとしていません。Archylはコンテナ図に逆方向から取り組みます。コードからモデルを導出するのです。
- コードベースからのAIディスカバリ。 リポジトリを接続すると、ArchylのAIディスカバリがコード構造、設定、依存関係マニフェストを分析し、C4モデルの草案を提案します。システム、コンテナ、コンポーネント、そしてそれらの間の関係です。記憶からボックスを描くのではなく、提案をレビューして承認します。
- ドリフト検知が正直さを保つ。 モデルが存在すると、Archylはドキュメント化されたコンテナをコードベースが実際に示すものと継続的に比較し、ドリフトスコアを表示します。誰かがサービスを分割したりRabbitMQをKafkaに置き換えたりすると、6ヶ月後の混乱したオンボーディングセッションからではなく、ダッシュボードから気づけます。
- Architecture as Code。 テキストが好みですか?完全なC4モデル(コンテナ、技術、関係)をYAMLで定義し、コードと一緒にバージョン管理し、Archylにインタラクティブな図をレンダリングさせることができます。図の変更は、他のすべてと同様にプルリクエストを通ります。
いずれにせよ、目標は同じです。今日正確で、かつ来四半期も正確なコンテナ図です。
FAQ
C4のコンテナはDockerコンテナと同じですか?
いいえ。C4のコンテナはアーキテクチャの抽象化です。Webアプリ、API、データベース、メッセージブローカーなど、システムの個別にデプロイまたは実行可能なあらゆるユニットです。Dockerコンテナはパッケージング技術です。多くのC4コンテナはたまたまDockerコンテナとしてデプロイされますが、そうでないものもたくさんあります。React SPAはブラウザで動き、モバイルアプリは電話で動き、マネージドデータベースはクラウドサービスとして動きます。名前の共有は歴史の不運な偶然です。
C4モデルのレベル2とは何ですか?
C4モデルのレベル2はコンテナ図です。1つのソフトウェアシステム(レベル1のコンテキスト図の単一のボックス)にズームインし、その内部のデプロイ/実行可能なユニット、その技術選択、そして通信に使うプロトコルを示します。コンテキスト図(レベル1)とコンポーネント図(レベル3)の間に位置します。
コンテナ図にはコンテナがいくつあるべきですか?
厳密なルールはありませんが、15〜20のコンテナを超えると読みやすさが急速に低下します。システムが本当にそれ以上を持つなら、ビューを分割してください。サブシステムごとに1つのコンテナ図にするか、関連するコンテナを視覚的にグループ化します。数百もあるなら、おそらく複数のシステムをドキュメント化しており、コンテキストレベルでリンクされた別個のC4モデルが必要です。
マイクロサービスはそれぞれ別個のコンテナにすべきですか?
はい — 定義上そうです。個別にデプロイ可能な各サービスは、それ自体のコンテナであり、データベース・パー・サービスに従うなら各サービスのデータベースも同様です。これは有用な臭いのテストでもあります。「マイクロサービス」が、プロセスを共有していたり独立してデプロイできなかったりするために別個のコンテナとして描けないなら、それは分散モノリスかもしれません。
コンテナ図を描く代わりに生成する準備はできましたか?Archylを無料で試して、数分でコードベースからC4モデルを手に入れましょう。C4シリーズを探索し続けてください:C4モデルとは?完全ガイド | C4 System Context図ガイド | C4コンポーネント図ガイド。