実践Dockerネットワーキング:Bridge、Host、Overlayはいつ使うべきか?

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

「Connection Refused」の悪夢からDocker Networkをマスターするまで

初めてマイクロサービスシステムをステージングサーバーにデプロイした日のことを、今でも鮮明に覚えています。ローカルではdocker-compose upですべてが完璧に動作していました。フロントエンド(React)はバックエンド(Node.js)をスムーズに呼び出し、バックエンドはデータベース(Postgres)やRedisとまるで身内のように対話できていました。しかし、サーバーに上げたとたん、悪夢が始まったのです。フロントエンドがバックエンドに全く接続できない。画面には「Connection Refused」のエラーが赤々と表示されていました。

原因究明に半日近くを費やしました。サーバーからコンテナのIPアドレスへpingは通るのに、コンテナ間でのサービス名(例:http://backend-api:3000)による呼び出しが完全に失敗していました。問題は一体どこにあったのでしょうか?

問題の根源:各コンテナはネットワークの「孤島」である

ドキュメントやフォーラムを深く掘り下げた結果、私は核心的な原則に気づきました。デフォルトでは、各Dockerコンテナはネットワーキングを含め、完全に隔離された環境であるということです。

docker runをネットワーク指定なしで実行すると、Dockerはコンテナをbridgeという名前のデフォルトネットワークに自動的に割り当てます。このように別々に実行された2つのコンテナは、同じbridgeネットワーク上にあっても、お互いを「名前で呼び合う」ことができません。Dockerが割り当てる内部IPアドレスを介してのみ通信できますが、このIPはコンテナが再起動するたびに変わる可能性があり、安定性に欠けます。

対照的に、docker-composeはもっと「賢く」振る舞います。docker-compose.ymlファイルで定義されたすべてのサービスのために、専用のブリッジネットワークを自動的に作成します。おかげで、同じcompose「ファミリー」内のコンテナは、サービス名で簡単にお互いを呼び出すことができます。ステージングでの私の問題は、まさにcomposeを使わずにコンテナを個別に実行したため、互いに「見失って」しまったことが原因でした。

このメカニズムを理解したことで、その場しのぎのエラー修正だけでなく、より複雑なシステムを自信を持って設計するための基盤も得られました。Dockerの世界では、私たちがマスターすべき主要なネットワークドライバーが3つあります。Bridge、Host、そしてOverlayです。

Dockerにおけるネットワーキングソリューション

1. Bridge Network:ほとんどのケースで安全な選択肢

BridgeはDockerの「国民的」ネットワークと言えるでしょう。デフォルトでありながら、ほとんどのシナリオに十分な柔軟性を備えています。使用すると、Dockerはホストマシン上に仮想的なゲートウェイとサブネットを作成し、コンテナ間の「橋」として機能します。

  • 動作の仕組み: 各コンテナには、仮想サブネット内(例:172.17.0.0/16)の個別のIPが割り当てられます。DockerがルーティングとNAT(Network Address Translation)を処理します。これにより、コンテナは互いに通信し、ホストマシンのIPを介してインターネットに接続できます。
  • 内部DNS: ユーザー定義ブリッジネットワーク(user-defined bridge network)を使用する際の「秘密兵器」は、統合されたDNSシステムです。同じネットワーク上のコンテナは、コンテナ名(例:postgres, redis)だけでお互いを見つけて通信できます。これこそが、docker-composeの利便性の背後にある魔法です。

実践例: Dockerのデフォルトブリッジを使わずに、常に独自のネットワークを作成しましょう。

# 1. カスタムブリッジネットワークを作成
docker network create my-app-net

# 2. そのネットワーク上でデータベースコンテナを実行
docker run -d --name my-postgres --network my-app-net -e POSTGRES_PASSWORD=mysecretpassword postgres

# 3. 同じネットワーク上でアプリケーションコンテナを実行
# これで、ホスト名「my-postgres」を使ってDBに接続できる
docker run -d --name my-app --network my-app-net -e DATABASE_HOST=my-postgres my-app-image

個人的な経験: 単一サーバーで実行するプロジェクトでは、99%のケースでユーザー定義ブリッジネットワークのみを使用しています。十分に安全(良好な分離性)で便利(DNS解決)です。ちなみに、私はスタック全体でdocker-compose v1からv2に移行しましたが、プロセスは非常にスムーズでした。ネットワーキングは全く同じように機能し、YAMLファイルの構文がよりクリーンになっただけです。

2. Host Network:制限をなくして最高速度を実現

ネットワークパフォーマンスが絶対的な優先事項である場合、Hostネットワークを使用すると、仮想化レイヤーを「取り除く」ことができます。コンテナが独自のネットワークカードを持たなくなるのを想像してみてください。代わりに、ホストのネットワークカードを直接共有し、まるでホスト上で直接実行されているアプリケーションのようになります。

  • 動作の仕組み: コンテナは独自のIPを持たず、ホストのネットワークスタックを使用します。コンテナ内でポート8080で実行されているアプリケーションは、ホストマシンのポート8080を直接占有します。
  • 利点: 最高のパフォーマンス。中間のNATレイヤーを通過しないため、ネットワーク速度はホスト上でネイティブに実行されるアプリケーションとほぼ同等です。
  • 欠点: セキュリティと管理の面で大きなトレードオフがあります。明白な問題はポートの競合です。同じポートを占有する2つのコンテナを同時に実行することはできません。さらに重要なのは、Dockerの最も中心的な価値の一つである分離の原則が破られることです。

例:

# このコンテナはホストのポート80を直接使用します
# ポート80が既に使用されている場合、このコマンドはエラーになります
docker run -d --name nginx-host --network host nginx

いつ使うべきか? 実際には、私がhostネットワークを使用することは極めて稀です。システムの監視エージェント(Prometheus Node Exporter, Datadog Agent)のように、メトリクスを収集するためにホストのネットワークインターフェースに直接アクセスする必要がある特殊なタスクにのみ適しています。あるいは、可能な限り低い遅延で巨大なネットワークデータストリームを処理する必要がある特定のシナリオです。選択する前には、常に慎重に検討してください。

3. Overlay Network:分散システムのための力

やがてあなたのアプリは1台のサーバーで順調に動作するようになります。上司に肩を叩かれて「安定性のためにサーバー3台で動かそう!」と言われました。この時点で、Bridgeネットワークではもはや不十分です。サーバーAのコンテナは、どうやってサーバーBのコンテナと通信するのでしょうか?

Overlay networkこそがその答えです。これは、複数のホスト上のコンテナ間の通信を可能にする基盤技術であり、Docker SwarmやKubernetesのようなオーケストレーションシステムにおいて中心的な役割を果たします。

  • 動作の仕組み: Overlayネットワークは、複数のDockerホストにまたがる仮想的なレイヤー2ネットワークを作成します。それはまるで、サーバーの物理ネットワークの上に広がる見えない「網」のようなものです。この「網」に接続されたコンテナは、クラスタ内のどのホストで実行されていても、名前で互いに通信できます。
  • 要件: Overlayネットワークを作成・管理するには、コンテナオーケストレーションツールが必要です。Dockerの場合、組み込みのツールがDocker Swarmです。

Docker Swarmでの例:

# (マネージャーノード上で)
# 1. Docker Swarmを初期化
docker swarm init

# 2. overlayネットワークを作成
docker network create --driver overlay my-distributed-net

# 3. そのoverlayネットワーク上に、3つのレプリカを持つサービスをデプロイ
# Docker Swarmはこれら3つのコンテナをクラスタ内のノードに自動的に分散します
docker service create --name my-api --network my-distributed-net --replicas 3 my-api-image

この時点で、my-apiサービスの3つのコンテナは、物理的に異なる3台のサーバー上にあるかもしれません。しかし、それらはmy-distributed-netネットワークを介して、シームレスにお互いを「見て」呼び出すことができます。

概要表:どのシナリオでどのネットワークを選ぶか?

すべての状況に「最良」の選択肢というものはありません。代わりに、あなたのアーキテクチャと要件に「最も適した」ネットワークタイプを選びましょう。

  1. ユーザー定義ブリッジネットワーク (User-defined Bridge Network): 単一ホスト上で実行されるアプリケーションのデフォルトの選択肢です。安全性、利便性(内部DNSによる)、そして優れたパフォーマンスのバランスが完璧です。
  2. ホストネットワーク (Host Network): 最高のネットワークパフォーマンスが必要で、セキュリティやポート競合のトレードオフを受け入れる特別なケース向けです。意図を明確にし、慎重に使用してください。
  3. オーバーレイネットワーク (Overlay Network): 複数ホストに分散したアプリケーションには必須のソリューションです。これは、Docker SwarmやKubernetesを使用した高可用性システムの基盤となります。

これら3つのネットワークタイプを習得したことで、私のシステムアーキテクチャの設計方法は完全に変わりました。単一VPS上のシンプルなアプリケーションから、複雑なマイクロサービスシステムまで、すべては適切なネットワークを選択することに帰着します。この実践的な経験が、皆さんがDockerを扱う上でより自信を持つ助けになることを願っています。

Share: