はじめに
この記事は、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点を疑います。
- 送信元インターフェースのRPフィルタが有効
- 同一サブネットと見做され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を割り当てるだけで十分です。
Baship 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 -LnのInActConnが増えるだけ
→ リアルサーバー側のARP応答が他ホストに届いていて、クライアントが直接リアルサーバーに届いてしまっている。
arp_ignore/arp_announceを再確認し、スイッチのMACテーブルもクリアしてみてください。
解決策まとめ
- LocalNodeを有効にしてもRPフィルタが有効だとパケットが捨てられる→
rp_filter=0 - 同一マシンにVIPを持たせるときはloopbackに
scope hostで追加 - ARPの返答を抑制して他ホストが誤学習しないように
arp_ignore=1,arp_announce=2 - アプリが
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構成を冗長化する方法を紹介します。
参考資料
- The Linux Virtual Server Project - DR Mode
- Red Hat Enterprise Linux 9 - Configuring kernel parameters for LVS
- ipvsadm(8) man page
