はじめに

この記事は、LVS(DRモード)を自前で構築したけど「LocalNodeを有効にしてもリクエストがリアルサーバーに流れてくれない!」という方に向けています。
記事を読むと「DRモードでディレクタとリアルサーバーを同一マシンにしたときのルーティングループ」「arp_ignore/arp_announceの意味」「ipvsadmでlocalnodeを有効にしてもダメな理由」が理解でき、最短で動作する構成を作れるようになります。

前提知識

  • IPネットワークの基礎(IPアドレス、サブネットマスク、ARP)
  • Linuxルーティングテーブルの基礎的な知識
  • LVSの3種のモード(NAT/TUN/DR)の違いをざっくり把握していること

DRモードLocalNodeが「動かない」とはどういうことか

DR(Direct Routing)モードではディレクタが受け取ったパケットをMAC層で書き換えてリアルサーバーに横流しします。
このとき「ディレクタとリアルサーバーを同一マシンにしよう」とすると、パケットはloopbackへ戻ってきます。
本来であればIPVSがそのパケットをキャッチしてアプリへ渡すべきですが、デフォルトのkernelパラメータではRPフィルタやARP制御が厳しく、パケットが到達しないというのが今回の現象です。

原因を特定するまでの調査手順と完全な設定方法

ステップ1:現状の確認と問題の切り分け

まずはipvsadm -LnでLocalNodeが有効になっているか確認します。

Bash
# ipvsadm -Ln TCP 10.0.0.10:80 wlc persistent 300 -> 127.0.0.1:80 Route 1 0 0

Routeの欄が1であればLocalNodeは有効ですが、これだけでは不十分です。
次にtcpdump -i lo port 80でloopbackにパケットが到達しているかを見ます。到達していなければ以下の2点を疑います。

  1. 送信元インターフェースのRPフィルタが有効
  2. 同一サブネットと見做されARP応答が抑制されている

ステップ2:kernelパラメータを正しく設定する

/etc/sysctl.d/99-lvs.confを作成し、以下を書き込みsysctl -pで反映します。

Bash
# RPフィルタを無効に net.ipv4.conf.all.rp_filter = 0 net.ipv4.conf.default.rp_filter = 0 net.ipv4.conf.eth0.rp_filter = 0 # 外向きインターフェース net.ipv4.conf.lo.rp_filter = 0 # ARPを制御 net.ipv4.conf.all.arp_ignore = 1 net.ipv4.conf.all.arp_announce = 2 net.ipv4.conf.lo.arp_ignore = 1 net.ipv4.conf.lo.arp_announce = 2 # 必要に応じて net.ipv4.ip_forward = 1

arp_ignore=1にしておくことで、VIP(10.0.0.10)へのARP要求に対してlo以外のインターフェースは応答しなくなり、ネットワーク上の他ホストが誤ってディレクタのMACを学習してしまうのを防げます。

ステップ3:ルーティングテーブルをクリーンアップ

DRモードではリアルサーバー側でもVIPを持つ必要がありますが、ディレクタ/リアルサーバー同一マシンではloopbackにVIPを割り当てるだけで十分です。

Bash
ip addr add 10.0.0.10/32 dev lo scope host

scope hostにしておくことで、他インターフェースからこのVIPが漏れないようにします。

ハマった点とエラー解決

  • 現象A: curl 10.0.0.10してもconnection refused
    → loopbackでLISTENしているアプリが127.0.0.1:80ではなく0.0.0.0:80で待ち受けている必要があります。
    アプリのバインドアドレスを見直しましょう。

  • 現象B: ipvsadm -LnInActConnが増えるだけ
    → リアルサーバー側のARP応答が他ホストに届いていて、クライアントが直接リアルサーバーに届いてしまっている。
    arp_ignore/arp_announceを再確認し、スイッチのMACテーブルもクリアしてみてください。

解決策まとめ

  1. LocalNodeを有効にしてもRPフィルタが有効だとパケットが捨てられる→rp_filter=0
  2. 同一マシンにVIPを持たせるときはloopbackにscope hostで追加
  3. ARPの返答を抑制して他ホストが誤学習しないようにarp_ignore=1,arp_announce=2
  4. アプリが0.0.0.0でLISTENしているかを確認

以上を守れば、DRモードでディレクタとリアルサーバーを同一マシンにしても、IPVSがきちんとパケットをキャッチし、LocalNodeが期待通り動作します。

まとめ

本記事では、LVS DRモードでLocalNodeを使いたいけど「パケットがloopbackに来ない」「接続できない」という壁にぶつかった方向けに、kernelパラメータの意味と正しい設定手順を解説しました。

  • RPフィルタを無効にしないとIPVSがパケットを見れない
  • ARPパラメータを調整しないと同一セグメント内でVIPが競合する
  • loopbackにVIPをscope hostで追加すれば他インターフェースにVIPが漏れない

この記事を通して、LVS DRモードの「なぜ動かないのか」を理解し、最短で運用可能な構成を構築できるようになりました。
次回は、Keepalivedを使ってこのLocalNode構成を冗長化する方法を紹介します。

参考資料