みなさんこんにちは、武井です。今回はAzureのL7ロードバランサーであるApplication Gatewayについて、わかりみの深く解説したいと思います。
目次
L7のロードバランサーとは?
Application GatewayはL7(レイヤー7)のロードバランサーになります。その比較対象としてよく挙げられるのがL4のロードバランサーですが、この違いについて明確にすることで、L7のロードバランサーの特徴やメリットなどを解説したいと思います。
下図は、L4とL7のロードバランサーの違いを図に示したものです。
L4のロードバランサーとは、その名の通りトランスポート層のプロトコルを解釈して負荷分散するロードバランサーです。トランスポート層のプロトコルはTCPやUDP等色々ありますが、ここではTCPを例に取ってご説明します。
上図の通り、クライアントとサーバー間のsyn、syn+ack、ackのやり取り(3ウェイハンドシェーク)は常にロードバランサーを素通り(?)して、貼られるTCPセッションは常に一本です。ロードバランサーはL4以下(IPアドレスやTCPポートなど)の情報を元に負荷分散先を判断します。つまり、L7のロードバランサーのように、高度な負荷分散はできません。ラウンドロビンで順番に各サーバーにリクエストを降ったり、送信元IPアドレスとポート番号のハッシュ値でリクエスト先のサーバーを決定したりと、L7に比べますと、負荷が特定のサーバーに寄ってしまう可能性があります。
それに対して、L7のロードバランサーは、クライアントがロードバランサーに対して3ウェイハンドシェークでTCPセッションを貼ってHTTPリクエストを送った後、今度はロードバランサーがHTTPクライアントとなり、サーバーに対してTCPセッションを貼ってHTTPリクエストを送ります。つまりTCPセッションは2本貼られます。
つまり、いったんロードバランサー側でSSLによる暗号化通信を解除することとなり、ロードバランサーでHTTPリクエスト及びレスポンスの中身を見ることができます。なので、Cookieパーシステンス(ロードバランサーからブラウザにCookieを発行することにより特定のブラウザからのアクセスは特定のサーバーに分散する機能)や、マルチサイト(HTTPリクエストのホスト名によって分散先のサーバーを決定する機能)といった高度な分散処理やHTTPレスポンスの書き換えが実現できます。ただ、HTTPリクエスト、HTTPレスポンスの検証や書き換え、SSLによる暗号化通信解除などといった処理を伴うので、一般的には高負荷になります。
まとめますと以下のようになります。
L4のロードバランサー | L7のロードバランサー |
|
負荷分散の機能 |
✗ | ◯ |
ラウンドロビン、IPアドレスとかTCPポートによる分散 | Cookieとかホスト名など様々な要素で分散可能 | |
SSL終端 |
✗ | ◯ |
L4なのでできない | L7なのでもちろん可能 | |
性能 | ◯ | ✗ |
仕組みがシンプルなので負荷分散性能は(一般的に)高い | SSL終端やHTTPリクエストの検証・書き換えなどの処理が高負荷であり、(一般的に)負荷分散性能は低い | |
適用範囲 | ◯ | ✗ |
L4なのでWebアプリケーションのみならず、LDAPなど幅広く適用可能 | HTTPで動作するアプリケーションのみ |
Azure Application Gatewayとは?
Azure Application Gatewayとは、Azureが提供するL7のロードバランサーです。以下の特徴があります。
- もちろんマネージド。セキュリティパッチ当てたりなどの運用は一切不要である。
- 負荷に応じて柔軟にスケールする。
- SSLの終端を行うことができる。
- WAF(Web Application Firewall)によって高いセキュリティを確保できる。
- Azureの各種サービスと密な連携が可能である(例えばApp Serviceの前段に配置することも簡単にできる)
と、まぁいろんな特徴があるわけなんですが、以降でそれらの特徴をわかりみ深く説明していきたいと思います。
Azure Application Gatewayの構成
Application Gatewayの概念は少々複雑です。まずはざっくりとした概念図をご説明して、その後により詳細な図でご説明するという流れにします。
ざっくりとした概念図
ざっくり図にすると、以下の通りとなります。
かなりいろんな構成要素が複雑に絡み合っているのがわかります。それぞれの構成要素を説明致します。
フロントエンド
Application Gatewayの入り口になります。具体的には、ユーザーやアプリがアクセスするロードバランサーのIPアドレスです。ユーザーやアプリは、フロントエンドにて定義されたパブリックIPやプライベートIPにアクセスすると、ロードバランサー配下の仮想マシンやApp Serviceなどにアクセスできます。
「パブリックIP」「プライベートIP」の2つがあるのですが、これはその名の通り、パブリックIPはインターネット上に公開されたエンドポイントです。パブリックIPアドレスがフロントエンドに付与されたApplication Gatewayはインターネット上からアクセスが可能です。
リスナー
後述するルーティング規則とフロントエンドを結びつける構成要素です。リスナーはHTTPのスキーム(HTTP or HTTPS)やホスト名などで構成されております。
例えば、XXX.XXX.XXX.XXXというパブリックIPを持つフロントエンドと、HTTPSのスキームをもつリスナーを結びつけると、「https://XXX.XXX.XXX.XXX」というURLを持つロードバランサーが構成されます。
ルーティング規則
フロントエンド+リスナーの組み合わせで作成されたURLで受信したHTTPリクエストを、どのバックエンド(Application GatewayからHTTPリクエストを受け付けてHTTPレスポンスを生成し、Application Gatewayに返すサーバー)に流すのかというルール決めを行う構成要素です。
ルーティング規則の中にも様々な構成要素があるのですが、その代表は「バックエンドターゲット」です。バックエンドターゲットは、その名の通り、そのバックエンドプールにHTTPリクエストを流すのかというルールを決めます。
バックエンドプール
バックエンドを配置するための構成要素です。VMやApp Service、IPアドレスを配置できます。
簡単な実例
ではここで、簡単な実例を交えて説明してみたいと思います。
https://XX.XX.XX.XXというURLでリクエストを受け付けて、2台のVM(VM1とVM2)にリクエストを分散させる構成を考えてみます。以下のような構成になります。
このようなApplication Gatewayを作り出すための手順は以下になります。
- XX.XX.XX.XXというパブリックIPを作成しフロントエンドに配置します。
- httpsでリクエストを受け付けるリスナーを作成して、ルーティング規則とフロントエンドを結びつけます。
- ルーティング規則の中に、バックエンドプールを作成し、分散対象のVM1とVM2を配置します。
- ルーティング規則の中にバックエンドターゲットを作成し、バックエンドプールを紐付けます。
このような流れで、Application Gatewayを作成します。
これは最も単純な例であり、本番で稼働するApplication Gatewayはもう少々複雑な設定が必要になることが多くあります。次章では、今回説明したリスナーやルーティング規則などの構成要素を更に細かく分解して見ていきます。
もっと細かい構成図
先で示したのはApplication Gatewayのざっくりとした概念図でした。本当は以下のような構成図になり、かなりいろいろな構成要素が登場して一気に複雑になります。
なんだか図がごちゃごちゃしてきました。でも、基本的なApplication Gatewayの動きは「ざっくりとした概念図」で提示したものとかわりありません。これから説明しますのは、「ざっくりとした概念図」では説明しきれなかった便利機能の数々といったイメージです。
では一つずつ説明していきます(^^)
リスナー
リスナーはさらに以下の細かい構成要素から成り立ちます。
- フロントエンドIP
- プロトコル
- ポート
- リスナーの種類
- エラーページのURL
以降で詳しく説明していきます。
フロントエンドIP
Application Gateway自身に付与するIPアドレスになります。先程も説明したように「パブリックIP」「プライベートIP」を付与することが可能です。Application GatewayのURLが「https://xx.xx.xx.xx/」だとすると、「xx.xx.xx.xx」の部分です。
プロトコル
HTTPもしくはHTTPSが選択可能です。Application GatewayのURLが「https://xx.xx.xx.xx/」だとすると、「https」の部分です。
ポート
Application GatewayのURLのポートは80、443以外にも任意のポートを指定することが出来ます。
リスナーの種類
「Basic」「マルチサイト」の2つがあります。「マルチサイト」にすると、URLのホスト名の部分は異なるけれど、同じルーティング設定を共有することが出来ます。
つまり、https://hoge.contoso.com/、https://fuga.contoso.com/という2つのURLのどちらにアクセスしても、同じサーバーに負荷分散させるような仕組みを作ることが出来ます。図にすると以下のような感じです。
Application GatewayはHTTPリクエストのHostヘッダーによって、接続するリスナーを判別します。
エラーページ
エラーが発生した際のエラーページを表示することが出来ます。ただし、どんなエラーのときでもエラーページが表示されるわけではなく、以下の2つのケースの場合に限られます。
- HTTPリクエストをルーティングするバックエンドが落ちているとき
- WAF利用時、悪意あるトラフィックを検出したとき
なので、例えばApplication Gatewayそのものが落ちているときには、上記で定義したエラーページには遷移しません。
バックエンドターゲット、バックエンドプール、パスベースの規則
バックエンドターゲットの中には、バックエンドプール、パスベースの規則という構成要素があります。
バックエンドプールはその名のとおり、Application Gatewayがリクエストを分散させるバックエンドを指定します。
パスベースの規則は、パスによって異なるバックエントにリクエストを振り分けることができる機能です。以下の図は、パスが/images/から始まる場合はバックエンドプール1に、パスが/videos/*から始まる場合はバックエンドプール2にリクエストを振る構成になります。
バックエンド設定
バックエンドに接続するための設定になります。バックエンドに接続するための様々なルールを定義します。設定項目を一つずつ見ていきましょう。
バックエンドプロトコル
バックエンドに接続するプロトコルを定義します。「http」「https」の2択です。例えば、「http」を選べば以下のような経路となり、SSL証明書はApplication Gatewayだけで持てばよいということになります。
ブラウザ→(https)→Application Gateway→(http)→バックエンド
バックエンドポート
バックエンドに接続するポートを定義します。任意のポート番号を設定出来ます。
Cookieベースのアフィニティ
いわゆる「Cookieパーシステンス」なロードバランサーを実現出来ます。Application GatewayがブラウザにCookieを発行し、そのCookieの値をもとに、同一ブラウザからのリクエストは同一バックエンドに振り分けます。
接続のドレイン
この設定を有効にしていると、バックエンドプールからバックエンドが削除されても、削除されたときに行われていた通信が最後まで完了するまで、バックエンドの切り離しを待ちます。
例えば、上記の例で言えば、ユーザーはVM2から画像ファイルをダウンロードしていたとします。このとき、計画メンテナンスなどで、バックエンドプールからVM2を削除したとしても、すぐには削除されず、「ドレイン タイムアウト(秒)」で指定した秒数まではこの通信を継続して、この通信が終了してからVM2がバックエンドプールから削除されます。
このようにすれば、計画メンテナンスなどでバックエンドをバックエンドプールから切り離す必要が発生したとしても、ユーザーには影響なく作業ができます。
バックエンドパスのオーバーライド
URLのロケーションの部分を変換する機能です。バックエンドパスのオーバーライドを「/override/」に設定すると、以下のようにロケーションの変換が行われます。
ホスト名のオーバーライド
Application Gatewayからバックエンドに送出するホストヘッダーを変更することが出来ます。
まずは特に何もホストヘッダーを変更しない場合は以下の挙動になります。
これはユーザーがApplication Gatewayにリクエストしてきたホストヘッダーをそのままバックエンドに渡す形式となります。
次は、バックエンドからホスト名を取得する方式です。
バックエンドに設定されたホスト名を取得して、Application Gatewayからバックエンドにそのホスト名を渡します。これは、特にApp Serviceを使う場合は必須で、App Serviceのロードバランサーはホストヘッダーの値を見て、リクエストを送るインスタンスを決定するからです。
最後に、任意のホストヘッダーを指定する方式です。
Application Gateway側で指定した任意のホストヘッダーをバックエンドに送ることが出来ます。
カスタムプローブ
Application Gatewayは何らかの異常が発生したバックエンドを振り分け対象から外すことが可能です。何を持ってして異常と判断するかを細かくカスタマイズが可能で、その設定が「カスタムプローブ」になります。
以下のようなカスタマイズが可能です。
プロトコル | 監視対象のURLのプロトコルになります。監視対象のURLがhttps://www.contoso.com/health.phpだとすると、「https」の部分です。httpもしくはhttpsを選択可能です。 |
ホスト |
監視対象のURLのホスト名になります。監視対象のURLがhttps://www.contoso.com/health.phpだとすると、「www.contoso.com」の部分です。 |
バックエンド設定からホスト名を選択する |
「はい」か「いいえ」を選択可能です。「はい」を選択すると、こちらで設定した内容から、監視対象URLのホスト名を引っ張ってきます。 |
ポートをバックエンド設定から選択する | 「はい」か「いいえ」を選択可能です。「はい」を選択すると、バックエンド設定のこちらにて設定した内容になります。 |
パス |
監視対象のURLのパスになります。監視対象のURLがhttps://www.contoso.com/health.phpだとすると、「health.php」の部分です。 |
間隔(秒) | 監視を行う間隔です。 |
タイムアウト(秒) | 監視対象のURLに監視リクエストを送ったときに、ここで定義した秒数以内で応答が得られなかった場合、監視は失敗となります。 |
プローブの一致条件を使用 | 「はい」か「いいえ」を選択可能です。「はい」を選択すると、「管理対象URLからのレスポンスが何を持ってして正常とするのか」というのを細かく定義できます。「いいえ」だと、HTTPレスポンスのステータスコードが200〜399の間だったら、監視結果が正常とみなされます。 |
HTTP応答の状態コードの一致 | 「プローブの一致条件」を「はい」にすると設定可能になる項目です。監視対象URLに監視リクエストを送った結果、この項目で定義したHTTPステータスコードと一致すれば、監視成功とみなされます。 |
HTTP応答本文の一致 |
「プローブの一致条件」を「はい」にすると設定可能になる項目です。監視対象URLに監視リクエストを送った結果、この項目で定義した内容とHTTPレスポンスのボディが一致すれば、監視成功とみなされます。 |
試してみよう
では、百聞は一見にしかずということで、実際にApplication GatewayでL7のロードバランサーを作ってみましょう。今回は以下の要件を満たすものを作ることとします。
- インターネット経由でアクセスできるIPアドレスをエンドポイントに持つ。
- ユーザーからApplication Gatewayのエンドポイントまでの通信はHTTPSとする。
- Application Gatewayからバックエンドまでの通信はHTTPとする。
- /images/から始めるロケーションにアクセスした場合はバックエンドプール2に振り分け、それ以外はバックエンドプール1に振り分ける。
- Application Gatewayは、バックエンドプール内に事前に用意したヘルスチェック用エンドポイントにアクセスし、以下の応答が返ってこなかったら、そのバックエンドを振り分け対象から外す。
- HTTPステータスコードが200
- HTTPレスポンスの本文内に「OK」の文字列を含む。
上図のバックエンドプール内にはそれぞれ1台ずつ仮想マシンを配置するものとし、Application Gatewayを作成するに先立ち、事前に作成されているものとします。
まずはApplication Gatewayのリソースを作成します。
Azureポータル上部のテキストボックスに「Application Gateway」と入力しますと、以下の画面の用に「アプリケーションゲートウェイ」と表示されますので、それをクリックします。
「作成」をクリックします。
以下のような画面が表示されます。
入力項目の詳細は以下のとおりです。
サブスクリプション | Application Gatewayを作成するサブスクリプションを選択します。 |
リソースグループ |
Application Gatewayを作成するリソースグループを選択します。 |
ゲートウェイ名 |
Application Gatewayのリソース名を入力します。 |
地域 | Application Gatewayを配置するリージョンを選択します。 |
レベル | ここで詳細は後述していますが、Application Gatewayのレベルであり、選択したレベルによって使える機能が異なります。例えば、「WAF V2」を選ぶとWAF(Web Application Firewall)が利用できます。ここでは、あまり気にせず、Standard v2を選択します。 |
自動スケール | ここで詳細は後述しますが、Application Gatewayのスケール方法です。負荷に応じて自動でスケールするか、そうでないかを選択します。ここでは、「はい」(自動スケールする)を選択します。 |
最小インスタンス数 | 自動スケールにすると登場する選択肢で、ここも自動スケールと同様ここで詳細は後述します。とりあえずここでは0とします。 |
最大インスタンス数 | 最小インスタンス数と同様です。とりあえずここでは10とします。 |
可用性ゾーン | 可用性ゾーンを有効にします。Application Gatewayのインスタンスが複数の可用性ゾーンに分散されます。特に無効にする理由はないので、必ず有効にします。 |
HTTP2 |
HTTP2を有効/無効を選択できます。とりあえず無効でいいです。 |
仮想ネットワーク |
Application Gatewayを配置する仮想ネットワークを指定します。 |
サブネット | Application Gatewayを配置するサブネットを指定します。 |
フロントエンドのIPアドレスの設定を行います。今回はパブリックのみとします。その場合、パブリックIPアドレスのリソースを選択する必要があります。もしなければ「新規追加」をクリックして作成します。
バックエンドプールを追加します。「バックエンドプールの追加」をクリックします。
「名前」には任意の値を入力します。「ターゲットを持たないバックエンド プールを追加します」はもちろん「いいえ」を選択します。「ターゲットの種類」には「仮想マシン」、「ターゲット」には冒頭の図の「バックエンドプール1」に配置すべき仮想マシンのリソースを選択します。最後に「追加」をクリックします。
「バックエンドプール2」に配置すべき仮想マシンも同様の手順で追加します。
こんな感じになるはずなので、次に「次: 構成 >」をクリックします。
次にルールを追加します。「ルール」をクリックします。
以下のような画面が表示されます。
「ルーティング規則」の入力項目の詳細は以下のとおりです。
ルール名 | ルールを一意に識別する任意の名前を入力します。 |
優先度 |
ルールを処理する順番を定義します。ここでは一つしかルールを定義しないので、1としておきます。 |
リスナー名 |
リスナーを一意に識別する名前を入力します。 |
フロントエンドIP |
Application GatewayのフロントエンドIPアドレスにパブリックもしくはプライベートのどちらをふよするか選択します。今回は、最初にパブリックIPのみしか追加しなかったため、「パブリック」しか選択できません。 |
プロトコル | Application GatewayにアクセスするユーザーとApplication Gatewayの間のHTTP通信を暗号化するか否かを選択します。ここではHTTPSを選択します。 |
証明書の選択 | 「プロトコル」で「HTTPS」を選択した場合に表示されます。「証明書のアップロード」を選択した場合は、自身のPCから証明書をアップロードします。「キーコンテナから証明書を選択する」を選択した場合は、Azure Key Vaultに登録した証明書を選択できます。今回は「証明書のアップロード」を選択します。 |
証明署名 | 証明書を一意に識別する名前を入力します。 |
PFX証明書ファイル | 「証明書の選択」で「証明書のアップロード」を選択した場合に表示されます。Application GatewayにアクセスするユーザーとApplication Gatewayの間のHTTP通信を暗号化するためのSSL証明書をPFX形式にしたものをアップロードします。 |
パスワード | 「証明書の選択」で「証明書のアップロード」を選択した場合に表示されます。「PFX証明書ファイル」にてアップロードした証明書に付与したパスワードを入力します。 |
リスナーの種類 |
「Basic」か「マルチサイト」を選択します(詳細はこちら)。今回は「Basic」を選択します。 |
エラーページのURL |
エラーページのURLを入力します(詳細はこちら)。今回は「いいえ」を選択します。 |
次にバックエンドターゲットを指定します。「ターゲットの種類」で「バックエンドプール」を選択して、「バックエンドターゲット」には、先程作成した「backendpool01」を選択します。そして、「バックエンド設定」を作成するために「バックエンド設定」の項目のところにある「新規追加」をクリックします。
以下のようにバックエンド設定の設定画面が表示されます。
バックエンド設定画面の設定項目の詳細は以下のとおりです。
バックエンド設定名 | バックエンド設定を一意に識別する任意の名前を入力します。 |
バックエンドプロトコル |
Application Gatewayが、バックエンドプール内にあるサーバーに接続する際のプロトコルを指定します。今回は、Application Gatewayからバックエンドプール1及びバックエンドプール2内にあるサーバーにはhttpで接続するので、「http」を選択します。 |
バックエンドポート |
「バックエンドプロトコル」と同様に、Application Gatewayが、バックエンドプール内にあるサーバーに接続する際のポート番号を指定します。今回は80になります。 |
Cookieベースのアフィニティ |
詳細はこちらで説明しております。今回は、「無効化」とします。 |
接続のドレイン | 詳細はこちらで説明しております。今回は、「無効化」とします。 |
要求のタイムアウト | バックエンドプール内にあるサーバーが、「要求のタイムアウト」で指定した秒数以内にApplication Gatewayにレスポンスを返さないと、Application Gatewayはブラウザに「接続がタイムアウトしました」というエラーを返します。 |
バックエンドパスのオーバーライド | 詳細はこちらで説明しております。今回は使いませんので、何も入力しません。 |
新しいホスト名でオーバーライドする | 詳細はこちらで説明しております。今回は、「無効化」とします。 |
カスタムプローブを作成する | 詳細はこちらで説明しております。今回は要件の中にバックエンドプール内にあるサーバーに対するヘルスチェックがあるので、カスタムプローブは必要になります。ただ、カスタムプローブはここで作ることはできず、別の画面で作成した上で、再度適用する必要があります。なので、ここでは何も選択しません(というかグレーアウトしていて何も選択できません)。 |
次に、要件「/images/から始めるロケーションにアクセスした場合はバックエンドプール2に振り分け、それ以外はバックエンドプール1に振り分ける。」を満たすために、パスベースの規則を作成します。以下の画面下部の「パスベースの規則を作成するには複数のターゲットを追加します」をクリックします。
以下のようにパスベースの規則の設定画面が表示されます。
パスベースの規則の設定項目の詳細は以下のとおりです。入力したら「追加」をクリックします。
ターゲットの種類 | バックエンドプールかリダイレクトを選択します。バックエンドを選択した場合、リクエストを指定してバックエンドプールにプロキシします。リダイレクトを選択した場合、ある特定のサイトにリダイレクトします。ここでは、バックエンドを選択します。 |
パス |
アクセスしたURLのパス(https://www.contoso.com/imagesの/imagesの部分)が、ここで設定した値にマッチするときに、指定したターゲットにリクエストをルーティングします。ここでは「/images/*」とします。 |
ターゲット名 |
このパスベースを一意に識別する値を入力します。なんでもよいです。 |
バックエンド設定 |
詳細はこちらで説明したとおり、Application Gatewayがバックエンドにアクセスするときのプロトコルやポートを定義したバックエンド設定を選択します。今回は、先ほど作成した「backend-config」を選択します。 |
バックエンドターゲット | アクセスしたURLのパス(https://www.contoso.com/imagesの/imagesの部分)が、「パス」の設定にマッチしたときに、ルーティングしたいバックエンドのターゲットを指定します。今回はバックエンドプール2内のVMなので、「backendpool2」を選択します。 |
以下のような画面が表示されます。「追加」をクリックします。
以下のような画面が表示されます。「次: タグ>」をクリックします。
特にタグの付与は今回考えていません。なので、「次: 確認および作成>」をクリックします。
確認画面が表示されます。設定した内容に問題がなければ「作成」をクリックします。
次にカスタムプローブの設定を行います。カスタムプローブは、バックエンドプール内のターゲットが正常に稼働しているかどうかを監視する機能になります。詳細はこちらで説明しています。
Application Gatewayのリソースの作成に成功していれば、リソースグループ内にApplication Gatewayのリソースがあるはずなので(以下画面のagw-demo-prd参照)、それをクリックします。
「正常性プローブ」をクリックします。
「追加」をクリックします。
正常性プローブの追加画面が表示されます。
以下の通り入力してください。
プロトコル | 監視対象のURLのプロトコルになります。監視対象のURLがhttps://www.contoso.com/healthcheck.phpだとすると、「https」の部分です。httpもしくはhttpsを選択可能です。今回は監視対象のバックエンドプール内のターゲットへの通信はhttpなので、httpを選択します。 |
ホスト |
正常性プローブの通信のHostヘッダーに設定する値です。今回は127.0.0.1でOKです。App Serviceや、マルチホスト(こちらを参照)のように、Hostヘッダーによって挙動を変える場合には、適切な値を設定する必要があります。 |
バックエンド設定からホスト名を選択する |
「はい」か「いいえ」を選択可能です。「はい」を選択すると、こちらで設定した内容を、正常性プローブの通信のHostヘッダーに設定します。 |
ポートをバックエンド設定から選択する | 正常性プローブの通信のポート番号になります。「はい」か「いいえ」を選択可能です。「はい」を選択すると、バックエンド設定のこちらにて設定した内容になります。今回は「はい」です。 |
パス |
監視対象のURLのパスになります。監視対象のURLがhttps://www.contoso.com/health.phpだとすると、「health.php」の部分です。今回は「healthcheck.php」とします。このPHPの内容は後述します。 |
間隔(秒) | 正常性プローブの通信を行う間隔です。デフォルトの30とします。 |
タイムアウト(秒) | バックエンドプール内のターゲットに正常性プローブのリクエストを送ったときに、ここで定義した秒数以内で応答が得られなかった場合、監視は失敗となります。デフォルトの30とします。 |
異常しきい値 | 正常性プローブが、ここで設定した値を超えて連続して失敗すると、バックエンドプール内のターゲット異常が発生したと識別されます。 |
プローブの一致条件を使用 | 「はい」か「いいえ」を選択可能です。「はい」を選択すると、「正常性プローブの通信からのレスポンスが何を持ってして正常とするのか」というのを細かく定義できます。「いいえ」だと、HTTPレスポンスのステータスコードが200〜399の間だったら、監視結果が正常とみなされます。ここでは「はい」とします。 |
HTTP応答の状態コードの一致 | 「プローブの一致条件」を「はい」にすると設定可能になる項目です。監視対象URLに監視リクエストを送った結果、この項目で定義したHTTPステータスコードと一致すれば、監視成功とみなされます。ここでは「200」とします。 |
HTTP応答本文の一致 |
「プローブの一致条件」を「はい」にすると設定可能になる項目です。監視対象URLに監視リクエストを送った結果、この項目で定義した内容とHTTPレスポンスのボディが一致すれば、監視成功とみなされます。ここでは「OK」とします。なぜこの値なのかは後述します。 |
バックエンド設定 |
正常性プローブの通信は、ここで設定したバックエンド設定に関連付けられたバックエンドプール内のターゲットに送られます。先程作成したバックエンド設定を選択します。 |
正常性プローブを追加する前にバックエンドの正常性をテストする |
これにチェックを入れておくと、その名の通り、正常性プローブを追加する前に、正常性プローブの通信がうまくいくかどうかをテストすることができます。チェックしておいたほうがよいです。本番であれば、正常性プローブに失敗したら、即システム障害ですし。。。 |
正常性プローブの追加画面で、上記の内容を入力して「テスト」をクリックするのですけど、その前に「パス」の部分で入力したhealthckek.phpは、以下のようなPHPスクリプトであることを前提としています。
<?php
http_response_code( 200 ) ;
echo "OK";
?>
これは冒頭の方で説明した、今回作成するApplication Gatewayの以下の要件を満たしたものです。
- Application Gatewayは、バックエンドプール内に事前に用意したヘルスチェック用エンドポイントにアクセスし、以下の応答が返ってこなかったら、そのバックエンドを振り分け対象から外す。
- HTTPステータスコードが200
- HTTPレスポンスの本文内に「OK」の文字列を含む。
つまり、正常性プローブの通信の結果が、HTTPレスポンスコード200であり、かつHTTPレスポンスの中に「OK」という文字列が含まれないと、正常とみなされないということです。
上記のPHPスクリプトは今回都合上、無条件にHTTPステータスコード200、HTTPレスポンス内に「OK」という文字列を返しているだけですが、実際はデータベースなどの間連システムの正常性を確認した上で、結果を返します。
話がそれましたが、正常性プローブの追加画面で「テスト」をクリックしてみましょう。
以下のような画面が表示され、先程設定したバックエンド設定が関連付けられたバックエンドプール内のターゲットに対して、正常性プローブのリクエストが送られます。問題なければ、以下のように「健全」と表示されるはずなので、「追加」をクリックしてみましょう。
以下のような画面が表示されればOKです。
これで、要件を満たしたApplication Gatewayの完成です!!
価格
本章では、Application Gatewayの価格について説明します。
まずその前にApplication Gatewayのレベルについて説明します。Application Gatewayにはv1とv2というレベルがあり、選択したレベルによって使える機能が異なります。例えば、v2だとWAFや自動スケールと言った便利な機能が利用できます。
昨今利用されるのはほとんどv2であると思うので、今回ご説明する価格については、v2をベースとします。
Application Gatewayの構成要素
価格を説明する上で重要になるのがApplication Gatewayの構成要素であり、以下の3つからなります。
- Application Gatewayのリソース
- インスタンス
- 容量ユニット
一つずつ説明してまいります。ざっくり図解すると以下のような感じになります。
Application Gatewayのリソース
Azureポータルから作成したApplication Gatewayのリソースそのものです。Azureポータルから以下のように見えるやつです。
容量ユニット
Application Gatewayの課金単位です。Application Gatewayが処理するHTTPリクエストが増えれば増えるほど、多くの容量ユニットが必要になり、さらに多くの課金がかかります。例えば、2023年7月8日現在、東日本リージョンで1容量ユニットが1時間利用された場合にかかる課金は、1.1564円となります。当然容量ユニットが2つになれば、その倍かかります。
先程「HTTPリクエストが増えれば増えるほど、多くの容量ユニットが必要になり・・・」と説明しましたが、容量ユニットが増える一定のルールがあります。以下の3つの条件のうちの一つでも超えるとさらに多くの容量ユニットが必要になります。
- 2500 個の永続的な接続
- 2.22 Mbps のスループット
- 1コンピューティングユニット
2,500個の永続的な接続 | 「永続的な接続」とは同時に行われるTCP接続を表します。つまり、一つの容量ユニットでは2,500のTCP接続を同時に処理でき、それ以上のTCP接続が発生すると、必要となる容量ユニットは増えます。 |
2.22Mbpsのスループット |
スループットとは、Application Gatewayが内部で処理した1秒あたりのバイト数になります。つまり、一つの容量ユニットで処理できるバイト数は1秒あたり2.22MByteであり、それ以上要求されると、必要となる容量ユニットは増えます。 |
1コンピューティングユニット |
1秒あたりのTLS接続数、URL書き換え計算、WAFルールの処理によってコンピューティングユニットを消費します。 |
容量ユニットを消費する要因としては上記3つがあるのですが、これを事前に机上で計算してインスタンス数を決めるのはほぼ不可能かと思います。事前に本番と同程度の負荷かけるか、もしくは実際に本番運用に入ってからメトリック(スループットやコンピューティングユニットなど)を確認して、適切なインスタンス数を調整するのが妥当な方法です。
インスタンス
容量ユニットはインスタンスの中に格納されます。一つのインスタンスの中に10個の容量ユニットが格納され、必要な容量ユニットが10個を超えると、新たなインスタンスが必要となります。
つまり、Application Gatewayのスケールはインスタンスという単位で行われます。
そしてインスタンスのスケールには、「自動スケーリング」「手動」の2つがあり、後で説明するコストの計算にも重要な概念となりますので、ここで説明します。
■ 自動スケーリング
インスタンスの自動スケールについては、Application Gatewayのリソースを作成するときに、以下の設定を行ったのを覚えてますでしょうか?
ここで「はい」を選択すると、自動スケールするようになります。
最小インスタンス数と最大インスタンス数を指定でき、まず初めは最小インスタンス数で指定した値でApplication Gatewayが起動し、負荷が増えればインスタンスが最大インスタンス数に指定した値までスケールアウトします。また、負荷が収束すれば、最小インスタンスで指定した値までスケールインします。
つまり、自動スケーリングの場合は、現在のインスタンス内にある容量ユニットで処理しきれないくらいのリクエストがあった場合、インスタンスが増えて、そのインスタンスに新たな容量ユニットが出来上がり、その容量ユニットでリクエストを処理するわけです。図にすると以下のようになります。
■ 手動の場合
先に説明した「自動スケール」の項目で「いいえ」を選択すると、以下の様な画面になります。
この場合インスタンス数は固定になります。例えばインスタンス数が2の場合に、最初は1つ目のインスタンスで処理しきれていたが、リクエストが多くなり1つ目のインスタンスだけでは処理しきれなくなった場合の動きは以下の通りとなります。
価格の構成要素
Application Gatewayの構成要素を説明しましたので、次はApplication Gatewayの価格がどのような要素で決定づけられるのかを説明したいと思います。以下の2つの要素によってApplication Gatewayの価格が決まります
- 固定コスト
- 容量ユニットのコスト
固定コスト
Application Gatewayのリソースを削除しない限り、たとえ接続がなくても、発生し続けるコストです。例えば東日本リージョンですと、2023年7月16日時点では、1時間あたり41.9181円のコストが発生します。つまり1ヶ月稼働させていると以下になります。
41.9181円/時間 × 24時間 × 30日 = 約30,181円
変動コスト
先程ご説明した容量ユニットに発生するコストです。例えば東日本リージョンですと、2023年7月16日時点では、一つの容量ユニットが1時間稼働すると、1.1564円のコストが発生します。10個の容量ユニットが1ヶ月稼働すると以下になります。
1.1564円/容量ユニット時間 × 10 × 24時間 × 30日 = 約8,326円
超過コストが発生しない手動スケーリングの場合
ここからは、いくつかの例を用いて、実際に発生する費用のシミュレーションをしてみたいと思います。
では、手動スケーリングの場合からです。以下の条件であったと仮定します。
- スケーリングは手動
- インスタンス数は6で固定
- ある特定の月に平均88.8Mbpsのデータを受信
この場合のApplication Gatewayの構成は以下のようになります。
一つの容量ユニットで2.22Mbpsのスループットを処理できて、今回は88.8Mbpsのスループットがありましたので、必要な容量ユニットは以下になります。
88.8Mbps ÷ 2.22Mbps/容量ユニット = 40容量ユニット
今回は、固定で6インスタンス起動しており、常時60容量ユニットがあります。
60容量ユニット(現在動いている分) > 40容量ユニット(必要な分)
なので、追加コストは発生しません。よってコストは以下となります。
固定コスト = 41.9181円/時間 × 24時間 × 30 = 約30,181円
変動コスト = 1.1564円/容量ユニット時間 × 60容量ユニット × 24時間 × 30 = 約49,965円
合計コスト = 固定コスト+変動コスト = 約80,146円
超過コストが発生する手動スケーリングの場合
そもそもタイトルから矛盾しているように思えるのですが、今回は超過コストが発生する手動スケーリングの場合です。以下の条件であったと仮定します。
- スケーリングは手動
- インスタンス数は3で固定
- ある特定の月に平均88.8Mbpsのデータを受信
この場合のApplication Gatewayの構成は以下のようになります。
一つの容量ユニットで2.22Mbpsのスループットを処理できて、今回は88.8Mbpsのスループットがありましたので、必要な容量ユニットは以下になります。
88.8Mbps ÷ 2.22Mbps/容量ユニット = 40容量ユニット
今回は、固定で3インスタンス起動しており、常時30容量ユニットがあります。
30容量ユニット(現在動いている分) < 40容量ユニット(必要な分)
つまり、今回の容量ユニットでは処理がさばききれず、追加コストが発生しない場合は、以下のようになります。
固定コスト = 41.9181円/時間 × 24時間 × 30 = 約30,181円
変動コスト = 1.1564円/容量ユニット時間 × 30容量ユニット × 24時間 × 30 = 約24,978円
合計コスト = 固定コスト+変動コスト = 約55,159円
「追加コストが発生しない場合」と書きましたが、実は「追加コストが発生する場合」もあります。1インスタンスの中には最大10個の容量ユニットを格納できると説明しましたが、場合によっては10個を超えて格納できることがあるそうです。ただ、どれくらい格納できるかはいろんな条件に応じて左右されるとのことです。
ここで、各インスタンスで1つだけ多くの容量ユニットを格納できたとしましょう。
つまり、3容量ユニット分の超過コストが発生することになります。よってコストは以下となります。
固定コスト = 41.9181円/時間 × 24時間 × 30 = 約30,181円
変動コスト = 1.1564円/容量ユニット時間 × 33容量ユニット × 24時間 × 30 = 約27,476円
合計コスト = 固定コスト+変動コスト = 約57,657円
つまり、2,498円の超過コストが発生します。
超過コストが発生する自動スケーリングの場合
今度は自動スケーリングの場合です。以下の条件であったと仮定します。
- スケーリングは自動
- 最小インスタンス数は3
- 一ヶ月全体に渡って34容量ユニットを利用するようなリクエストを受信
この場合、Application Gatewayの構成は以下となります。
コストは以下の通りとなります。
固定コスト = 41.9181円/時間 × 24時間 × 30 = 約30,181円
変動コスト = 1.1564円/容量ユニット時間 × 34容量ユニット × 24時間 × 30 = 約28,308円
合計コスト = 固定コスト+変動コスト = 約58,489円
各種機能の紹介
本章では、今まで紹介しきれなかったApplication Gatewayの細かい便利機能について説明します。
クライアント証明書による認証
Application Gatewayはクライアント証明書による認証も可能です。実際に試してみたいと思います。
手順としては以下になります。
- クライアント証明書を作成する。
- SSLプロファイルを作成して、CA証明書を登録する。
- 作成したSSLプロファイルをリスナーに紐付ける。
クライアント証明書を作成する
まずは以下の手順で認証局とクライアント証明書を作成しましょう。opensslコマンドを使います。
認証局を作成します。
$ openssl req -newkey rsa:4096 -keyform PEM -keyout clientca.key -x509 -days 3650 -extensions v3_ca -outform PEM -out clientca.cer -addext basicConstraints=CA:true
クライント証明書の秘密鍵を作成します。
$ openssl genrsa -out client.key 4096
クライント証明書のCSRを作成します。
$ openssl req -new -key client.key -out client1.req
クライアント証明書を作成します。
$ openssl x509 -req -in client1.req -CA clientca.cer -CAkey clientca.key -set_serial 101 -extensions client -days 365 -outform PEM -out client1.cer
Windowsなどでも読み込めるように、P12形式に変換します。
$ openssl pkcs12 -export -inkey client.key -in client1.cer -out client1.p12
SSLプロファイルを作成して、CA証明書を登録する
AzureのポータルからApplication Gatewayのリソースを表示して、左部メニューの「SSL設定」をクリックします。それから、「+ SSLプロファイル」をクリックします。
「SSLプロファイル名」に任意の名称を入力します。そして、「新しい証明書のアップロード」をクリックします。
「証明書」に証明書を識別するための一意な名前を入力します。そして、先程作成したCA証明書(ファイル名clientca.cer)を選択して、「OK」をクリックします。
最後に以下の画面で「追加」をクリックします。
作成したSSLプロファイルをリスナーに紐付ける
クライアント証明書による認証を行いたいリスナーにアクセスします。Azureのポータルにアクセスして、左部メニューの「リスナー」をクリックします。画面右部にリスナーの一覧が表示されるので、クライアント証明書による認証を行いたいリスナーをクリックします。
「SSLプロファイルを有効にする」をチェックしますと、「SSLプロファイル」というセレクトボックスが現れます。そこで、先程作成した名称のSSLプロファイルを選択して、「保存」をクリックします。
これで設定は完了です。サイトにアクセスすると、クライアント証明書による認証が要求されるはずです。
HTTPヘッダーとURLの書き換え
Application GatewayはHTTPリクエストヘッダーやHTTPレスポンスヘッダー、URLを様々な条件で書き換えることが可能です。
この設定は、「書き換えセット」「書き換えルール」「条件」「アクション」の4つで構成され、その関係は図に示す通りとなります。
これは理論を説明するよりも、いろんな実例をもとに説明したほうがわかりやすいとおもいます。マイクロソフトのドキュメントに乗っている実例を挙げてわかりみ深く解説します。
X-Forwarded-For ヘッダーからポート情報を削除する
X-Forwarded-ForヘッダーにはIPアドレスに加えてポート番号が付与されてくるケースもありますが、このポート番号は不要であることが多いので、これを削除したいと思います。以下のようなイメージです。X-Forwarded-Forには203.0.113.7:8080の値が設定されてユーザからApplication Gatewayに送られてきましたが、Application Gateway側でポート番号を削除して203.0.113.7という値にして、バックエンドに送ります。
AzureのポータルからApplication Gatewayのリソースを表示して、左部メニューの「書き換え」をクリックします。画面右部に表示されている「+ 書き換えセット」をクリックします。
「名前」には、書き換えセットを一意に識別する名称を入力します。「関連付けられているルーティング規則」には、この書き換えセット(X-Forwarded-Forからポート番号を削除する)を適用するルーティング規則を選択します。そして、「次へ」をクリックします。
「+書き換え規則の追加」をクリックします。
以下のような画面になります。「実行」をクリックして、アクションを編集します。
以下のように設定します。
上記の設定内容の詳細は以下のとおりです。
書き換えの種類 | 書き換えの対象を指定します。「要求ヘッダー」「応答ヘッダー」「URL」の3つを選択することができます。「要求ヘッダー」はHTTPリクエストヘッダー、「応答ヘッダー」はHTTPレスポンスヘッダーのことです。ここでは「要求ヘッダー」を設定します。 |
アクションタイプ |
「書き換えの種類」で「要求ヘッダー」「応答ヘッダー」を選択したときにだけアクティブになる項目であり、「設定」「削除」を選択可能です。「設定」はヘッダーを追加したり上書きしたりする場合、「削除」はヘッダーを削除する場合に選択します。ここでは「設定」を選択します。 |
ヘッダー名 |
「共通ヘッダー」「カスタムヘッダー」の2つが選択可能です。「共通ヘッダー」はすでに用意されてるいくつかのよく使われるヘッダーから選択します。「カスタムヘッダー」は独自のヘッダー名を入力します。ここで選択した値は、のちの「共通ヘッダー/カスタムヘッダー」に影響します。ここでは「共通ヘッダー」を選択します。 |
共通ヘッダー/カスタムヘッダー |
「ヘッダー名」で「共通ヘッダー」を選択すると、ここの項目名が「共通ヘッダー」になり、「カスタムヘッダー」を選択すると「カスタムヘッダー」になります。今回は「ヘッダー名」のところで「共通ヘッダー」となっているので、「共通ヘッダー」となります。そして、その値には「X-Forwarded-For」を設定します。 |
ヘッダー値 |
Application Gatewayにはサーバー変数という概念があります。サーバー変数とは、Application Gatewayの設定の中で扱うことができる変数であり、例えば接続元クライアントIPアドレスはclient_ip、HTTPメソッド(GETやPUTなど)はhttp_methodという変数に格納されます。これらを書き換えルールの中で扱うには、{var_サーバー変数}といった書き方をします。X-Forwarded-Forヘッダは、サーバー変数add_x_forwarded_for_proxyに格納されるので、{var_add_x_forwarded_for_proxy}をここでは設定します。 |
最後に「作成」をクリックして完了です。
クエリパラメータの値によって振り分けるバックエンドを変える
今度はクエリパラメータの値によって振り分けるバックエンドを変えてみます。
クエリパラメーターにcategory=foodsが設定されていたら、ロケーションを/listfoodsに変換してバックエンドにルーティングします。つまり、図にしますと以下のような感じです。バックエンドは2つあり、バックエンド02は/listfoodsのロケーションにアクセスした場合にルーティングされるバックエンド、バックエンド01はそれ以外のすべてのリクエストがルーティングされるバックエンドです。
上記のパスマップは、Azureポータルでは以下のような構成となります。
では早速設定してみましょう。AzureのポータルからApplication Gatewayのリソースを表示して、左部メニューの「書き換え」をクリックします。画面右部に表示されている「+ 書き換えセット」をクリックします。
「名前」には、書き換えセットを一意に識別する名称を入力します。「関連付けられているルーティング規則」には、「種類」が「パスベースの規則(既定の書き換え設定)」のものを選択します。そして、「次へ」をクリックします。
「+書き換え規則の追加」をクリックします。
以下のような画面になります。「+条件の追加」をクリックします。
先程追加した条件(「If – クリックしてこの条件を構成」と記載されているもの)をクリックします。
以下のように設定します。
上記の設定内容の詳細は以下のとおりです。
チェックする変数の型 | この条件でチェックする内容を指定します。「HTTPヘッダー」「サーバー変数」から選択ができ、「HTTPヘッダー」はHostヘッダーやContent-TypeなどHTTPリクエストヘッダーに登場する値になります。「サーバー変数」はApplication Gatewayに設定される独自の変数で、接続元クライアントIPアドレスを表す「client_ip」や、クライアント証明書認証した場合の証明書のsubjectが格納される「client_certificate_subject」などがあります。ここでは、「サーバー変数」を指定します。 |
サーバー変数 |
クエリパラメータを格納するサーバー変数である「query_string」を指定します。 |
大文字と小文字を区別する |
比較する際に比較元と比較先の大文字と小文字を区別するかどうかを設定します。今回であれば、クエリパラメーターがcategory=foodsにマッチするかどうかを比較するのですが、この設定を「いいえ」にすると、渡されてきたクエリパラメーターがcAteGory=FooDsでも条件は真となります。ここでは、「いいえ」を設定します。 |
演算子 |
比較元と比較先を比較する際の演算子です。「等しい(=)」と「等しくない(!=)」を設定できます。ここでは、「等しい(=)」を設定します。 |
一致させるパターン |
比較対象の値を設定します。テキスト形式か正規表現が利用可能です。今回であれば、「クエリパラメーターがcategory=foodsに一致するかどうか」なので、ここで指定する値は「category=foods」になります。 |
次に、「結果 – クリックしてこのアクションを構成」をクリックします。先程の条件が真だった場合に実行されるアクションとなります。
書き換えの種類 | 書き換えの対象を指定します。「要求ヘッダー」「応答ヘッダー」「URL」の3つを選択することができます。「要求ヘッダー」はHTTPリクエストヘッダー、「応答ヘッダー」はHTTPレスポンスヘッダーのことです。ここでは「URL」を設定します。 |
アクションタイプ |
「書き換えの種類」で「URL」を選択した場合、ここで選択できるのは「設定」のみとなります。 |
コンポーネント |
このアクションで書き換え対象のものを指定します。「URLパス」「URLクエリ文字列」「URLパスとURLクエリ文字列の両方」から選択が可能です。 「URLパス」を選択した場合は、例えばURLが「https://www.contoso.com/shoes」だった場合、「shoes」の部分だけが書き換え対象になります。 「URLクエリ文字列」を選択した場合は、例えばURLが「https://www.contoso.com/?category=shoes」だった場合、「category=shoes」の部分だけが書き換え対象になります。 「URLパスとURLクエリ文字列の両方」を選択した場合は、「URLパス」と「URLクエリ文字列」の両方が書き換えとなります。 |
URLパスの値 |
「コンポーネント」で「URLパス」もしくは「URLパスとURLクエリ文字列の両方」を選択した場合に表示されます。このアクション実行後に書き換えられるURLパスの値を指定します。ここでは、「http://example.com?category=foods」を「http://example.com/listfoods」に書き換えたいので、「/listfoods」と指定します。 |
パスマップの再評価 |
取りあえずはチェックしますが、詳細は後述します。 |
URLクエリ文字列の値 |
「コンポーネント」で「URLパス」もしくは「URLパスとURLクエリ文字列の両方」を選択した場合に表示されます。このアクション実行後に書き換えられるURLクエリ文字列の値を指定します。ここでは、「http://example.com?category=foods」を「http://example.com/listfoods」に書き換えたいのです。つまり、書き換え後にはクエリ文字列は何も付与したくないので、空の値を設定します。これを設定しないと、元のURLのクエリ文字列が、書き換え後のURLにも付いてしまいます。 |
「パスマップの再評価」については以下の図のとおりとなります。
「パスマップの再評価」をチェックしないと、以下のようにデフォルトのバックエンドにルーティングされます。つまり、Application Gatewayはバックエンド01にhttp://example.com/listfoodsというURLでアクセスします。
「パスマップの再評価」をチェックすると、「パスベースの規則」にて追加したバックエンドにルーティングされます。バックエンドが複数あれば、http://example.com/listfoodsのURLにマッチしたバックエンドにルーティングされることとなります。今回であればバックエンド02にルーティングされるというわけです。
最後に「作成」をクリックして完了となります。
最後に
Application Gatewayは、なかなかに設定が複雑で構築が大変ですが、もしこのブログがそんなみなさんの一助になれば幸いでございます。