「WebアプリをホストするVMへのアクセスを固定したいのだが、うまくいかない場合がある」という問い合わせがあった。この事象が解決したので、その原因と解決策をまとめておく。
環境および配置
問い合わせの事象が発生していた環境は以下の通り。問い合わせ主によると、この環境はオンプレミスからLiftしたもので、事象はGo live後しばらくして発生しはじめた、とのこと。マルチリージョン対応はしていない。
- Azure Load Balancer(以下、ALB)
- ネットワーク仮想アプライアンス(以下、NVA)
- L7 Load Balancer(以下、L7 LB)
- Reverse Proxy
- 仮想マシン(以下、VM)
- Web App
- データベース

問い合わせ主からのリクエストは、
cookieを使ってアクセス対象のWeb App(をホストするVM)を固定したい。追加開発にあまり費用を出せないので、低コストでsession affinityを実現したい。
というもの。平たく言うとcookieベースのsession affinityを構成したい、ということ。
Web AppはJava EEアプリケーションサーバでホストされているため、ふつうに考えるとアプリケーションサーバのクラスタリングやIn-memory data gridでセッション共有すればよいのだが、コスト低減のためクラスタリング構成できないEditionを使っていた。また、ALBにはsession affinity機能がないことは知っていたため、ALBの後段にL7 LBを配置してsession affinityを実現しようとしていた、ということだった。
この例での原因
おそらく、上図を見ただけで仮説が立つ人も多いはず。具体的には、以下のあたり。
- Public Load Balancer(以下、Public LB)へのトラフィックのsource IPが変化したのでは?具体的には、アクセス元でローカルIPからGlobal IPへNATした際にglobal IPが変化していないか?
- ALBではsession affinityを実現する機能はないから、もしsource IPが変わってしまったら宛先のWeb App(をホストするVM)が変わるはず。
- Reverse Proxyが何か悪さをしたのでは?
- session affinityを目的としてALBの後段に配置したL7 LBが期待した動作をしているか?例えば、Active-Active構成を取っているが、session情報はL7 LB両系で共有されていない、とか。
今回の事象は、以下が複合して発生していた。
- アクセス元(プロキシ&Firewallの背後でローカルIPを使っている環境)のlocal IPからのNAT後のglobal IPが以前のアクセスと変わっており、結果としてpublic LBへのトラフィックのsource IP(この場合、NAT後のglobal IP)が変化していた。
- ALBにはsession affinityの機能はなく、最も細かくてもsource IPとprotocolでしか判断できない。source IPが異なった(変わった)結果、異なるクライアントからのアクセスと判断し、前回とは異なるL7 LBにルーティングしていた。
- session affinityを目的としてALBの後段に配置されているActive-Active構成のL7 LBは、両系でsession情報が共有されておらず、一方のL7 LBを通過した情報は他方のL7 LBに共有されていなかった。別のL7 LBにトラフィックがルーティングされた場合、sessionの継続性を判断できず、異なるクライアントからのアクセスと判断していた。
なお、ALBの負荷分散規則は以下のドキュメントに記載がある。
Azure Load Balancer の分散モードを構成する / Configure the distribution mode for Azure Load Balancer
https://docs.microsoft.com/azure/load-balancer/load-balancer-distribution-mode
具体的には以下のような流れで、結果として所望の動作をしないケースが発生した。
構成 要素 | 発生しうる事象 |
---|---|
Public LB | 実際には同一クライアントからのアクセスにも関わらず、異なるglobal IPにNATされる場合がある。その場合、Public LBは異なるアクセス元からのアクセスと判断し、任意のL7 LBにトラフィックをルーティングする 結果として、前回のトラフィックルーティング先のL7 LBにトラフィックがルーティングされない可能性がある |
L7 LB | Active-Active構成 異なるL7 LBにルーティングされた場合、以前のトラフィック情報が共有されていないため、任意のReverse Proxyにトラフィックをルーティングする 結果として、前回のルーティング先のReverse Proxyにトラフィックがルーティングされない可能性がある |
Internal LB | 通過したReverse Proxyが以前と異なる場合、source IPが違うために異なるアクセス元からのトラフィックと判断し、任意のinternal L7 LBにトラフィックをルーティングする 結果として、前回のルーティング先のInternal L7 LBにトラフィックがルーティングされない可能性がある |
Internal L7 LB | Active-Active構成 これも先ほどのL7 LBと同様、異なるL7 LBにルーティングされた場合、以前のトラフィック情報を共有されていないため、任意のWeb App(をホストするVM)にトラフィックをルーティングする 結果として、前回のルーティング先のWeb App(をホストするVM)にトラフィックがルーティングされない可能性がある |
Web App | これまでのトラフィックルーティングの結果、偶然前回と同じVMへトラフィックがルーティングされる可能性もあれば、異なるVMへルーティングされる可能性もある |
対策
以下の置き換えを実施し、所望の動作をするようになった。
- Azure Application Gateway(以下、App GW)でALBとL7 LB、Reverse Proxyを置き換えた
- 以下のドキュメントに従い、App GWでcookieベースのsession affinityを有効にした
アプリケーション ゲートウェイで Cookie ベースのアフィニティを有効にする / Enable Cookie based affinity with an Application Gateway
https://docs.microsoft.com/azure/application-gateway/ingress-controller-cookie-affinity
構成変更後のトポロジーは以下の通り。

この構成により、cookieベースのsession affinityが機能するだけでなく、以下のようなメリットを享受できるようになった。
- L7 LBやReverse ProxyのNVAを使う必要がなくなったため、メンテナンス対象が減り、かつコストを減らすことができた
- メンテナンス対象が減ったため、オペレーションコストも低減した
その他
Public L7 LBとしてAzure Front Doorを使わなかった理由は、この問い合わせ主のシステムがマルチリージョン対応しておらず、グローバルサービスを使う理由がなかったから。
Azure Front Door Service とは / What is Azure Front Door Service?
https://docs.microsoft.com/azure/frontdoor/front-door-overview
今回はApp GWの機能でReverse Proxyに対する要件を賄うことができたが、Reverse Proxyに対する要件がApp GWの機能で賄いきれないものである場合、以下のような配置になる可能性もある。具体的には、認証のためのGatewayとしてのReverse Proxyが必要、とか。

まとめ
類似の事象では異なる解決策が適切な場合があるため、全てのケースにこの解決策があてはまるわけでない。ただ、クラウド移行にあたっては利用するサービスの機能を十分に理解し、機能を使い尽くして利用コンポーネント点数を減らす方向、つまりシンプルにするトポロジーを考えることが重要。
「Azure Load BalancerでSession affinityを構成したい」への1件のフィードバック