「コンテナ名でpingが届かない」「-p でポートを公開したのに外部から見えない、または逆に意図せず見えてしまう」——Dockerネットワークに関するトラブルは、仕組みを理解していないと原因の見当もつきません。
この記事では、Dockerネットワークドライバの種類から、コンテナ間通信のDNS解決の仕組み、docker network コマンドの実践的な使い方、Docker Composeのネットワーク定義パターン、そしてRocky Linux 9環境特有のfirewalld干渉問題まで体系的に解説します。
- bridge / host / none の違いと、カスタムbridgeネットワークの作成・運用方法
- コンテナ名でDNS解決できる仕組みと、デフォルトbridgeで使えない理由
- Rocky Linux 9 での firewalld と Docker の干渉問題と DOCKER-USER チェーンによる安全な制御
Dockerネットワークの全体像 — 4種類のドライバ早見表
Dockerコンテナは起動時にいずれかのネットワークドライバに接続されます。どのドライバを選ぶかで、コンテナ間通信の方法やホストネットワークとの関係が大きく変わります。
| ドライバ | 主な用途 | コンテナ名DNS | 特徴 |
|---|---|---|---|
| bridge(デフォルト) | 単一ホスト・開発用途 | 無効 | コンテナ名での名前解決不可。IPアドレス直接指定のみ |
| bridge(カスタム) | 単一ホスト・推奨 | 有効 | コンテナ名・サービス名で通信可。本番環境にも使用可 |
| host | 高スループット・特殊用途 | 不要 | ホストのネットワーク名前空間を共有。ポートマッピング不要 |
| none | 完全隔離・バッチ処理 | なし | ループバック(lo)のみ。外部通信を完全遮断 |
| overlay | Docker Swarm・マルチホスト | 有効 | 複数ホスト間でコンテナを通信させる(Swarm専用) |
| macvlan | レガシーシステム連携 | N/A | コンテナにMACアドレスを直接割り当て |
bridge — 同一ホスト内の標準ネットワーク
bridgeドライバは、Dockerのデフォルトネットワークです。docker run でネットワークを指定しない場合、コンテナは自動的に bridge(docker0)に接続されます。ホストには仮想ブリッジ docker0(デフォルトサブネット: 172.17.0.0/16)が作成され、コンテナはそのサブネット内のIPアドレスを取得します。
重要な制限: デフォルトの bridge ネットワークでは、コンテナ名によるDNS解決が無効です。別のコンテナと通信するには、docker network inspect でIPアドレスを調べて直接指定する必要があります。後述のカスタムbridgeで解決できます。
host — ホストのネットワーク空間を共有
hostドライバを使うと、コンテナはホストのネットワーク名前空間をそのまま使用します。コンテナ内のプロセスがポート80でListenすれば、ホストの80番ポートに直接バインドされます。
# ポートマッピング不要で起動できる
docker run --rm --network host nginx
# ホストの80番ポートで直接アクセス可能
curl http://localhostコンテナとホストがポート空間を共有するため、ポートの競合リスクがあります。ネットワークの隔離もなくなるため、セキュリティ要件が厳しい環境では使用を避けてください。
none — 完全ネットワーク遮断
noneドライバを使うと、コンテナはループバックインターフェース(lo)のみを持ち、外部との通信が完全に遮断されます。バッチ処理(ファイル変換・データ処理など)やセキュリティ上ネットワーク接続を禁止したい処理に使います。
docker run --rm --network none alpine ip addr
# lo のみ表示される
# 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 ...
# inet 127.0.0.1/8 scope host looverlay — Docker Swarm 向けマルチホストネットワーク
overlayドライバは Docker Swarm クラスタ専用です。複数のDockerホストにまたがるネットワークを構成し、別ホストのコンテナとも同一ネットワーク内のように通信できます。単独のDockerホスト環境では使用しません。
デフォルトbridgeの落とし穴とカスタムbridgeの作り方
デフォルトbridgeではコンテナ名のDNS解決ができない
最もよくある落とし穴を実際に確認してみます。
# コンテナAを起動
docker run -d --name containerA alpine sleep 3600
# コンテナBからコンテナAにpingしてみる
docker run --rm alpine ping -c 2 containerA
# ping: bad address 'containerA' ← 名前解決できない!
# IPアドレスで指定すれば通信できる
docker inspect containerA --format '{{.NetworkSettings.IPAddress}}'
# 172.17.0.2
docker run --rm alpine ping -c 2 172.17.0.2
# PING 172.17.0.2 (172.17.0.2): 56 data bytes
# 64 bytes from 172.17.0.2: ... ← IPなら届くデフォルトの bridge ネットワークは Docker 組み込みDNSサーバーが機能しないため、コンテナ名での名前解決ができません。カスタムbridgeネットワークを使うことで解決できます。
カスタムbridgeネットワークの作成と接続
docker network create mynetworkdocker run -d --name containerA --network mynetwork alpine sleep 3600docker run --rm --network mynetwork alpine ping -c 2 containerA
# PING containerA (172.18.0.2): 56 data bytes
# 64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.137 ms
# ← コンテナ名で解決できた!カスタムbridgeネットワークのメリットをデフォルトbridgeと比較します。
| 機能 | デフォルトbridge | カスタムbridge |
|---|---|---|
| コンテナ名でのDNS解決 | 不可 | 可能 |
| コンテナ間の分離 | 全コンテナが同一ネット | ネットワーク単位で分離 |
| 実行中コンテナへの追加接続 | 不可 | docker network connect で可能 |
| ネットワークスコープの分離 | なし | プロジェクトごとに分離できる |
サブネット・ゲートウェイを固定指定する
IPアドレス範囲を明示的に指定したい場合(他のネットワークとの競合回避・固定IP運用など)は --subnet と --gateway オプションを使います。
# サブネットとゲートウェイを明示して作成
docker network create \
--driver bridge \
--subnet 192.168.100.0/24 \
--gateway 192.168.100.1 \
myapp-network
# 固定IPを指定してコンテナを起動
docker run -d \
--name webserver \
--network myapp-network \
--ip 192.168.100.10 \
nginx
# 確認
docker inspect webserver --format '{{.NetworkSettings.Networks.myapp-network.IPAddress}}'
# 192.168.100.10docker networkコマンド実践リファレンス
docker network ls / create / rm / prune
# ネットワーク一覧を表示
docker network ls
# NETWORK ID NAME DRIVER SCOPE
# a1b2c3d4e5f6 bridge bridge local
# b2c3d4e5f6a1 host host local
# c3d4e5f6a1b2 none null local
# d4e5f6a1b2c3 mynetwork bridge local
# ネットワーク作成
docker network create --driver bridge mynetwork
# ネットワーク削除(接続中のコンテナがない場合)
docker network rm mynetwork
# 未使用のネットワークをまとめて削除
docker network prune
# WARNING! This will remove all custom networks not used by at least one container.
# Are you sure you want to continue? [y/N]docker network inspect の使い方
# ネットワークの詳細情報を表示(JSON形式)
docker network inspect mynetwork
# 出力例(抜粋)
# [
# {
# "Name": "mynetwork",
# "Driver": "bridge",
# "IPAM": {
# "Config": [
# { "Subnet": "172.18.0.0/16", "Gateway": "172.18.0.1" }
# ]
# },
# "Containers": {
# "abc123...": {
# "Name": "containerA",
# "IPv4Address": "172.18.0.2/16"
# }
# }
# }
# ]–format オプションと jq で出力を加工する
JSON全体が長い場合、--format テンプレートや jq を使って必要な情報だけ抽出できます。
# 接続中のコンテナ名とIPアドレスを一覧表示
docker network inspect mynetwork \
--format '{{range .Containers}}{{.Name}}: {{.IPv4Address}}{{"\n"}}{{end}}'
# containerA: 172.18.0.2/16
# containerB: 172.18.0.3/16
# jq でコンテナ名とIPアドレスをテーブル形式で表示
docker network inspect mynetwork | \
jq -r '.[0].Containers | to_entries[] | "\(.value.Name)\t\(.value.IPv4Address)"'
# サブネット情報を取得
docker network inspect mynetwork \
--format '{{range .IPAM.Config}}Subnet: {{.Subnet}} / Gateway: {{.Gateway}}{{"\n"}}{{end}}'
# Subnet: 172.18.0.0/16 / Gateway: 172.18.0.1docker network connect / disconnect
実行中のコンテナをネットワークに後から接続・切断できます。コンテナを再起動せずにネットワーク構成を変更できる便利な機能です。
# 実行中のコンテナを別のネットワークに追加接続
docker network connect mynetwork containerA
# コンテナをネットワークから切断
docker network disconnect mynetwork containerA
# 接続確認(コンテナが複数のネットワークに属していることを確認)
docker inspect containerA \
--format '{{range $k, $v := .NetworkSettings.Networks}}{{$k}}: {{$v.IPAddress}}{{"\n"}}{{end}}'
# bridge: 172.17.0.2
# mynetwork: 172.18.0.2コンテナ名でつながる仕組み — Docker内蔵DNSサーバとは
/etc/resolv.conf の中身を確認する
カスタムbridgeネットワークに接続したコンテナの /etc/resolv.conf を確認してみます。
# カスタムネットワーク上のコンテナで確認
docker run --rm --network mynetwork alpine cat /etc/resolv.conf
# search mynetwork
# nameserver 127.0.0.11 ← Docker内蔵DNSサーバー
# options ndots:0
# デフォルトbridgeのコンテナで確認
docker run --rm alpine cat /etc/resolv.conf
# nameserver 192.168.1.1 ← ホストのDNSサーバーが設定される(127.0.0.11ではない)DNSサーバー 127.0.0.11 の正体
127.0.0.11 は Docker デーモンが管理する組み込みDNSサーバーです。Dockerは iptables の REDIRECT ルールを使って、コンテナから 127.0.0.11:53 へのDNSクエリをDockerデーモンのDNSハンドラーにリダイレクトします。
# dig でコンテナ名のDNS解決を確認
docker run --rm --network mynetwork alpine sh -c \
"apk add --no-cache bind-tools -q && dig @127.0.0.11 containerA"
# ;; ANSWER SECTION:
# containerA. 600 IN A 172.18.0.2
# ← コンテナ名が正しくAレコードとして返ってくるポートマッピング(-p オプション)の仕組みとセキュリティ注意点
-p の内部動作 — iptables への自動ルール追加
docker run -p 8080:80 を実行すると、Dockerは iptables の DOCKER チェーンに転送ルールを自動的に追加します。
# -p 8080:80 で起動後、iptablesルールを確認
docker run -d -p 8080:80 --name web nginx
sudo iptables -t nat -L DOCKER --line-numbers -n
# Chain DOCKER (2 references)
# num target prot opt in out source destination
# 2 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.2:80
# ↑ 外部からポート8080へのアクセスをコンテナの172.17.0.2:80に転送するルールが追加された全インターフェース公開と localhost 限定公開の違い
-p オプションのバインドアドレスを意識していないと、意図せず全ネットワークインターフェースに公開してしまいます。
# 全インターフェースに公開(デフォルト)— 外部からアクセス可能
docker run -d -p 8080:80 nginx
# localhostのみに公開 — 外部からアクセス不可、サーバー内からのみ
docker run -d -p 127.0.0.1:8080:80 nginx
# 確認
ss -tlnp | grep 8080
# 0.0.0.0:8080 → 全インターフェース公開
# 127.0.0.1:8080 → localhost のみDOCKER-USER チェーンでアクセス制限する
Dockerは iptables の DOCKER チェーンを自動管理するため、このチェーンに手動でルールを追加してもDockerが上書きしてしまいます。アクセス制限のカスタムルールは DOCKER-USER チェーンに追加します。
# 社内ネットワーク(192.168.1.0/24)からのみアクセスを許可
# それ以外はすべてDROP
sudo iptables -I DOCKER-USER -i eth0 \
! -s 192.168.1.0/24 \
-j DROP
# ルールを確認
sudo iptables -L DOCKER-USER -n --line-numbers
# Chain DOCKER-USER (1 references)
# num target prot opt in out source destination
# 1 DROP all -- eth0 * !192.168.1.0/24 0.0.0.0/0
# ルールを永続化(Rocky Linux 9)
sudo iptables-save | sudo tee /etc/sysconfig/iptables
sudo systemctl enable iptablesDocker Composeのネットワーク定義パターン
デフォルトネットワークの自動生成
Docker Composeは、docker compose up を実行すると自動的に プロジェクト名_default という名前のカスタムbridgeネットワークを作成します。すべてのサービスはこのネットワークに接続され、サービス名でDNS解決できます。
services:
web:
image: nginx
ports:
- "8080:80"
app:
image: myapp:1.0.0
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: secretfrontend / backend の2ネットワーク分離構成
セキュリティ要件に応じてネットワークを分離できます。以下は Web・アプリ・DBの3層構成でネットワークを分離する例です。
services:
web:
image: nginx
ports:
- "8080:80"
networks:
- frontend # フロントエンドネットワークのみ
app:
image: myapp:1.0.0
networks:
- frontend # webと通信できる
- backend # dbと通信できる
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: secret
networks:
- backend # バックエンドネットワークのみ(webからは直接アクセス不可)
networks:
frontend:
backend:db を外部から完全遮断する internal: true
internal: true を設定したネットワークは、ホスト外部(インターネット)との通信が完全に遮断されます。DBサーバーなど、絶対に外部から通信させたくないコンテナを配置するのに適しています。
services:
app:
image: myapp:1.0.0
networks:
- frontend
- internal-net
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: secret
networks:
- internal-net # internal ネットワークのみ
networks:
frontend:
internal-net:
internal: true # ← このネットワークのコンテナはインターネットに出られないexternal: true で別 Compose プロジェクトと通信する
複数のdocker-composeプロジェクト間でコンテナを通信させたい場合、共有ネットワークを external: true で参照します。
# まず共有ネットワークを手動で作成
docker network create shared-network# プロジェクトA の compose.yaml
services:
api:
image: myapi:1.0.0
networks:
- shared-network
networks:
shared-network:
external: true # 既存のネットワークを参照(作成しない)# プロジェクトB の compose.yaml
services:
frontend:
image: myfrontend:1.0.0
networks:
- shared-network
networks:
shared-network:
external: true # 同じ既存ネットワークを参照【Rocky Linux 9対応】firewalldとDockerの共存設定
Dockerが自動作成するfirewalldゾーン
Rocky Linux 9 など firewalld が有効な環境でDockerを起動すると、Dockerは自動的に docker という名前のfirewalldゾーンを作成し、docker0 インターフェースをそのゾーンに追加します。
# firewalld のゾーン一覧を確認
sudo firewall-cmd --get-zones
# block dmz drop external home internal public trusted work docker
# ↑ Dockerが自動作成
# docker ゾーンの設定を確認
sudo firewall-cmd --zone=docker --list-all
# docker (active)
# target: ACCEPT
# interfaces: docker0-p でポートを公開すると firewalld をバイパスする問題
Rocky Linux 9 で最も注意が必要なのが、docker run -p によるポート公開が firewalld のルールを無視してしまう問題です。
# firewall-cmd でポート8080を閉じる
sudo firewall-cmd --zone=public --remove-port=8080/tcp
# しかし docker run -p で公開すると...
docker run -d -p 8080:80 nginx
# 外部から確認すると(別ホストから)
curl http://<サーバーIP>:8080
# <h1>Welcome to nginx!</h1> ← firewall-cmd で閉じているのに届いてしまう!Dockerは iptables の DOCKER チェーンにポート転送ルールを書き込みますが、このルールは firewalld のルールよりも先に評価されます。結果として、firewalld でポートを閉じていても Docker のiptablesルールが優先されてしまいます。
DOCKER-USER チェーンへのルール追加で安全に制御する
Dockerが管理する DOCKER チェーンにルールを追加するとDockerの再起動時に削除されますが、DOCKER-USER チェーンに追加したルールは保持されます。
# DOCKER-USER チェーンの現在のルールを確認
sudo iptables -L DOCKER-USER --line-numbers -n
# 社内ネットワーク(192.168.1.0/24)からのみアクセスを許可
sudo iptables -I DOCKER-USER -i eth0 \
! -s 192.168.1.0/24 \
-j DROP
# ルールを永続化(Rocky Linux 9)
sudo iptables-save | sudo tee /etc/sysconfig/iptables
sudo systemctl enable iptablesfirewalld と Docker の共存に関するよくある問題と対処法をまとめます。
| 症状 | 原因 | 対処法 |
|---|---|---|
| firewall-cmd でポートを閉じても Docker コンテナに届く | DockerのiptablesルールがfirewalldをBYPASS | DOCKER-USER チェーンにDROPルールを追加 |
| Docker 起動後に firewalld のルールが効かなくなった | firewalld が iptables を管理していない | iptables-legacy を使用するか firewalld バックエンドを確認 |
| コンテナが外部に通信できない(DNS解決不可) | firewalld が docker0 のフォワーディングをブロック | docker ゾーンの設定を確認、masquerade を有効化 |
| Docker 再起動後に DOCKER-USER のルールが消える | iptables-save で永続化していない | iptables-save で保存、iptables.service を有効化 |
よくある質問(FAQ)
- docker0 と カスタムbridgeは何が違うの?
最大の違いは DNS解決の有無 です。デフォルトの docker0 ではコンテナ名での名前解決ができず、IPアドレスを直接指定する必要があります。カスタムbridgeではコンテナ名・サービス名で通信でき、ネットワーク単位での分離も可能です。実運用では必ずカスタムbridgeを使いましょう。
- Docker Composeのサービス名でコンテナに接続できない
まず
docker compose psでコンテナが起動しているか確認してください。次にdocker network inspect <プロジェクト名>_defaultで両コンテナが同じネットワークに属しているか確認します。networks:を明示指定している場合、接続したいサービス同士が同じネットワーク名を参照しているか見直してください。- Rocky Linux 9 でfirewalldとDockerを両立させる最もシンプルな方法は?
アプリコンテナを
127.0.0.1:PORT:PORTでバインドし、Nginxリバースプロキシだけを外部公開する構成が最もシンプルです。この場合、firewalldで80/443のみを開けるだけで済み、DOCKER-USERチェーンの設定が不要になります。- docker network prune を実行したらどうなる?
現在どのコンテナにも接続されていないカスタムネットワークがすべて削除されます。
bridge・host・noneの組み込みネットワークは削除されません。実行前にdocker network lsで削除対象を確認し、-f(–force)オプションを使えば確認プロンプトをスキップできます。
まとめ
Dockerネットワークの重要ポイントをまとめます。
- デフォルトbridgeは使わない:コンテナ名でのDNS解決が使えないため、
docker network createでカスタムbridgeネットワークを作成してから使う - Docker ComposeはデフォルトでカスタムbridgeをDNS有効で作成する:サービス名で通信できるのはこの仕組みのおかげ
-pはfirewalldをバイパスする:Rocky Linux 9 では DOCKER-USER チェーンにアクセス制限ルールを追加するか、127.0.0.1バインドにしてリバースプロキシ経由で公開する- DB等はinternalネットワークに閉じ込める:
internal: trueで外部通信を完全遮断 docker network inspectを活用する:トラブル時は--formatやjqで必要な情報だけ抽出する
次回の Docker 連載では、本番環境でのコンテナ運用における Docker のセキュリティ設定(非rootユーザー、read-only filesystem、capabilities の制限など)を解説します。

コメント