ロード・バランサのルーティング・ポリシー言語
ロード・バランサのルーティング動作をガイドするルーティング・ポリシー条件ステートメントを記述する方法について学習します。
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
がある場合(URLhttps://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 |
=, ==, equal, equals |
マッチャの左側の値と右側の値が等しい場合に一致します。 | http.request.url.path eq "/category/element/id" |
ew |
左側の値が右側の値で終わる場合に一致します。 | http.request.url.path ew '/id' |
|
sw |
左側の値が右側の値で始まる場合に一致します。 | http.request.url.path sw '/category' |
|
not eq |
!=, not equal, not equals |
マッチャの左側の値と右側の値が等しくない場合に一致します。 | http.request.url.path neq '/some/other/path' |
not ew |
左側の値が右側の値で終わらない場合に一致します。 | 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リクエスト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
マッチャを使用して、そのキーのany
の値がその特定の値と等しいかどうかをチェックします。述語が一致するのは、そのキーの少なくとも1つの値がその特定の値と一致した場合です。
例:
- ヘッダー
header-name
のいずれかの値がheader-value
と等しい場合に一致させるには:http.request.headers[(i 'header-name')] eq 'header-value'
ヘッダー
name
は、大/小文字の区別なしに比較されますが、ヘッダーvalue
は、大/小文字の区別ありですでに比較されます。 - Cookieの"cookie-name"の値が
cookie-value
と等しい場合に一致させるには:http.request.cookies['cookie-name'] eq 'cookie-value'
not eq
マッチャを使用すると、そのキーのnone
値も特定の値と等しくないことをチェックできます。
例:
- ヘッダー
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.url.path |
HTTPリクエストURLパス。これは、プロトコル、ドメイン、ポートおよび問合せ文字列のないリクエストURLです。 | |
http.request.url.query |
HTTPリクエストURL問合せ要素を含むマップ。リクエストURLに問合せがない(? 文字がない場合)場合、または問合せが空である(? 文字がURLの最後の文字である)場合、このマップは空です。問合せを解析して
URLに存在する最初の キーと値のペア内で、最初に存在する=文字により、キーと値が区切られます。追加の =文字が存在する場合、それらの文字は値の一部として処理されます。 キーと値は、URLエスケープ・ルールに従ってエスケープされません。 |
URL:https://www.domain.com/path?key=value&key=%61&another%20key=another+value このURLでのリクエストの
この例では、キーと値の両方が大/小文字の区別ありで照合されます。したがって、 ただし、次の場合には、URL問合せ文字列のキーおよび値のペアは
|
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))