Docker Composeのネットワーク設計|サービス名での名前解決・カスタムネットワーク・external接続の実践手順

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Docker > Docker Composeのネットワーク設計|サービス名での名前解決・カスタムネットワーク・external接続の実践手順
「docker compose upしたのに、コンテナ同士が通信できない」
「サービス名でDBにアクセスできたが、なぜ動くのか仕組みがわからない」
そんな疑問を抱えたまま使い続けているエンジニアは少なくありません。

Docker Composeはデフォルトで専用ネットワークを自動作成し、サービス名をそのままDNSホスト名として機能させます。しかし本格的な環境では「DBをフロントエンドから直接見えなくしたい」「別のComposeプロジェクトのネットワークに接続したい」といった要件が必ず出てきます。

この記事では、Docker Composeのネットワークの仕組みをゼロから整理し、カスタムネットワーク定義・複数ネットワークによる通信分離・external接続の実践手順まで、実サーバーの確認例を交えて解説します。

動作確認環境: Rocky Linux 9.4 / Ubuntu 24.04 LTS(Docker Engine 26.x・Docker Compose Plugin v2.27)

この記事のポイント

・Composeはdocker compose up時に専用ブリッジネットワークを自動作成しサービス名をDNSホスト名にする
・networks:ブロックでカスタムネットワークを定義しサービスに複数割り当てると通信経路を分離できる
・external: trueでComposeの外側に存在する既存Dockerネットワークに接続できる
・docker network inspectとdocker compose execで通信障害を迅速に切り分けられる


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
図解60P/登録10秒/解除も3秒 / 詳細はこちら

Docker Composeのデフォルトネットワークとサービス名DNS解決の仕組み

docker compose up を実行すると、Composeは自動的に {プロジェクト名}_default という名前のブリッジネットワークを作成します。
そのcompose.yml内の全サービスがこのネットワークに自動参加するため、サービス名をそのままホスト名として使えます。

# docker compose up後にネットワーク一覧を確認 $ docker network ls NETWORK ID NAME DRIVER SCOPE a1b2c3d4e5f6 bridge bridge local f6e5d4c3b2a1 host host local 9z8y7x6w5v4u myapp_default bridge local # myapp = compose.ymlのあるディレクトリ名(プロジェクト名)

1. サービス名でアクセスできる理由

Dockerは各コンテナが参加するネットワーク内に専用のDNSサーバーを持っています。
このDNSがサービス名(例: dbredis)を自動的に対応するコンテナのIPアドレスに解決します。
これはLinux標準の DNS設定(/etc/resolv.conf) とは独立した仕組みで、コンテナ内の /etc/resolv.conf を見るとDockerのDNSサーバー(127.0.0.11)が指定されています。

# webコンテナ内でdbのホスト名を解決できることを確認 $ docker compose exec web ping -c 3 db PING db (172.18.0.3) 56(84) bytes of data. 64 bytes from db (172.18.0.3): icmp_seq=1 ttl=64 time=0.094 ms 64 bytes from db (172.18.0.3): icmp_seq=2 ttl=64 time=0.078 ms 64 bytes from db (172.18.0.3): icmp_seq=3 ttl=64 time=0.081 ms # コンテナ内のDNS設定 $ docker compose exec web cat /etc/resolv.conf nameserver 127.0.0.11 options ndots:0

2. デフォルトネットワークの参加状況を確認する

docker network inspect でネットワークにどのコンテナが参加しているかを確認できます。

$ docker network inspect myapp_default [ { "Name": "myapp_default", "Driver": "bridge", "Containers": { "a1b2c3...": { "Name": "myapp-web-1", "IPv4Address": "172.18.0.2/16" }, "d4e5f6...": { "Name": "myapp-db-1", "IPv4Address": "172.18.0.3/16" } } } ]

デフォルトネットワークはすべてのサービスが同じネットワークに参加するため、WebコンテナからDBに直接アクセスできてしまうという問題があります。
本番環境では通信経路を明示的に分離すべきです。

networks:ブロックでカスタムネットワークを定義する方法

compose.ymlの最上位に networks: ブロックを追加することで任意のネットワークを定義できます。
サービス側の networks: キーでそのサービスが参加するネットワークを指定します。

# カスタムネットワークを定義するcompose.ymlの基本形 services: nginx: image: nginx:1.25 ports: - "80:80" networks: - frontend app: image: myapp:latest networks: - frontend - backend db: image: postgres:15 networks: - backend networks: frontend: driver: bridge backend: driver: bridge

3. ネットワークのdriverオプション

driver: には以下を指定できます。
bridge(デフォルト):同一ホスト内のコンテナ間通信に使う最も一般的な選択
host:コンテナがホストのネットワーク名前空間を直接使う(パフォーマンス重視・セキュリティリスクあり)
overlay:Docker Swarm等の複数ホスト間通信向け(本記事の対象外)

通常の開発・本番単一ホスト環境では driver: bridge が正解です。

複数ネットワークで通信経路を分離する3層設計

4. なぜ通信を分離するのか

「フロントエンド → アプリ → DB」の3層構成で、フロントエンドからDBへの直接通信を禁止するのがセキュリティの基本です。
コンテナに複数のネットワークを割り当て、共有するネットワークだけで通信させることでこれを実現します。

現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、Docker Composeのネットワーク設計をはじめとするDockerの実践スキルを体系的に学べる講座を用意しています。
Dockerマスター講座の詳細はこちら >>

5. 3層構成のcompose.yml実践例

# nginx-app-dbの3層構成でネットワークを分離する例 services: nginx: image: nginx:1.25 ports: - "80:80" networks: - frontend volumes: - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro app: image: myapp:latest networks: - frontend # nginxと通信できる - backend # dbと通信できる environment: - DB_HOST=db db: image: postgres:15 networks: - backend # appとのみ通信できる(nginxからは見えない) volumes: - db_data:/var/lib/postgresql/data environment: - POSTGRES_PASSWORD=secret volumes: db_data: networks: frontend: driver: bridge backend: driver: bridge

6. 通信分離の動作確認

# appコンテナからdbへはアクセスできる $ docker compose exec app ping -c 2 db PING db (172.19.0.3) 56(84) bytes of data. 64 bytes from db (172.19.0.3): icmp_seq=1 ttl=64 time=0.112 ms 64 bytes from db (172.19.0.3): icmp_seq=2 ttl=64 time=0.089 ms # nginxコンテナからdbへはアクセスできない(別ネットワーク) $ docker compose exec nginx ping -c 2 db ping: db: Name or service not known

nginxとdbは共通するネットワークを持たないため、nginxからdbのサービス名が解決できません。
これが複数ネットワーク分離によるセキュリティ効果です。

7. networksのaliasesで別名アクセスを設定する

サービス名以外の別名(エイリアス)でアクセスさせたい場合は aliases: を使います。
たとえばアプリが「mysql」というホスト名を期待している場合に、実際のサービス名(db)のまま別名を設定できます。

services: db: image: mysql:8.0 networks: backend: aliases: - mysql # サービス名"db"に加え"mysql"でもアクセス可能 - database

external: trueで既存Dockerネットワークに接続する方法

8. external:が必要なシーン

以下のようなケースでは、Composeが管理しない外部の既存Dockerネットワークに接続する必要があります。
・PrometheusやGrafanaなどの監視コンテナを独立したComposeで管理し、複数アプリを同時監視したい
・複数のComposeプロジェクト間でデータベースコンテナを共有したい
・インフラチームが事前に用意した共有ネットワークを使う

9. 外部ネットワークの作成とexternal設定

# まず手動で共有ネットワークを作成する(1度だけ実行) $ docker network create shared_monitoring 8f3c9a1b2d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0 # 作成確認 $ docker network ls | grep shared_monitoring 8f3c9a1b2d4e shared_monitoring bridge local

# アプリ側のcompose.yml(monitoring networkにもアクセス可能にする) services: app: image: myapp:latest networks: - backend - monitoring networks: backend: driver: bridge monitoring: external: true # Composeの外で管理するネットワーク name: shared_monitoring # 実際のネットワーク名を指定

# 監視ツール側のcompose.yml(同じshared_monitoringに参加) services: prometheus: image: prom/prometheus:latest networks: - monitoring networks: monitoring: external: true name: shared_monitoring

10. 外部ネットワークが存在しない場合のエラー

external: true を設定した状態で対象のネットワークが存在しないと、以下のエラーが出て起動できません。

$ docker compose up network shared_monitoring declared as external, but could not be found # 対処: 先にdocker network createで作成する $ docker network create shared_monitoring

external: true のネットワークはComposeが作成・削除しません。
docker compose down を実行しても外部ネットワークは残ります。これは意図的な設計です。

トラブルシュート|コンテナ間が通信できない時の調査手順

11. 手順1: ネットワーク一覧とコンテナ参加状況を確認する

# 現在存在するネットワークを確認 $ docker network ls # 特定ネットワークの詳細(参加コンテナのIPを含む) $ docker network inspect myapp_frontend

「通信したい2つのサービスが同じネットワーク名に参加しているか」を確認するのが最初のステップです。

12. 手順2: サービス名でpingが通るか確認する

# webからdbへのpingテスト $ docker compose exec web ping -c 3 db # DNSが解決できない場合(別ネットワーク) ping: db: Name or service not known # IPアドレス直打ちで通るかを確認(DNSだけの問題か切り分ける) $ docker compose exec web ping -c 3 172.18.0.3

13. 手順3: ポートの疎通をncで確認する

pingが通ってもアプリレベルの接続が失敗する場合は、ポートの疎通を確認します。
Linux ポート確認の全コマンドでも紹介しているssコマンドをコンテナ内でも活用できます。

# appからdbの5432ポートが開いているかncで確認 $ docker compose exec app nc -z db 5432 Connection to db (172.19.0.3) 5432 port [tcp/postgresql] succeeded! # タイムアウトする場合は別ネットワーク・ポート未開放を疑う $ docker compose exec app nc -z -w 3 db 5432

14. よくある原因チェックリスト

サービス名のスペルミス:compose.yml内のサービス名と呼び出し側のホスト名が一致しているか確認
共通ネットワークがない:通信したいサービスが同じネットワーク名に参加しているか docker network inspect で確認
external:ネットワークが未作成:docker network create で先に作成しているか確認
compose upのタイミングずれ:参照先サービスが起動前にアクセスしている場合は depends_on と healthcheck を設定する
ファイアウォール(iptables):ホストのiptablesがDOCKER-USERチェーンでブロックしていないか確認

本記事のまとめ

やりたいこと compose.ymlの設定
サービス名でコンテナ間通信したい デフォルトネットワーク(設定不要)を使う
カスタムネットワーク名を付けたい 最上位のnetworks:ブロックに名前を定義する
フロントエンドからDBを見えなくしたい frontend/backendネットワークを分けてサービスに割り当てる
別名(エイリアス)でアクセスさせたい サービスのnetworks:内でaliases:を設定する
Composeの外のネットワークに接続したい external: trueとネットワーク名を指定する
コンテナ間通信の問題を切り分けたい docker network inspectdocker compose exec pingで確認する
Docker Composeのネットワーク設計を理解すると、セキュリティを考慮した構成や複数プロジェクト間の連携が体系的に組み立てられるようになります。
デフォルトネットワークで動く小規模環境から、外部ネットワーク連携が必要な本番環境まで、今回の手順を足がかりに自分の環境に合ったネットワーク設計を試してみてください。

現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、本記事で紹介したDocker Composeのネットワーク設計をさらに深く学べる講座を用意しています。
Dockerマスター講座の詳細はこちら >>

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

登録10秒/合わなければ解除3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。