ブリッジを回避する:本番環境で Macvlan と Ipvlan に切り替えた理由

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

Docker ブリッジが限界に達するとき

多くのチームは、デフォルトの Docker ブリッジから使い始めます。セットアップが簡単で、すぐに動作するからです。しかし、その利便性には「NAT のオーバーヘッド」という隠れたコストが伴います。標準のブリッジは iptables とネットワークアドレス変換(NAT)を使用してトラフィックを制御しますが、このプロセスが CPU サイクルを消費し、無視できないレイテンシを引き起こします。

昨年、私たちのチームはある危機に直面しました。5万件以上の G.711 ストリームを同時に処理する VOIP クラスターで、パケットロスが発生し始めたのです。調査の結果、ボトルネックはブリッジドライバにあることが判明しました。パケット変換だけで、CPU 全体の 15% を消費していたのです。コンテナが物理ネットワークに直接アクセスできる方法が必要でした。Macvlan と Ipvlan に切り替えることで、中間層を排除し、ストリーミングサービスの安定性を取り戻すことができました。

ネットワークドライバの選択

Macvlan と Ipvlan はどちらも、コンテナを物理インターフェースに直接接続します。ホストのブリッジを完全にバイパスしますが、ハードウェアアドレスの処理方法が大きく異なります。選択を誤ると、ネットワークスイッチがダウンしたり、コンテナがブロックされたりする可能性があります。

Macvlan:コンテナごとに 1 つの MAC アドレス

Macvlan は、イーサネットケーブルの仮想的な分配器のようなものだと考えてください。各コンテナに固有の、ハードウェアのような MAC アドレスを割り当てます。物理スイッチから見ると、各コンテナはポートに接続された個別のサーバーのように見えます。これは、専用のネットワーク ID を必要とするレガシーアプリケーションに最適です。

ほとんどのデプロイメントでは、Bridge モードを使用しています。これにより、同じホスト上のコンテナ同士が通信できるようになります。ただし、注意が必要です。多くのエンタープライズスイッチには「ポートセキュリティ」制限があります。1 つのホストで 200 個のコンテナを起動すると、スイッチが 1 つのポートに 200 個ের MAC アドレスを検出し、なりすまし攻撃を防ぐためにポートをシャットダウンしてしまう可能性があります。

Ipvlan:高密度な環境向けのソリューション

Ipvlan は、MAC アドレスの制限に対する現代的な解決策です。一意の ID の代わりに、すべてのコンテナがホストマシンの物理 MAC アドレスを共有します。レイヤー 3 の IP アドレスを使用してトラフィックを識別するため、ネットワークハードウェアへの負荷が大幅に軽減されます。

Ipvlan には主に 2 つのモードがあります:

  • L2 (Layer 2): Macvlan のように動作しますが、MAC アドレスを共有します。ARP やブロードキャストも処理します。
  • L3 (Layer 3): ルーターのように動作します。ARP を処理しないため、ブロードキャストノイズがパフォーマンスを低下させがちな大規模クラスターにおいて、非常に効率的です。

Macvlan の設定

データベースノードの実際の構成例を見てみましょう。物理インターフェースを eth0、サブネットを 192.168.1.0/24 と仮定します。

# ネットワークを作成
docker network create -d macvlan \
  --subnet=192.168.1.0/24 \
  --gateway=192.168.1.1 \
  -o parent=eth0 my_macvlan_net

# 固定 IP でコンテナを起動
docker run -d \
  --name db_node \
  --network my_macvlan_net \
  --ip 192.168.1.50 \
  postgres:15

コンテナは現在「ネットワーク上に直接」存在しています。ポートフォワーディングを設定しなくても、オフィスネットワーク内のどのデバイスからも 192.168.1.50 に ping を送信できます。

Ipvlan L2 のデプロイ

Cisco スイッチに負荷をかけすぎないよう、モニタリングエージェントを Ipvlan に切り替えました。設定はほぼ同一ですが、ipvlan ドライバを使用します。これにより、物理サーバーあたりの MAC アドレス数を正確に 1 つに保つことができます。

# Ipvlan L2 ネットワークを作成
docker network create -d ipvlan \
  --subnet=192.168.1.0/24 \
  --gateway=192.168.1.1 \
  -o ipvlan_mode=l2 \
  -o parent=eth0 my_ipvlan_net

# コンテナをデプロイ
docker run -d \
  --network my_ipvlan_net \
  --ip 192.168.1.60 \
  alpine sleep infinity

ホストで tcpdump を実行すると、.60 からのパケットがホストの MAC アドレスを使用していることがわかります。これは、ネットワークインフラチームが監視を行う際にも非常にクリーンな状態です。

隔離の壁

多くのエンジニアが陥りやすい特有の挙動があります。デフォルトでは、ホストは自身の Macvlan または Ipvlan コンテナと通信できません。Linux カーネルがトラフィックループを防ぐためにそれらを隔離しているからです。Prometheus のスクレイピングなどでホストからコンテナにアクセスする必要がある場合は、ホスト側に仮想リンクを作成する必要があります。

次のコマンドを使用して、そのギャップを解消します:

# ホスト上にサブインターフェースを作成
ip link add macvlan_bridge link eth0 type macvlan mode bridge

# IP を割り当てて有効化
ip addr add 192.168.1.250/24 dev macvlan_bridge
ip link set macvlan_bridge up

# サブインターフェース経由でコンテナへのトラフィックをルーティング
ip route add 192.168.1.50 dev macvlan_bridge

本番環境での結論

この構成で 6 か月間運用した結果、パフォーマンスの向上は疑いようもありません。データストリーミングアプリのレイテンシは 1.1ms から約 0.3ms に低下しました。

次のような場合は Macvlan を継続してください:

  • DHCP やライセンスソフトウェアのために一意の MAC アドレスが必要な場合。
  • 少数のコンテナ(ポートあたり 50 未満)を運用している場合.
  • 外部からの可視性を最もシンプルに確保したい場合。

次のような場合は Ipvlan を選択してください:

  • 1 つのホストで数百ものコンテナにスケールさせる場合。
  • ネットワークスイッチに複数の MAC アドレスに関する厳格なセキュリティポリシーがある場合。
  • AWS や GCP などのパブリッククラウド環境で、仮想 MAC アドレスがブロックされている場合。

最後に

Docker ブリッジをやめることは、ネットワークの制約を取り払うようなものです。初期設定、特にホストとの通信には入念な計画が必要ですが、得られるパフォーマンスと可視性にはそれだけの価値があります。CPU 使用率の高さや複雑なルーティングテーブルに悩まされているなら、コンテナを物理ネットワークに直接配置することを検討すべき時かもしれません。

Share: