
Dockerのネットワークモードは、コンテナがどの経路で外部と通信するかを決める設定です。
普段はあまり意識しません。bridgeという標準モードが、面倒な部分を裏で処理してくれるからです。
ところが今回、GitHub Codespaces上のMavenコンテナだけが、この標準モードでつまずきました。
ホストOSからは repo.maven.apache.org を問題なく名前解決できます。同じCodespaces上のMavenコンテナからは、これができませんでした。
「Mavenかpom.xmlの設定が悪いのでは」と疑いたくなるところですが、そうではありません。原因は、Dockerコンテナ側のネットワーク経路にありました。
本記事では、bridgeとhostで通信経路がどう変わるのかを図で整理します。そのうえで、なぜ network_mode: "host" への変更だけで直ったのかを解説します。
主なネットワークモード
Dockerには、コンテナの通信経路を決める設定がいくつか用意されています。代表的なのは、次の4つです。
| モード | コンテナのネットワーク | 用途 |
|---|---|---|
| bridge | Docker専用ネットワークを使う | 一般的なDocker |
| host | ホストOSのネットワークを直接使う | ネットワーク制約を回避したい場合など |
| none | ネットワークなし | 完全に通信させたくない場合 |
| container:<名前> | 別コンテナとネットワークを共有 | 特殊な構成 |
このうち、何も指定しなければ自動的に選ばれるのが bridge です。今回のMavenコンテナも、本来はこの設定でした。
services:
java:
image: maven:3.8.5-openjdk-11これだけの記述で、Dockerはコンテナ専用のネットワークを作り、その中にコンテナを接続してくれます。普段は、この自動処理を意識する必要がありません。
bridge のイメージ
今回の構成を単純化すると、次のようになります。
Docker bridge network
GitHub Codespacesというホストの中に、Docker bridge networkという「もう一枚のネットワーク」が重なっている構造です。今回つまずいたのは、この二重構造の内側でした。
コンテナから curl https://repo.maven.apache.org を実行すると、まず名前解決が必要になります。ドメイン名をIPアドレスに変換する、あの処理です。
そこで切り分けのため、ホストとコンテナの両方から同じドメインを引いてみました。結果は、次のとおりです。
| 場所 | 名前解決 |
|---|---|
| Codespacesホスト | OK |
| Dockerコンテナ | NG |
同じCodespaces環境なのに、片方だけ失敗する。つまりMavenそのものではなく、Dockerコンテナ側のネットワーク経路で名前解決できていなかったわけです。
host モードとは
ここで network_mode: "host" を指定すると、構成が大きく変わります。
コンテナはDocker独自のネットワークを持たなくなり、ホスト側のネットワークをそのまま借りる形になります。いわば、コンテナとホストが同じ土俵に立つイメージです。
これにより、コンテナ → Docker bridge → Docker DNS(127.0.0.11) という、先ほど詰まっていた経路そのものを使わなくなります。
要するに、ホストでは通信できるのに、Docker bridge側だけがおかしい——そんなケースに host はよく効きます。問題のある経路を丸ごと迂回してしまうからです。
なぜ今回これで直ったのか
状況を整理すると、原因はシンプルです。Codespacesホストは repo.maven.apache.org を名前解決できるのに、Dockerコンテナだけができない。この一点に尽きます。
そこで network_mode: "host" にすると、経路は次のように変わります。
Mavenコンテナ → ホストのネットワーク → DNS → repo.maven.apache.org
コンテナが自前のDocker DNSを介さず、ホストの名前解決をそのまま使えるようになるわけです。結果として、mvn clean package はMaven Centralへ問題なく接続できました。
ここで押さえておきたいのは、Mavenの設定を直したわけではないという点です。Spring Bootのバージョンも、pom.xmlも変更していません。変えたのは、Dockerコンテナが外部ネットワークへ出ていくルートだけです。
ports が不要になる理由
もう一つ、見落とされがちな変化があります。それが ports の扱いです。
通常のDocker Composeでは、次のように書きます。
ports:
- "8080:8080"これは、ホストの8080番ポートとDockerコンテナの8080番ポートを橋渡しする、いわゆるポートフォワーディングです。
ところが host モードでは、この橋渡し自体が要らなくなります。コンテナがホストのネットワークをそのまま使うため、アプリがコンテナ内で 0.0.0.0:8080 で待ち受けていれば、その8080番ポートはホスト側でそのまま公開されるからです。そのため network_mode: "host" の場合、Dockerのポートマッピングは基本的に使いません。
つまり今回の構成は、次の形で成立します。
services:
java:
image: maven:3.8.5-openjdk-11
network_mode: "host"host は万能な解決策ではない
ここは、誤解しやすいポイントです。
host は、「ネットワーク周りが面倒だから、とりあえずhostにする」という便利設定ではありません。Dockerが本来持っているネットワーク分離を、意図的に弱める設定だからです。
たとえば frontend、backend、database を同時に動かす構成を考えてみてください。この場合は、通常どおり bridge network を使う方が自然です。frontend ── backend ── database のように、Dockerネットワークの中で安全につなぐ形が向いています。
一方、今回はそもそも条件が違いました。登場するのは GitHub Codespaces と Docker、Maven、そして外部の Maven Central です。問題はDocker側のネットワーク経路だけに限定されていました。だからこそ、host が有効な回避策になったわけです。
今回のケースを一言で言うと
通常の経路は、コンテナ → Docker bridge → Docker DNS → インターネット、です。今回は、まさにこの経路の途中で失敗していました。
そこで host モードに切り替え、コンテナ → ホストのネットワーク → インターネット、というシンプルな経路に変更しました。
通常(失敗)
hostモード(成功)
Docker独自のネットワーク経路をバイパスした。 これが、今回 network_mode: "host" で解決した理由です。設定を疑う前に、まず経路を疑う——今回の教訓は、その一点に尽きます。
クラウドや業務システム、インフラ構成など、ITまわりでお悩みの際は、まずはお気軽にご相談ください。
課題の整理から設計・開発まで、コンサルティングの形で伴走し、サイト構築や業務システム開発にも対応しています。