Dockerネットワーキングにより、コンテナは互いに、そして外部と通信できるようになります。この記事では、ネットワークタイプ、ポートマッピング、DNS、セキュアなコンテナ化アプリケーション構築のベストプラクティスを解説します。
Container Network Model (CNM)
Dockerのネットワーキングは、3つの主要コンポーネントを持つContainer Network Modelに基づいています:
flowchart TB
subgraph CNM["Container Network Model"]
Sandbox["Sandbox(ネットワーク名前空間)"]
Endpoint["Endpoint(vethペア)"]
Network["Network(Bridge, Overlayなど)"]
end
Sandbox --> Endpoint
Endpoint --> Network
style Sandbox fill:#3b82f6,color:#fff
style Endpoint fill:#8b5cf6,color:#fff
style Network fill:#22c55e,color:#fff
| コンポーネント | 説明 |
|---|---|
| Sandbox | 分離されたネットワークスタック(インターフェース、ルーティング、DNS) |
| Endpoint | SandboxをNetworkに接続する仮想ネットワークインターフェース |
| Network | 複数のEndpointを接続するソフトウェア定義ネットワーク |
ネットワークドライバー
Dockerはいくつかの組み込みネットワークドライバーを提供しています:
# 利用可能なネットワークを一覧
docker network ls
# 出力:
NETWORK ID NAME DRIVER SCOPE
abc123 bridge bridge local
def456 host host local
ghi789 none null local
| ドライバー | 説明 | ユースケース |
|---|---|---|
bridge |
デフォルト、分離されたネットワーク | ほとんどのアプリケーション |
host |
ホストのネットワークスタックを共有 | パフォーマンス重視のアプリ |
none |
ネットワークなし | セキュリティ、分離された処理 |
overlay |
マルチホストネットワーキング | Docker Swarm、Kubernetes |
macvlan |
MACアドレスを割り当て | 直接LAN接続が必要なレガシーアプリ |
Bridgeネットワーク
Bridgeネットワークは、Dockerのデフォルトで最も一般的に使用されるネットワークタイプです。
デフォルトBridgeネットワーク
# デフォルトbridgeでコンテナを実行
docker run -d --name web nginx
# デフォルトbridgeを検査
docker network inspect bridge
デフォルトbridgeには制限があります:
- コンテナはIPアドレスでのみ通信可能(名前では不可)
- すべてのコンテナが同じbridgeを共有
ユーザー定義Bridgeネットワーク
ユーザー定義bridgeは優れています:
# カスタムbridgeを作成
docker network create mynetwork
# カスタムネットワークでコンテナを実行
docker run -d --name web --network mynetwork nginx
docker run -d --name api --network mynetwork myapi
# コンテナは名前で互いにアクセス可能
docker exec web curl http://api:3000
ユーザー定義bridgeの利点:
| 機能 | デフォルトBridge | ユーザー定義Bridge |
|---|---|---|
| DNS解決 | ❌(IPのみ) | ✅(名前で可能) |
| 分離 | 共有 | ネットワークごと |
| 接続/切断 | 再起動が必要 | ライブ接続 |
| コンテナリンク | 手動--link |
自動 |
ネットワークの作成と管理
# オプション付きでネットワークを作成
docker network create \
--driver bridge \
--subnet 172.20.0.0/16 \
--gateway 172.20.0.1 \
--ip-range 172.20.240.0/20 \
mynetwork
# 実行中のコンテナをネットワークに接続
docker network connect mynetwork existing-container
# ネットワークから切断
docker network disconnect mynetwork container-name
# ネットワークを削除
docker network rm mynetwork
# 未使用のすべてのネットワークを削除
docker network prune
Hostネットワーク
Hostネットワークはネットワーク分離を解除します。コンテナはホストのネットワークスタックを共有します:
# hostネットワークを使用
docker run -d --network host nginx
# コンテナはホストポートに直接バインド
# ポートマッピング不要 - nginxはhost:80で利用可能
hostネットワーキングを使うタイミング:
| ユースケース | 理由 |
|---|---|
| パフォーマンス重視のアプリ | NATオーバーヘッドなし |
| ホストネットワークアクセスが必要なアプリ | ポートスキャン、ネットワークツール |
| ポートマッピングが問題になる場合 | 多数の動的ポート |
注意: Hostネットワーキングは分離を減らし、Linuxでのみ動作します。
Noneネットワーク
Noneネットワークは完全なネットワーク分離を提供します:
docker run -d --network none --name isolated alpine sleep infinity
# コンテナにはネットワークインターフェースがない(ループバック以外)
docker exec isolated ip addr
# loインターフェースのみ表示
ユースケース:
- 機密データの処理
- ネットワーキングが不要なバッチジョブ
- 最大限のセキュリティ分離
ポートマッピング
ポートマッピングはコンテナポートをホストに公開します:
# ホストポート8080をコンテナポート80にマッピング
docker run -d -p 8080:80 nginx
# 特定のインターフェースにマッピング
docker run -d -p 127.0.0.1:8080:80 nginx
# ランダムなホストポートにマッピング
docker run -d -p 80 nginx
# 複数ポートをマッピング
docker run -d -p 80:80 -p 443:443 nginx
# UDPポートをマッピング
docker run -d -p 53:53/udp dns-server
# ポート範囲をマッピング
docker run -d -p 8000-8010:8000-8010 myapp
ポートマッピングの確認
# ポートマッピングを一覧
docker port container-name
# 出力:
80/tcp -> 0.0.0.0:8080
# またはdocker psを使用
docker ps --format "table {{.Names}}\t{{.Ports}}"
コンテナDNS
Dockerはユーザー定義ネットワーク内で自動DNS解決を提供します:
flowchart LR
subgraph Network["ユーザー定義ネットワーク"]
Web["web"]
API["api"]
DB["db"]
DNS["Docker DNS<br/>127.0.0.11"]
end
Web -->|"api:3000"| DNS
DNS -->|"172.20.0.3"| API
Web -->|"db:5432"| DNS
DNS -->|"172.20.0.4"| DB
style DNS fill:#f59e0b,color:#fff
DNS機能
# ネットワークとコンテナを作成
docker network create mynet
docker run -d --name db --network mynet postgres
docker run -d --name api --network mynet myapi
# apiコンテナは名前でdbにアクセス可能
docker exec api ping db
カスタムDNS設定
# カスタムDNSサーバーを使用
docker run -d \
--dns 8.8.8.8 \
--dns 8.8.4.4 \
--dns-search example.com \
myapp
# ホストエントリを追加
docker run -d \
--add-host myhost:192.168.1.100 \
--add-host db:192.168.1.50 \
myapp
Docker Composeでのネットワーク設定
services:
frontend:
build: ./frontend
networks:
- frontend-net
ports:
- "80:80"
api:
build: ./api
networks:
- frontend-net
- backend-net
expose:
- "3000" # 内部のみ、ホストにマッピングしない
db:
image: postgres:15
networks:
- backend-net
# ポートを公開しない - backend-netからのみアクセス可能
networks:
frontend-net:
driver: bridge
backend-net:
driver: bridge
internal: true # 外部アクセスなし
ネットワークエイリアス
services:
api:
networks:
frontend:
aliases:
- backend
- api-service
networks:
frontend:
コンテナはこれらの名前のいずれかでapiにアクセスできます:api、backend、api-service。
マルチティアアーキテクチャの例
# docker-compose.yml
services:
# パブリック層 - 外部からアクセス可能
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
networks:
- public
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
# アプリケーション層 - 内部のみ
api:
build: ./api
networks:
- public # nginxからトラフィックを受信
- private # データベースに接続
environment:
DATABASE_URL: postgres://db:5432/mydb
expose:
- "3000"
worker:
build: ./worker
networks:
- private # データベースアクセスのみ
environment:
DATABASE_URL: postgres://db:5432/mydb
# データ層 - 最も制限
db:
image: postgres:15
networks:
- private
volumes:
- postgres_data:/var/lib/postgresql/data
# ホストにポートを公開しない
redis:
image: redis:7-alpine
networks:
- private
networks:
public:
driver: bridge
private:
driver: bridge
internal: true # インターネットに到達不可
volumes:
postgres_data:
flowchart TB
subgraph Internet
Users["ユーザー"]
end
subgraph PublicNet["パブリックネットワーク"]
Nginx["nginx<br/>:80, :443"]
end
subgraph AppNet["プライベートネットワーク(internal)"]
API["api<br/>:3000"]
Worker["worker"]
DB["postgres<br/>:5432"]
Redis["redis<br/>:6379"]
end
Users --> Nginx
Nginx --> API
API --> DB
API --> Redis
Worker --> DB
Worker --> Redis
style PublicNet fill:#3b82f6,color:#fff
style AppNet fill:#22c55e,color:#fff
ネットワークの検査
# 詳細なネットワーク情報
docker network inspect mynetwork
# コンテナのIPアドレスを取得
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container-name
# ネットワーク上のコンテナを一覧
docker network inspect mynetwork -f '{{range .Containers}}{{.Name}} {{end}}'
ネットワーキングのトラブルシューティング
ネットワークツールコンテナでデバッグ
# デバッグにnicolaka/netshootを使用
docker run -it --rm --network container:myapp nicolaka/netshoot
# デバッグコンテナ内で:
curl localhost:3000
ping db
nslookup api
tcpdump -i eth0
よくある問題と解決策
| 問題 | 考えられる原因 | 解決策 |
|---|---|---|
| 名前でコンテナに到達できない | デフォルトbridge使用 | ユーザー定義ネットワークを使用 |
| 接続拒否 | 間違ったポートまたはサービス未起動 | ログを確認、ポートを検証 |
| 外部インターネットに到達できない | internalネットワーク | internal: trueを削除 |
| ポートが既に使用中 | ホストポートの競合 | 別のホストポートを使用 |
コンテナの接続性を確認
# コンテナのネットワーク設定を表示
docker exec myapp ip addr
docker exec myapp ip route
docker exec myapp cat /etc/resolv.conf
# 接続性をテスト
docker exec myapp ping other-container
docker exec myapp curl http://api:3000/health
ベストプラクティス
1. ユーザー定義ネットワークを使用
# 常にカスタムネットワークを作成
docker network create app-network
docker run -d --network app-network myapp
2. 機能で分離
networks:
frontend: # Webサーバー
backend: # アプリサーバー
data: # データベース
internal: true
3. 機密サービスにはInternalネットワークを使用
networks:
database:
internal: true # インターネットアクセスなし
4. 必要なものだけを公開
services:
api:
expose:
- "3000" # 内部のみ
# 外部アクセスが必要でなければ'ports'は使わない
5. 開発時はLocalhostにバインド
# ホストマシンからのみアクセス可能
docker run -d -p 127.0.0.1:5432:5432 postgres
まとめ表
| ネットワークタイプ | 分離 | DNS | 外部アクセス | ユースケース |
|---|---|---|---|---|
| Bridge(デフォルト) | 中 | IPのみ | ポートマッピング経由 | 基本 |
| Bridge(カスタム) | 中 | 名前で可能 | ポートマッピング経由 | ほとんどのアプリ |
| Host | なし | ホストの | 直接 | パフォーマンス |
| None | 完全 | なし | なし | セキュリティ |
| Internal | 高 | 名前で可能 | なし | データ層 |
重要なポイント
- 常にユーザー定義ネットワークを使用 - より良いDNSと分離
- セキュリティを考慮した設計 - 機密サービスにはinternalネットワークを使用
- ポート公開を制限 - 内部には
expose、外部にはports - Docker DNSを活用 - IPではなく名前でコンテナを参照
- 機能で分離 - フロントエンド、バックエンド、データ層を分離
- デバッグコンテナを使用 -
nicolaka/netshootはトラブルシューティングに不可欠
次のステップ
次の記事では、最適化された本番イメージを作成するためのマルチステージビルドを学びます。
参考文献
- Docker Deep Dive, 5th Edition - Nigel Poulton
- The Ultimate Docker Container Book, 3rd Edition - Dr. Gabriel N. Schenker
- Dockerネットワーキングドキュメント