ネットワークエンジニアのITブログ

長らくネットワークで生活してきましたが、ここ数年クラウドとサーバー系に触れる機会が増えて、日々成長しています。最近のお気に入りはNSXALBとGoogle Cloud。

DataScriptでURIによる負荷分散を行う

今までの負荷分散は一意のFQDNへのアクセスに対して、複数のサーバへ負荷分散を行ってきましたが、ユーザーによりURIが指定されている場合、URIの文字列によって対象のサーバを指定する方法を紹介します。
BIG-IPなどでは、iRuleにより実現していましたが、NSXALBだとDataScriptを使用します。

ネットワーク構成

ネットワーク構成は、TerraformでVSを作成したcent71、cent72のサーバを利用します。
hironw.hatenablog.com

VS、Pool、サーバの接続イメージは以下のようになります。
負荷分散対象のサーバ2台に対して、URIに「/test01/」が含まれている場合は「pool_cent71」へ、URIに「/test02/」が含まれている場合は「pool_cent72」へ転送します。

Poolの作成

まずは、Poolとサーバの組み合わせを以下のような構成でPoolを作成します。
Name:pool_cent71
Default Server Port:80
Server Name:192.168.10.71
IP Address:192.168.10.71
Health Monitors:System-HTTP



同様に、pool_cent72のPoolも作成します。
Name:pool_cent72
Default Server Port:80
Server Name:192.168.10.72
IP Address:192.168.10.72
Health Monitors:System-HTTP

VIPの作成

VIPとして192.168.3.72を作成します。

DataScriptの作成

URIによる負荷分散は、DataScripにより実現するため、スクリプトを作成します。
[Templates]-[Scripts]-[DataScripts]から「CREATE」を選択します。

以下の内容で設定を行います。
Name:Test-Datascript
Pools:pool_cent71、pool_cent72

[Events]-[ADD]から「HTTP Request」を選択し、スクリプトを貼り付けます。

POOL_01                   = "pool_cent71"
POOL_02                   = "pool_cent72"
PATH_01                   = "/test01/"
PATH_02                   = "/test02/"
path                      = avi.http.get_path()
POOL_01_up, POOL_01_total = avi.pool.get_servers(POOL_01)
POOL_02_up, POOL_02_total = avi.pool.get_servers(POOL_02)
UserAgent                 = avi.http.get_header("user-agent")
-- ----------------------------------------------------------
if string.beginswith(path, "index.html") and UserAgent == "avi/1.0" then
   if (POOL_01_up >= 1) or (POOL_02_up >= 1)then
      avi.http.response(200)
   else
      avi.http.response(503)
   end
elseif string.contains(path, PATH_01) then
   avi.vs.log("LOG1: path hit! " .. path)
   avi.pool.select(POOL_01)
elseif string.contains(path, PATH_02) then
   avi.vs.log("LOG2: path hit! " .. path)
   avi.pool.select(POOL_02)
else
   avi.vs.log("LOG3: path not hit!" .. path)
   avi.http.close_conn()
end

DataScriptの処理について説明していきます。
最初の「if string.beginswith(path, "index.html") and UserAgent == "avi/1.0"」は、beginswith(path, "index.html")関数で取得したpathが、「index.html」で始まる場合かつ、UserAgentが「avi/1.0」である場合という条件になり、これは、SEからのヘルスチェックが対象になります。
「 if (POOL_01_up >= 1) or (POOL_02_up >= 1)then」は、2台のサーバのいずれかのPoolがUPしていた場合となり、ヘルスチェックの結果を条件としています。
「avi.http.response(200)」は条件にマッチした場合、Response Code 「200」を返し、「avi.http.response(503)」はどちらのPoolもDOWNしていた場合、Response Code 「503」を返します。

「elseif string.contains(path, PATH_01) then」は、ヘルスチェックでないアクセスが来た場合で、「string.contains(path, PATH_01)」関数で取得したpathに、「/test01/」が含まれていた場合という条件になります。
条件にマッチした場合、「avi.vs.log("LOG1: path hit! " .. path)」で指定した文字列をログに出力し、「avi.pool.select(POOL_01)」で「pool_cent71」に転送します。
同様に、「/test02/」が含まれていた場合は、「pool_cent72」に転送します。

いずれの文字列も含んでいなかった場合は、「avi.http.close_conn()」でコネクションをクローズします。

VSの作成

ここまで作成してきた、Pool、VIP、DataScripを組み合わせ、以下のパラメータでVSを作成します。
VSを新規作成し、以下の内容を入力したら、「NEXT」を選択します。
Name:VS_Datascript_URI
VS VIP:vip_192.168.3.72
Services:80
TCP/UDP Profile:System-TCP-Proxy
Application Profile:System-HTTP

[Polices]-[DataScripts]から「Add DataScript」を選択します。

作成した「Test-Datascript」を選択し「NEXT」を選択します。

後は特に変更はせず、「NEXT」→「SAVE」を選択します。

動作確認

ブラウザから「http://192.168.3.72/test01/start.html」にアクセスするとcent71のページが表示され、「http://192.168.3.72/test02/start.html」にアクセスするとcent72のページが表示され、URIにより対象サーバへ転送していることの確認ができました。

DataScriptによる負荷分散の紹介は以上です。