Lua は、軽量で効率的なスクリプト言語です。ゲートウェイ開発では、Lua を使用して、API ゲートウェイ、メッセージゲートウェイ、リバースプロキシなど、さまざまなゲートウェイプログラムを作成および実行できます。Lua スクリプトを使用すると、開発者はリクエストルーティング、フィルタリング、認証などの機能を実装し、カスタム処理を実行できます。Lua を Nginx や Envoy などのプロキシに埋め込んで、リクエストと応答を処理したり、ログを出力したり、その他のカスタム操作を実行したりできます。このトピックでは、Envoy プロキシで Lua スクリプトを使用してリクエストと応答を処理し、それらのヘッダーと本文をログとして出力する方法について説明します。
制限事項
MSE クラウドネイティブゲートウェイのバージョンが 1.2.11 以降である必要があります。
セキュリティ上の理由から、MSE クラウドネイティブゲートウェイは、デフォルトで次の Lua ライブラリと関数を無効にします。
debug.debug
debug.getfenv
debug.getregistry
dofile
io
loadfile
os.execute
os.getenv
os.remove
os.rename
os.tmpname
ルーティングルールの構成
MSE コンソールにログインし、上部のナビゲーションバーでリージョンを選択します。
左側のナビゲーションウィンドウで、Cloud-Native Gateway > ゲートウェイリスト を選択します。[ゲートウェイ] ページで、ゲートウェイの ID をクリックします。
[ゲートウェイ詳細] ページの左側のナビゲーションウィンドウで、Plug-in Marketplace をクリックします。
All Plug-ins > Custom タブで、[lua] リソースカードをクリックします。
[プラグイン構成] タブで、ルールの適用レベルを選択し、ルールを構成できます。
説明ゲートウェイに送信されるすべてのリクエストは、ルートレベル、ドメインレベル、インスタンスレベルの順にプラグインルールと照合されます。
ルートレベルのプラグインルール
[ルールを作成] をクリックします。表示されたページで、スイッチをオンにし、ターゲットルートを選択して、[ルールの構成] エディターに Lua スクリプトを入力します。
構成が完了したら、[OK] をクリックします。
ドメインレベルのプラグインルール
[ルールを作成] をクリックします。表示されたパネルで、スイッチをオンにし、ターゲットドメイン名を選択して、[ルールの構成] エディターに Lua スクリプトを入力します。
重要Lua プラグインルールは、アスタリスク (*) を含むドメイン名をサポートしていません。
構成が完了したら、[OK] をクリックします。
インスタンスレベルのプラグインルール
インスタンスレベルのプラグインルールは、デフォルトで Lua プラグイン用に構成されています。ルールを編集するには、まず編集ロックを無効にする必要があります。
スイッチを有効にし、[ルールの構成] エディターに Lua スクリプトを入力します。
完了したら、[保存] をクリックします。
API リファレンス
クラウドネイティブゲートウェイが提供する Lua API の詳細については、「Lua」をご参照ください。
シリアル化または逆シリアル化中にエラーが発生した場合、Lua はエラー関数を呼び出してエラーをスローし、現在のプロセスを停止します。
一般的なユースケース
完全なリクエストと応答の情報をプラグインログに出力する
ルーティングルールを構成する際に、次の Lua コードを使用します。
このコードは、次の
content-type値のリクエスト本文と応答本文のみを出力します。本文は 1024 バイト (1 KB) を超えることはできません。application/x-www-form-urlencoded
application/json
text/plain
local maxBodySize = 1024 function check_content_readable(type) if type == nil then return false end if string.find(type, "application/x-www-form-urlencoded",1,true) or string.find(type, "application/json",1,true) or string.find(type, "text/plain",1,true) then return true end return false end function envoy_on_request(request_handle) local headers = request_handle:headers() local headersStr = "" local contentType for key, value in pairs(headers) do if key == "content-type" then contentType = value end headersStr = headersStr .. key .. "=" .. value .. ", " end request_handle:streamInfo():dynamicMetadata():set("envoy.lua","request_headers",headersStr) local requestBody = "" if check_content_readable(contentType) then for chunk in request_handle:bodyChunks() do if (chunk:length() > 0) then requestBody = requestBody .. chunk:getBytes(0, chunk:length()) end if (#requestBody > maxBodySize) then requestBody = requestBody .. "<truncated>" break end end end request_handle:streamInfo():dynamicMetadata():set("envoy.lua","request_body",string.gsub(requestBody,"\n","\\n")) end function envoy_on_response(response_handle) local headers = response_handle:headers() local headersStr = "" local contentType local contentEncoding = false for key, value in pairs(headers) do if key == "content-type" then contentType = value elseif key == "content-encoding" then contentEncoding = true end headersStr = headersStr .. key .. "=" .. value .. ", " end local responseBody = "" if check_content_readable(contentType) and not contentEncoding then for chunk in response_handle:bodyChunks() do if (chunk:length() > 0) then responseBody = responseBody .. chunk:getBytes(0, chunk:length()) end if (#responseBody > maxBodySize) then responseBody = responseBody .. "<truncated>" break end end end local reqHeaders = "" local reqBody = "" local metadata = response_handle:streamInfo():dynamicMetadata():get("envoy.lua") if metadata ~= nil then local headers = response_handle:streamInfo():dynamicMetadata():get("envoy.lua")["request_headers"] if headers ~= nil then reqHeaders = headers end local body = response_handle:streamInfo():dynamicMetadata():get("envoy.lua")["request_body"] if body ~= nil then reqBody = body end end response_handle:logInfo("request Headers: [" .. reqHeaders .. "] request Body: [" .. string.gsub(reqBody,"\n","\\n") .. "] response Headers: [" .. headersStr .. "] response Body: [" .. string.gsub(responseBody,"\n","\\n") .. "]") endプラグインログを表示します。
この機能を使用するには、ゲートウェイプラグインのログ配信を有効にする必要があります。有効になっていない場合は、[ログ配信を有効にする] をクリックします。有効にすると、プラグインログは Simple Log Service (SLS) に配信され、ページで表示できます。次の図に示すように、アクセスログの
request-idを使用して、Lua プラグインログで完全なリクエストと応答の情報を見つけることができます。
アクセスログに完全なリクエストと応答の情報を追加する
ルーティングルールを構成する際に、次の Lua コードを使用します。
ゲートウェイのアクセスログパラメーターは、カスタム動的メタデータをサポートしています。まず、プラグインでメタデータを定義する必要があります。次のコードは、リクエストヘッダー、リクエストボディ、レスポンスヘッダー、レスポンスボディに対応する 4 つのメタデータフィールドを定義します:
envoy.lua:request_headers
envoy.lua:request_body
envoy.lua:response_headers
envoy.lua:response_body
local maxBodySize = 1024 function check_content_readable(type) if type == nil then return false end if string.find(type, "application/x-www-form-urlencoded",1,true) or string.find(type, "application/json",1,true) or string.find(type, "text/plain",1,true) then return true end return false end function envoy_on_request(request_handle) local headers = request_handle:headers() local headersStr = "" local contentType for key, value in pairs(headers) do if key == "content-type" then contentType = value end headersStr = headersStr .. key .. "=" .. value .. ", " end request_handle:streamInfo():dynamicMetadata():set("envoy.lua","request_headers",headersStr) local requestBody = "" if check_content_readable(contentType) then for chunk in request_handle:bodyChunks() do if (chunk:length() > 0) then requestBody = requestBody .. chunk:getBytes(0, chunk:length()) end if (#requestBody > maxBodySize) then requestBody = requestBody .. "<truncated>" break end end end request_handle:streamInfo():dynamicMetadata():set("envoy.lua","request_body",string.gsub(requestBody,"\n","\\n")) end function envoy_on_response(response_handle) local headers = response_handle:headers() local headersStr = "" local contentType local contentEncoding = false for key, value in pairs(headers) do if key == "content-type" then contentType = value elseif key == "content-encoding" then contentEncoding = true end headersStr = headersStr .. key .. "=" .. value .. ", " end response_handle:streamInfo():dynamicMetadata():set("envoy.lua","response_headers",headersStr) local responseBody = "" if check_content_readable(contentType) and not contentEncoding then for chunk in response_handle:bodyChunks() do if (chunk:length() > 0) then responseBody = responseBody .. chunk:getBytes(0, chunk:length()) end if (#responseBody > maxBodySize) then responseBody = responseBody .. "<truncated>" break end end end response_handle:streamInfo():dynamicMetadata():set("envoy.lua","response_body",string.gsub(responseBody,"\n","\\n")) endログフォーマットを調整します。
ゲートウェイインスタンスの左側のナビゲーションウィンドウで、[パラメーター設定] をクリックし、次に [デフォルトフォーマット (クリックしてカスタマイズ)] をクリックします。対応するメタデータをカスタムログフィールドに追加します。その後、アクセスログでメタデータを表示できます。
