Bridge vs Macvlan:NATが負荷になるのはどんな時?
Dockerを使っているなら、デフォルトのBridgeモードには馴染みがあるでしょう。高速で便利ですが、NATという致命的な欠点があります。Bridgeを使うと、コンテナはホストマシンのIPアドレスの背後に隠れてしまいます。サービスにアクセスするには、ポートマッピング(例:8080:80)が必須です。これは、固定ポートが必要なアプリや、LAN内でブロードキャスト通信を行うアプリにとっては非常に面倒です。
2021年、私は顧客のためにDockerでVoIPシステム(Asterisk)を構築しました。SIPプロトコルはNATと非常に相性が悪いです。RTPポートの範囲(10000-20000)をすべてマッピングしたにもかかわらず、音声が片通話になったり、内線登録ができなかったりしました。2日間徹夜でデバッグした後、Macvlanへの切り替えを決めました。結果は驚くべきものでした。コンテナがルーターから直接IPを取得し、まるで本物の物理サーバーのようにスムーズかつ安定して動作したのです。
Macvlanを使用すると、各コンテナに独自の物理MACアドレスを割り当てることができます。これにより、ルーターはコンテナをLANに接続されたノートPCやスマートフォンのように認識します。ポートマッピングの壁は完全に消え去ります。
Macvlanネットワークの仕組み
簡単に言うと、Macvlanはホストマシンの物理ネットワークカードからサブインターフェースを作成します。各コンテナには独自のMACアドレスと、使用しているLANの範囲(例:192.168.1.x)のIPアドレスが割り当てられます。
圧倒的なメリット:
- 優れたパフォーマンス: NATレイヤーを排除することで、ネットワーク遅延(レイテンシ)を約10〜15%削減できます。
- 直感的な管理: 静的IPを直接割り当てるため、複雑なポートマッピングのリストを覚える必要がありません。
- 高い視認性: LAN内の他のデバイスから、仲介なしでコンテナに直接pingを打ったり接続したりできます。
注意すべきデメリット:
- セキュリティ: コンテナがネットワーク上に完全に露出するため、ファイアウォールの設定を非常に慎重に行う必要があります。
- ホスト・コンテナ間通信: デフォルトでは、ホストマシンとMacvlanコンテナは互いに通信できません。ただし、これは数行のコマンドで解決可能です。
- プロミスキャスモード: ホストマシンのネットワークカードが、すべてのパケットを受信するこのモードをサポートしている必要があります。
Docker Macvlanの詳細な設定手順
まず、ルーターに接続されているネットワークカード名を確認します。Linuxでは以下のコマンドを入力します:
ip addr show
ネットワークカードが eth0、IPの範囲が 192.168.1.0/24、ゲートウェイが 192.168.1.1 であると仮定します。
ステップ1:プロミスキャスモードを有効にする
このコマンドにより、ネットワークカードが自身のMACアドレスと一致しないパケットも受信できるようになります。
sudo ip link set eth0 promisc on
ステップ2:Macvlanネットワークの作成
ここが重要なステップです。スマートフォンやテレビなどの他のデバイスとの競合を避けるために、Dockerが割り当て可能なIP範囲を制限する必要があります。
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
--ip-range=192.168.1.192/27 \
-o parent=eth0 my_macvlan
各パラメータの意味:
--ip-range:重複を避けるため、Docker専用に .192 から .223 までのIPを割り当てています。-o parent=eth0:ブリッジとして機能する物理ネットワークカードを指定します。
ステップ3:静的IPでコンテナをデプロイする
Nginxコンテナを実行し、固定IP 192.168.1.200 を割り当ててみましょう。
docker run -d \
--name web-server \
--network my_macvlan \
--ip 192.168.1.200 \
nginx
これで、家の中のどのデバイスからでも http://192.168.1.200 と入力するだけで、Nginxに直接アクセスできます。8080や8888といった複雑なポート指定はもう不要です。
トラブルシューティング:ホストからコンテナにpingが通らない場合
設定後、少し奇妙な現象に遭遇するでしょう。ネットワーク内の他のマシンからはコンテナが見えますが、Dockerを実行しているホストマシン自身からは通信できません。これはLinuxカーネルのループバックセキュリティメカニズムによるものです。
解決するには、ホストマシンにサブインターフェースを作成し、Macvlanの範囲と「会話」できるようにします:
# macvlan-br という名前の仮想リンクを作成
sudo ip link add macvlan-br link eth0 type macvlan mode bridge
# このインターフェースに独自のIPを割り当てる
sudo ip addr add 192.168.1.210/32 dev macvlan-br
sudo ip link set macvlan-br up
# ルーティングの設定
sudo ip route add 192.168.1.200 dev macvlan-br
完了です!これでホストマシンからコンテナ 192.168.1.200 へスムーズに接続できるようになりました。
実戦で学んだ重要な教訓
Macvlanの設定は難しくありませんが、覚えておくべき重要な注意点がいくつかあります:
- IP管理: 常に
--ip-rangeを使用してください。Dockerに無計画にIPを割り当てさせると、プリンターや他の重要なデバイスのIPを奪ってしまう可能性があります。 - Wi-Fiは使わない: MacvlanはWi-Fiカードではうまく動作しません。これは、ドライバーが複数のMACアドレスをサポートしていないことが多いためです。Raspberry Piを使用する場合は、LANケーブルでの接続を優先してください。
- ネットワークセキュリティ: コンテナがLAN上に「露出」するため、機密データを扱う場合は、アプリに対して
iptablesや内部ファイアウォールを設定してください。
実際、Home Assistantをデプロイした際に、笑えない失敗をしたことがあります。ip-range の制限を忘れたため、Dockerがゲートウェイであるルーターと全く同じIPを割り当ててしまったのです。たった一行の不注意なコマンドのせいで、オフィス全体が15分間インターネットに繋がらなくなりました。皆さんはそんな状況にならないよう気をつけてくださいね!
まとめ
Macvlanネットワークは、コンテナを内部ネットワーク内の独立した実体として扱いたい場合に最適なソリューションです。NATに関するトラブルを根本的に解決し、特にVoIP、メディアサーバー、監視システムなどで威力を発揮します。Bridgeよりも設定に手間はかかりますが、それによって得られるパフォーマンスと利便性は、苦労に見合う価値が十分にあります。

