グローバルルーティングテーブルの制限
標準的なLinuxネットワーキングはシンプルなルールに従います。すなわち、1つのメインルーティングテーブルと1つのデフォルトゲートウェイがあり、すべてのインターフェースがそのグローバルなリスト内のスペースを競い合います。この「一律」のアプローチは基本的なWebサーバーでは機能しますが、複雑なエンタープライズ環境では破綻します。
具体的なシナリオを考えてみましょう。あなたはVPN経由で2つの異なる支店を接続するゲートウェイを管理しているとします。両方の支店が内部のプリンターやNASデバイスに 192.168.1.0/24 サブネットを使用している場合、それらを接続するとカーネルで競合が発生します。
もし 192.168.1.50 にアクセスしようとした場合、どちらの支店がパケットを受け取るべきでしょうか?標準的なセットアップでは、2つ目のルートを追加すると、カーネルがパス間をフラッピング(激しく切り替わり)して50%のパケットロスが発生するか、あるいは片方の接続が単純に切断されます。歴史的には、iptables のマーキングやポリシーベースルーティング(PBR)で回避してきましたが、それらの設定は脆弱であり、デバッグが非常に困難であることで知られています。
VRF(Virtual Routing and Forwarding)は、ネットワーキングスタックを独立したルーティングインスタンスに分割することで、この問題を解決します。これは、1台の物理サーバーを複数の仮想ルーターに変えるようなものだと考えてください。各VRFは、独自のルーティングテーブル、インターフェース、およびデフォルトゲートウェイを保持します。
VRF vs. ネットワーク名前空間:軽量な代替案
Dockerを使用しているなら、ネットワーク名前空間(netns)をご存知でしょう。どちらも分離を提供しますが、動作する深度が異なります。名前空間は「サイロ」のような重厚な仕組みで、ファイアウォールやループバックデバイスを含むスタック全体を複製します。本質的には、ネットワークのためのコンテナです。
VRFははるかに局所的です。これはレイヤー3(ルーティング層)のみを分離します。すべてのVRFは、同じグローバルなファイアウォールルールとシステムリソースを共有します。このため、管理用トラフィック(SSH/SNMP)を本番データのトラフィックから分離するのに理想的な選択肢となります。20個もの異なる名前空間コンテキストを管理する複雑さなしに、必要な分離を実現できます。
VRF環境の構築
始める前に、Linuxカーネル 4.14 以降を実行していることを確認してください。サポート自体は 4.4 から始まりましたが、4.14 以降のリリースが本番環境に必要な安定性を提供します。また、iproute2 パッケージも必要です。
1. VRFデバイスの作成
LinuxはVRFを仮想ネットワークデバイスとして扱います。これを特定のルーティングテーブルIDに関連付ける必要があります。ここでは vrf-blue を作成し、テーブル100を割り当ててみましょう。
# VRFマスターデバイスを作成
sudo ip link add vrf-blue type vrf table 100
# インターフェースを有効化
sudo ip link set vrf-blue up
アクティブなVRFデバイスをリスト表示して、作業内容を確認します:
ip link show type vrf
2. インターフェースをVRFに所属させる
VRFデバイスは、物理または仮想インターフェースの「マスター」として機能します。インターフェースが所属(enslaved)されると、カーネルはそのインターフェースのトラフィックについて、グローバルテーブルを無視して具体的にテーブル100を参照するようになります。
eth1 がBlueクライアントに接続されていると仮定します:
# eth1をvrf-blueコンテキストに移動
sudo ip link set dev eth1 master vrf-blue
# インターフェースを移動するとIPが消えることが多いため、再割り当てします:
sudo ip addr add 192.168.1.5/24 dev eth1
sudo ip link set eth1 up
3. VRF内のルーティング
eth1 がVRF内にある場合、標準のルーティングコマンドでは認識されません。VRFコンテキストを指定する必要があります。構文を読みやすくするために vrf キーワードを使用します:
# Blueネットワークのデフォルトゲートウェイを設定
sudo ip route add default via 192.168.1.1 dev eth1 vrf vrf-blue
このインスタンスの特定のルーティングテーブルを監査するには、以下を実行します:
ip route show vrf vrf-blue
VRFコンテキストでのプロセス実行
ping 8.8.8.8 を実行しようとすると、おそらく失敗します。デフォルトでは、シェルはグローバルテーブルを使用するためです。プロセスにVRFのルーティングロジックを強制的に使用させるには、ip vrf exec を使用します。
# Blueルーティングテーブルを使用して接続をテスト
sudo ip vrf exec vrf-blue ping -c 3 8.8.8.8
このヘルパーは、プロセスのソケットをVRFデバイスにバインドします。これは、サーバーの残りの部分が別のネットワークで数ギガビットの本番トラフィックを処理している間に、特定のネットワークで管理用SSHインスタンスを実行するといった場合に大きな威力を発揮します。
サービスをVRFにバインドする
バックアップエージェントやSSHデーモンのような特定のサービスを、Blueネットワークのみで待機させる必要がある場合は、そのコンテキスト内で開始します:
sudo ip vrf exec vrf-blue /usr/sbin/sshd -D
本番環境から得られた教訓
数百台のエッジルーターにVRFをデプロイした結果、最も頻繁に発生する3つの問題があります。
- ループバックの制限: インターフェースは分離されますが、
127.0.0.1はグローバルのままです。異なるVRF内の2つのサービスが同じローカルホストポートにバインドしようとすると、衝突が発生します。 - カーネル設定: VRFでTCP/UDPソケットを正しく処理するには、特定の sysctl 調整が必要です。
net.ipv4.tcp_l3mdev_accept=1とnet.ipv4.udp_l3mdev_accept=1が設定されていることを確認してください。これにより、カーネルが着信パケットを正しいVRFテーブルに自動的にマッピングできるようになります。 - 永続化: 実行時の
ip linkコマンドは、再起動後に消失します。モダンなUbuntuシステムでは、Netplanのvrfs:キーを使用してください。古いDebianシステムでは、/etc/network/interfacesでVRFマスターとそのスレーブを定義します。
まとめ
LinuxのVRFは、基本的なルーティングと完全な仮想化の中間に位置する機能を提供します。名前空間や仮想マシンのようなCPUおよびメモリのオーバーヘッドなしに、IPの重複や厳格なトラフィック分離を処理するための、クリーンでスケーラブルな手法を提供します。VRFをマスターデバイスとして扱うことで、1台のサーバーを強力なマルチテナントルーターに変えることができます。

