ロード・バランサのルーティング・ポリシー言語

ロード・バランサのルーティング動作をガイドするルーティング・ポリシー条件ステートメントを記述する方法について学習します。

Webサーバーなどのリソースに受信リクエストをルーティングする方法を制御するには、ポリシーを作成する必要があります。これらのポリシーには、「これが発生した場合、トラフィックをバックエンド・セットに転送する」という一般的な形式があります。バックエンド・セットは、すでに作成済ある必要があります。

ルーティング・ポリシーは、次のように動作します:

  • 各HTTPリクエストは、ルールに対して評価されます。

  • ルールは、ポリシーで定義された順序で実行されます。

  • 各ルールには、少なくとも1つの条件とバックエンド・セットがあります。

  • HTTPリクエスト条件がルールに一致すると、リクエストはルールに定義されているバックエンド・セットに転送されます。ポリシー内の他のルールはスキップされ、リクエストはそれらに対して評価されません。

例: 1つのパス・ルール

次に、パスベースのルールが1つのみ含まれるルーティング・ポリシー・ルール・セットの例を示します:

{
  "name": "BasicPathBasedPolicy",
  "conditionLanguageVersion": "V1",
  "rules": [
    {
      "name": "Documents_rule",
      "condition" : "any(http.request.url.path eq (i '/documents'))",
      "actions": [{
        "name": "FORWARD_TO_BACKENDSET",
        "backendSetName": "backendSetForDocuments"
      }]
    }
  ]
}

この例は、次の要素を示しています:

  • ルール・セットは中カッコ{ }で囲まれ、ルール・セットの名前、言語バージョン番号、およびルールのセットの名前が含まれます。

  • 例のルール・セット名は"BasicPathBasedPolicy"です。セット内のルールは角カッコ内に含まれます。

  • セット内の唯一のルールは、"Documents_rule"という名前です。

  • ルールの条件は、anyの条件が満たされた場合、"actions"のアクションを実行することを意味しています。

  • 条件では、受信HTTPリクエストURLパスが/documentsと比較されます。比較のeqは、等しいことを意味しており、=と記述することもできます。

  • 条件文(i '/documents')は、'/documents'の大/小文字を区別しないことを宣言します。

  • 条件が満たされると、アクションが実行され、リクエストが特定のバックエンド・セット(この場合は"backendSetForDocuments")に転送されます。ルールを有効にするには、このバックエンド・セットが存在する必要があります。

このルールは、「リクエストされたURLパスが/documentsに完全一致した場合、リクエストをバックエンド・セットbackendSetForDocumentsに転送する」と言い換えることができます。

例: 2つの単純なパス・ルール

次に、単純なパスベースのルールが2つ含まれるルーティング・ポリシー・ルール・セットの例を示します。受信問合せは、リクエストURLパスに基づいて異なるバックエンド・セットに送信され、最初の条件または2番目の条件のいずれかが満たされると転送が発生します。複数のルールはポリシー内の順序で評価されます。問合せがこれらの両方の条件に一致した場合、アクションは一致した最初の条件に基づいて実行され、2番目の一致はスキップされます。

{
  "name": "PathBasedPolicy",
  "conditionLanguageVersion": "V1",
  "rules": [
    {
      "name": "Documents_rule",
      "condition" : "any(http.request.url.path eq (i '/documents'))",
      "actions": [{
        "name": "FORWARD_TO_BACKENDSET",
        "backendSetName": "backendSetForDocuments"
      }]
    },
    {
      "name": "Videos_rule",
      "condition" : "any(http.request.url.path eq (i '/videos'))",
      "actions": [{
        "name": "FORWARD_TO_BACKENDSET",
        "backendSetName": "backendSetForVideos"
      }]
    }
  ]
}

例: 2つの条件を持つ1つのルール

次のポリシーには、2つの条件を持つ1つのルールがあります(各条件はカンマで区切られます)。最初の条件はリクエスト・ヘッダーを調査し、2番目の条件はリクエストの問合せ文字列を調査します:

      {
        "name": "Example_policy",
        "conditionLanguageVersion": "V1",
        "rules": [
          {
            "name": "HR_mobile_user_rule",
            "condition" : "all(http.request.headers[(i 'user-agent')] eq (i 'mobile'), http.request.url.query['department'] eq 'HR')",
            "actions": [{
              "name": "FORWARD_TO_BACKENDSET",
              "backendSetName": "backendSetForHRMobileUsers"
            }]
          }
        ]
      }

このルールは、allキーワードで始まるため、2つの条件が両方ともtrueの場合にリクエストがバックエンド・セットに転送されます。ルールの条件は、「ヘッダーでリクエストされたuser-agent値がmobileに設定されており、ヘッダーのdepartment値がHRである場合、指定したバックエンド・セットに転送する」と言い換えることができます。

例: 2つのルール

最後の例は、2つのルールを示しています。各ルールに異なるアクションがあり、両方のルールに2つの条件があります。重要なことは、2番目のルールがキーワードanyで始まることです。つまり、アクションをトリガーするには、2つの条件のうち1つのみがtrueである必要があります。3つ以上の条件を指定した場合、それらのうちいずれか1つがtrueであれば、アクションがトリガーされます。

      {
        "name": "Example_policy",
        "conditionLanguageVersion": "V1",
        "rules": [
          {
            "name": "HR_mobile_user_rule",
            "condition" : "all(http.request.headers[(i 'user-agent')] eq (i 'mobile'), http.request.url.query['department'] eq 'HR')",
            "actions": [{
              "name": "FORWARD_TO_BACKENDSET",
              "backendSetName": "backendSetForHRMobileUsers"
            }]
          },
          {
            "name": "Documents_rule",
            "condition" : "any(http.request.url.path eq (i '/documents'), http.request.headers[(i 'host')] eq 'doc.myapp.com')",
            "actions": [{
              "name": "FORWARD_TO_BACKENDSET"
              "backendSetName": "backendSetForDocuments"
            }]
          }
        ]
      }

ルール条件

ロード・バランサ・リソースのルーティング・ポリシー言語のルール条件について学習します。

ルール条件は述語の形式で記述されます。コンビネータを使用して、1つの条件で複数の述語を使用できます。any()all()の2つのコンビネータは、論理ORまたはANDのように動作します。コンビネータの前にキーワードnotを配置して、コンビネータを否定することもできます。単純な述語は次のように表すことができます:

left value matcher right value

HTTPリクエストURLパスが/foo/barで始まる場合に一致する必要があるルールの条件は:

http.request.url.path sw '/foo/bar'

使用可能なマッチャの詳細は、マッチャを参照してください。

使用可能な変数の詳細は、変数を参照してください。

複数の述語の構文

not? any|all(<condition>,<condition>,...)

例:

all(http.request.url.path sw '/foo', 'bar' in (http.request.url.query))

条件の例

次に、条件の使用方法の追加例を示します。正確な構文および機能の詳細を示します。

  • URLパスが"/category/element"で始まる場合にHTTPリクエストを一致させるには:

    http.request.url.path sw '/category/element'
  • URLパスが"/category"で始まるか"/id"で終わる場合にHTTPリクエストを一致させるには:

    any(http.request.url.path sw '/category', http.request.url.path ew '/id')
  • "User-Agent"リクエスト・ヘッダーが存在する場合にHTTPリクエストを一致させるには:

    (i 'User-Agent') in (http.request.headers)
  • ヘッダー"User-Agent"の値が"Some User Agent"である場合にHTTPリクエストを一致させるには:

    http.request.headers[(i 'User-Agent')] eq 'Some User Agent'
  • URL問合せ文字列に大/小文字が区別されるキー"search"がある場合(URL https://www.example.com/category/?search=item+foo%20bar&page=1など)にHTTPリクエストを一致させるには

    'search' in (http.request.url.query)
  • URL問合せ文字列の大/小文字が区別されるキー"search" (大/小文字区別あり)に大/小文字が区別されない値"item+foo%20bar"がある場合(URL https://www.domain.com/category/?search=item+foo%20bar&page=1など)にHTTPリクエストを一致させるには
    http.request.url.query['search'] = (i 'item foo bar')

    URL問合せ(キーと値の両方)の照合は、その値のURLエスケープされていないバージョンを使用して実行する必要があります。

  • "tastycookie"という名前のCookieに対するHTTPリクエストを大/小文字の区別なしで一致させるには:

    (i 'tastycookie') in (http.request.cookies)
  • 大/小文字が区別される値"strawberry"を含む"tastycookie"という名前のCookieに対するHTTPリクエストを大/小文字の区別なしで一致させるには:

    http.request.cookies[(i 'tastycookie')] = 'strawberry'

マッチャ

ロード・バランサ・リソースのルーティング・ポリシー言語でマッチャを使用する方法について学習します。

条件では複数のマッチャを使用できます。

文字列マッチャ

次の表に、文字列値を操作するマッチャを示します。一部のマッチャには代替バリアントがあり、どのバリアントもそのマッチャで同じ意味で使用できます。

各マッチャの例はすべて、'/category/element/id'を含むhttp.request.url.pathに一致します:

名前

代替

説明

eq

= 、== 、等しい、等しい

マッチャの左側の値と右側の値が等しい場合に一致します。

http.request.url.path eq "/category/element/id"

イチモツ

左側の値が右側の値で終わる場合に一致します。

http.request.url.path ew '/id'

sw

左側の値が右側の値で始まる場合に一致します。

http.request.url.path sw '/category'

なし

!=、not equal、not equals

マッチャの左側の値と右側の値が等しくない場合に一致します。

http.request.url.path neq '/some/other/path'

いいえ

左側の値が右側の値で終わらない場合に一致します。

http.request.url.path not ew '/not_id'

not sw

左側の値が右側の値で始まらない場合に一致します。

http.request.url.path not sw '/not_category'

部分マッチャ

ルールで使用される一部の変数には、ルール実行時のデータの任意のキー/値マップが含まれます。たとえば、http.request.headersにはHTTPリクエスト・ヘッダーが含まれます。使用可能なマップの詳細は、変数を参照してください。

マッチャのinおよびnot inを使用して、マップ変数に特定のキーが含まれているかどうかを確認できます。これは、キーが実際に表す変数の内容によって決まります。

マップ変数に特定のキーが含まれているかどうかを確認するための構文は:

<key> in (<map variable>)
  • <key>は、大/小文字が区別される文字列または大/小文字が区別されない文字列である必要があります。

  • 右側の値はカッコ内に配置する必要があります。

たとえば、HTTPリクエストに'Foo'という名前のCookieが含まれる場合、次の条件は一致します:

'Foo' in (http.request.cookies)

ロード・バランサ・リソースのルーティング・ポリシー言語で値を使用する方法について学習します。

述語で使用される値は、定数値または実行時に評価される変数のいずれかです。

定数

ロード・バランサ・リソースのルーティング・ポリシー言語の値に関連付けられた定数について学習します。

ルールは、一重引用符の間に記述された文字列定数をサポートします。

例:

http.request.url.path sw '/foo'

文字列の大/小文字区別

文字列の一致では、デフォルトで大/小文字が区別される比較が使用されます。

たとえば、あるリクエストのHTTPリクエストURLパスが/fooの場合、大/小文字が区別される文字列比較が使用されるため、次の述語はそのリクエストに対して一致しません:

http.request.url.path eq '/FOO'

比較される値の少なくとも1つが大/小文字が区別されない文字列の場合、大/小文字が区別されない照合が実行されます。大/小文字が区別されない文字列の構文は:

(i '<string content>')

たとえば、次の文字列はすべて大/小文字が区別されないため、述語で使用された場合は等価です:

(i 'foo')
(i 'Foo')
(i 'FOO')

元の例と比較すると、次の述語は、大/小文字が区別されない比較が使用されるため一致します:

http.request.url.path eq (i '/FOO')

変数

ロード・バランサ・リソースのルーティング・ポリシー言語の値に関連付けられた変数について学習します。

変数は、HTTPリクエストの特定の値に対して照合する条件で使用されます。各変数の実際の値は、ルールの実行時、つまり個々のHTTPリクエストの処理中に決定されます。

マップ・タイプ変数

一部の変数には、リクエスト・ヘッダーやCookieなど、リクエスト・データの任意のキー/値マップが含まれます。キーごとに、1つ以上の値を指定できます。たとえば、同じ名前の複数のリクエスト・ヘッダーが存在する場合があります。

通常、マップ変数は、次のようにルールで使用できます:

  • マップに特定のキーがあるかどうかをチェックします。

  • マップに特定の値を持つ特定のキーがあるかどうかをチェックします。

マップに特定のキーがあるかどうかのチェック:

マップ変数に特定のキーがあるかどうかをチェックするには、inマッチャを使用します。詳細は、ロード・バランサのルーティング・ポリシー言語を参照してください。

例:

'Foo' in (http.request.cookies)

HTTPリクエストに'Foo'という名前のCookieが含まれる場合、この条件は一致します。

マップに特定の値を持つ特定のキーがあるかどうかのチェック:

マップに特定の値を持つ特定のキーがあるかどうかをチェックするには、大カッコ[]表記法を使用して特定のキーの値を取得します。大カッコ表記法を使用するための構文は:

<variable>[<key>]

<key>は、大/小文字が区別される文字列または大/小文字が区別されない文字列として指定する必要があります。

特定の値の実際のチェックは、eqマッチャを使用して、そのキーのいずれかの値がその特定の値と等しいかどうかをチェックします。述語が一致するのは、そのキーの少なくとも1つの値がその特定の値と一致した場合です。

例:

  • ヘッダー"header-name"のいずれかの値が"header-value"と等しい場合に一致させるには:

    http.request.headers[(i 'header-name')] eq 'header-value'

    ヘッダーは大/小文字の区別なしで比較されますが、ヘッダーは大/小文字の区別ありで比較されます。

  • Cookieの"cookie-name"の値が'cookie-value'と等しい場合に一致させるには:

    http.request.cookies['cookie-name'] eq 'cookie-value'

not eqマッチャを使用すると、そのキーのどの値も特定の値と等しくないことをチェックできます。

例:

  • ヘッダー"header-name"のどの値も"header-value"と等しくない場合に一致させるには:

    http.request.headers[(i 'header-name')] not eq 'header-value'

    ヘッダー名は大/小文字の区別なしで比較されます。ヘッダー値は大/小文字の区別ありで比較されます。

  • Cookieの"cookie-name"のどの値も'cookie-value'と等しくない場合に一致させるには:

    http.request.cookies['cookie-name'] not eq 'cookie-value'

使用可能なすべての変数

条件で使用可能な変数は:

名前

説明

http.request.headers

HTTPリクエスト・ヘッダーを含むマップ。

このマップにはいくつかの特別な動作があります。キー(ヘッダー名)は、大/小文字が区別されない文字列である必要があります。述語のhttp.request.headersキーに大/小文字が区別される文字列は使用できません。

  • 正しい使用方法:

    (i 'User-Agent') in http.request.headers
    http.request.headers[(i 'User-Agent')] = 'Mobile'
  • 誤った使用方法:

    'User-Agent' in http.request.headers
    http.request.headers['User-Agent'] = 'Foo'

http.request.url.path

HTTPリクエストURLパス。これは、プロトコル、ドメイン、ポートおよび問合せ文字列のないリクエストURLです。

http.request.url.query

HTTPリクエストURL問合せ要素を含むマップ。リクエストURLに問合せがない(?文字がない)場合、または問合せが空である(?文字がURLの最後の文字である)場合、このマップは空です。

問合せを解析してhttp.request.url.queryマップを生成するため、URLの問合せ文字列部分(最初の?文字の後の部分)を取得し、次の文字を特殊文字として処理することでそれをキーと値のペアに分割します:

  • &文字は、異なるキーと値のペアのセパレータです
  • =文字は、(キーと値のペア内にある)キーと値のセパレータです

URLに存在する最初の?文字は、問合せ文字列の先頭を示します。最初の文字の後に追加の?文字が存在する場合、それらは特別に処理されることはなく、他の任意の文字と同様に処理されます。

キーと値のペア内で、最初に存在する=文字により、キーと値が区切られます。追加の=文字が存在する場合、それらは値の一部として処理されます。

キーと値は、URLエスケープ・ルールに従ってエスケープされません。

URL: https://www.domain.com/path?key=value&key=%61&another%20key=another+value

このURLでのリクエストのhttp.request.url.queryデータは、JSONで次のように表されます:

{
  "key": [
    "value",
    "a"
  ],
  "another key": [
    "another value"
  ],
}

この例では、キーと値の両方が大/小文字の区別ありで照合されます。したがって、key=valueのかわりにURLにKEY=valueまたはkey=VALUEが含まれている場合、条件は一致しません。

ただし、URL問合せ文字列のキーと値のペアは、次の場合にはhttp.request.url.queryマップに追加されません:

  • キーと値のペアに=文字が存在しない場合

    例:

    URL: https://www.example.com/path?no_key"

    この場合、http.request.url.queryマップに問合せ文字列要素no_keyは存在しません。

  • =文字の左側が空の場合(キーが指定されていない場合)

    例: URL: https://www.domain.com/path?=no_value

    この場合、http.request.url.queryマップに問合せ文字列要素no_valueは存在しません。

=文字の右側が空の場合、そのキーと値のペアの値は空の文字列''です。

http.request.cookies

HTTPリクエストCookieを含むマップ。これはRFC-6265に記載されている"Cookie"リクエスト・ヘッダーから解析され、キーはCookie名であり、値は対応するCookie値です。"Cookie"リクエスト・ヘッダーがリクエストに存在しない場合、このマップは空です。

受信HTTP/1.1リクエストは次のようになります(リクエスト行とヘッダー):

GET /category/some_category?action=search&query=search+terms&filters[]=5&features[]=12 HTTP/1.1
Accept-Encoding: gzip, deflate, br
Cookie: cookie_a=1; cookie_b=foo
Host: www.domain.com
User-Agent: Browser Foo/1.0
X-Forwarded-For: 1.2.3.4, 5.6.7.8
X-Forwarded-For: 9.10.11.12

この場合、ルールに使用可能な変数に、このリクエストからのデータが次のように移入されます: (構造化変数のデータはJSON形式で示されます)

http.request.url.path: "/category/some_category"
 
http.request.url.query: {
  "action": ["search"],
  "query": ["search terms"],
  "filters[]": ["5", "12"]
}
 
http.request.headers: {
  "Accept-Encoding": ["gzip, deflate, br"],
  "Cookie": ["some_cookie=1; another_cookie=foo"],
  "Host": ["www.domain.com"],
  "User-Agent": ["Browser Foo/1.0"],
  "X-Forwarded-For": ["1.2.3.4, 5.6.7.8", "9.10.11.12"]
}
 
http.request.cookies: {
  "cookie_a": ["1"],
  "cookie_b": ["foo"]
}

次に、このリクエストを照合する方法の例を示します:

  • ドメイン"www.domain.com"および"/category/"で始まるURLパスとリクエストを照合する場合は、次のような条件を使用します:

    all(http.request.headers[(i 'Host')] eq 'www.domain.com', http.request.url.path sw '/category')
  • URLパスが正確に"/category/some_category"であるか、またはリクエスト問合せ要素が"action=search"である場合にリクエストを照合するには

    any(http.request.url.path eq '/category/some_category', http.request.url.query['action'] eq 'search')
  • "query"という問合せ文字列要素に値"search terms" (URLエスケープ削除後)が含まれるリクエストを照合するには

    http.request.url.query['query'] eq 'search terms'
  • Cookieに"cookie_a"が含まれるがCookieに"cookie_c"が含まれないリクエストを照合するには:

    all('cookie_a' in (http.request.cookies), 'cookie_c' not in (http.request.cookies))