ブログサイトをもう少しクラウドに寄せてみよう
コレをやる前の状態として、Microsoft Azureの環境というのは、あくまで補佐的な位置づけであり、例えば内部ネットワークへアクセスするための拠点であったり、CDNのPOPリストをリバースプロキシに展開したりと言う用途にしか使ってませんでした。
強いてあげればAzure CDNなんかは比較的中核的な位置づけで稼働していたのですが、もう少しAzureを使い込んでみたり出来ないものかと
まともにVMとか建ててしまうと、少しスペックを挙げただけで金額が上がってしまうし、KubernetesサービスであるAKSは簡単に予算を突き抜けるぐらい高かったりするもんで・・・
で、他になにか要素がないかなと調べて、「これかな?」と思ったのが今回のネタです。
構成

今回使用することにしたのは、以下の2つのリソースです。
- Application Gateway
- Traffic Manager
Application Gatewayは、所謂「L7ロードバランサー」です。SSL終端が可能であり、WebSocketやHTTP/2に対応させることが可能です。プローブも単純な応答確認だけでなく、Status Codeに基づくルールを適用することが出来ますし、セッションアフィニティをかけることも可能です。
なんとこれ、最小構成であれば月額2,300円程度で遊ぶことが可能です。今回はその最小構成である「V1/SKU:S/1インスタンス構成」で挑みたいと思います。
Traffic ManagerはDNSサービスの一種です。地理冗長されたシステムに対して、それぞれの死活監視・性能監視を行い、その結果をもって複数サイトの振り分けを行うことが出来ます。
Traffic ManagerはDNSサービスの一種であるため、クエリ単位での課金になりますが、かなり安いです。感覚的にはAzure DNSより少し高めぐらいの位置づけであり、TTLを短くする必要がある分、少し高めになるものの、桁違いな金額にはなりにくいのかなと考えられます。
プロトコルフロー

まず、クライアントはDNSに対してサイトURLに対する名前解決を行います。この時、DNSはAzure CDNの名前を応答として返します。

CDNはキャッシュにデータが有ればそれを応答し、それがなければオリジンサイトへのアクセスを行います。その際、オリジンサイトのホスト名はDNSサーバによってTraffic Managerの名前にCNAMEで紐付けられています。
そのため、CDNはまずTraffic Managerに対して名前解決を試みます。
Traffic Managerは、それ自身に登録されたサイトの状態を確認し、予め定められたルールに基づいて、向かうべきサイトの名前をCDNへ応答します。

AppGateway側のアドレスが応答で帰ってきた場合、CDNはAppGatewayに対してアクセスを試みます。AppGateway側へアクセスが行われると、AppGatewayは自身のバックエンドプールに対してアクセスを行います。
私の環境では、自宅K8S環境へアクセスに行き、オリジンサーバであるコンテナがその応答を返します。最終的にCDNを介してユーザに対してコンテンツを表示させることになります。

オンプレミス側のアドレス応答が帰ってきた場合、CDNはオンプレミス環境にあるリバースプロキシへアクセスを試みます。オンプレミス側へアクセスが行われると、同様にオンプレミス環境上のNginxが設定に基づきオリジンサーバであるコンテナへアクセスを行い、最終的にはCDN経由でコンテンツなどの応答を返す形になります。
Traffic Managerについて
では、まずTraffic Managerリソースを作成するのですが、このリソースの正式名称は「Traffic Manager プロファイル」と呼ばれます。このリソースはリージョンに依存しない「グローバルリソース」と呼ばれ、世界中に散在させたTraffic Managerが協調しながら稼働しています。
設定項目は非常にシンプルで、大別すると
- エンドポイント
- ルーティング方式
- プローブ
- プロトコル/ポート
ぐらいしかありません。
エンドポイントは名前の通り、振り分け先を指します。IPアドレス/ホスト名/Azureリソースを指定することが可能であり、今回のケースでは、AppGatewayとオンプレミスNginxのグローバルIPを指定する形になります。
ルーティング方式は、全ては押さえきれてませんが、「優先度」「重み付け」「地域」などがあります。
優先度はその優先度に従い、生存するエンドポイントのうち、最も高い優先度のサイトに振り向ける方式で、Active/Standby/Standby/Standby…構成というやつです。重み付けは、特定の比率に従いサイト振り分けを行う方式、地域は特定の地域に対して特定のサイトを定める方式です。
当方のサイトでは、優先度を使用しており、
AppGw > 本番Nginx > 災対Nginx
と言う形で設定をしています。
プローブは所謂「正常性確認処理」を指しており、これが異常と判断された場合、振り分け対象から除外されます。HTTP応答の戻り値から異常/正常を判断させることが可能です。
当方のサイトは、トップページを表示させてみて、レスポンスが200-399出会った場合に正常と判断するよう設定しています。
プロトコル/ポートはプローブ処理に必要な設定で、何のプロトコルでプローブするのかを設定します。当方のサイトはHTTPS/443ですので、その設定を行っています
試しに当方のオリジンサイトのFQDNで名前解決してみると
;; ANSWER SECTION:
www-origin.bluecore.net. 3599 IN CNAME bluecore.trafficmanager.net.
bluecore.trafficmanager.net. 59 IN CNAME bluecore-websites.japanwest.cloudapp.azure.com.
bluecore-websites.japanwest.cloudapp.azure.com. 9 IN A 40.74.65.103
こんな風になります。
- Azure DNS上で定義したCNAMEが返ってきている
- TrafficManager上で定義されてるCNAMEが返ってきている
- AppGatewayで定義されているFQDNに基づき、IPアドレスが返ってきている
このような形で、最終的な名前解決の結果、AppGatewayに振り向けてCDNはアクセスしていくということになります。
Application Gateway
Application Gatewayは先にも説明したとおり、L7のロードバランサです。このリソースの設定は、主に6つほどの設定要素があります。
- ルール
- バックエンドプール
- HTTP設定
- リスナー
- フロントエンドIPアドレス
- 正常性プローブ

初期設定などを見ながら、それを参考にするとよいのかな?と思います。
なお、AppGatewayにはバージョンがあります。V1/V2があり、V1はIISベース、V2はNginxベースだそうです。商用ページに適用させるのであれば、恐らくはV2が良いでしょう。V1は設定反映が遅いという弱点があり、小さな設定でも数分程度待たされることがあります。コレに対して、V2はデプロイメント含めてV1よりも圧倒的に速く処理させることが可能です。
ただし、V2はインスタンス構成単位が2~であること、SKUの概念がないためどの価格帯のAppGatewayが作られるのかわからないというコスト面でのリスクが少々あります。とはいえ、そもそもSKU:Sや1インスタンス構成に対してMicrosoftはSLAを定義していませんので、商用にV1の小規模構成を持ってくるのは危険だと思います。
商用の場合はV2を、個人で小さくささやかにやるならV1がいいでしょう。
証明書の適用
証明書はApp Service 証明書を適用することも出来ますし、持ち込み証明書を適用することも出来ます。ただし、EV証明書には対応していません。また、Keyvaultと連携してないため、App Service証明書は、その内容を変更するたびにKeyvaultからエクスポートし、AppGatewayへインポートする必要があります。形式は必ず.pfxファイル(PKCS#12形式)にする必要があります。
私の環境では元々所持していたKingSSLの証明書をPKCS#12形式に変換したあと直接インポートしています。
セキュリティはNSGで担保する
AppGatewayはIaaSリソースであるがゆえ、必ずVNETに接続します。このVNETに対して、専属のサブネットを構成することが必須になります。このAppGatewayに対するIPフィルタリングはNSGを使用することで実現できます。
ただ、注意が必要なのは、図を見るとわかるんですが、

という感じになってると認識したほうが良いです。故に、NSGに対する受信規則は常に「AppGateway用サブネット(プライベートアドレス)に着信することを前提にして」考えたほうが良いと思います。つまり、Public IPに対する着信を考慮した設定は全く意味をなしません。その点には注意が必要です。
また、接続するネットワークセグメントは上記のように1つであるため、内部IPとか外部IPとかはほとんど気にしなくて良い感じです。それ以前に内部IPは原則開示されておらず、通信状況のログ等を見る過程でようやく理解できるレベルですので、オンプレミスベースの考えで物事を進めると恐らくは混乱すると思います。その点は注意が必要かなと思います。
Azure CDN(Premium Verizon)とAppGatewayの相性は悪い
コレは冗談抜きに要注意事項なんですが、Azure CDN(Verizonタイプ)はSNIに対応していません。コレで何の弊害が起きるかというと、AppGatewayでリスナータイプを「マルチサイト」にすると、CDNからAppGatewayに対するアクセスが失敗してしまい、502エラーが発生します。
これは、そのリスナーの性質を考えるとわかるのですが、IPアドレスとSSL証明書を1対1で対応付けるベーシックリスナーは、SSL証明書をIPバインドします。これに対して名前によって振り分けるマルチサイトリスナーはSSL証明書をSNIバインドします。
CDNがSNIに対応してないことから、CDNでSNIベースのリクエストやレスポンスが解釈できずに最終的にオリジンへ不到達と言う判断を下してしまい、エラーとなるわけです。curlコマンドを試しに発行すると、以下のような感じになります。HTTP/1.0リクエストに対する応答が最初返って来ていることから、CDN側としてはHTTP/1.0ベースで動いてることがわかると思います。
HTTP/1.0 200 OK
HTTP/1.1 502 Bad Gateway
Content-Encoding: gzip
Content-Type: text/html
Date: Thu, 27 Dec 2018 04:31:37 GMT
Server: ECAcc (tka/8891)
Content-Length: 349
とはいえ、実はデフォルトで対応してないだけで、申請すればSNI対応してくれます。ただ、自分の場合は・・と言う話ではありますが、
- Microsoft有償サポート契約を結ぶ
- 英語で問い合わせ文を作成する必要がある
この2点がハードルを上げるかなと思います。
まず、Azure CDNはOEM製品のようなものです。Verizon Digital Media Service(VDMS)というところが提供しているものであり、Microsoft社のサポートポリシーとして、これに関する質問は直請けしません。VDMS社へエスカレーションするまでがMSの範囲になります。
そして、Microsoft社サポートはユーザに対して認識齟齬を回避するため(というより、翻訳に対する責任を負えない)、ユーザ側で英語文を作ることを求めてきます。コレに対しては「MSがなんとかしろよ!」とは言えませんので、なんとか頑張って英文を書いてください・・・ということになります。
私自身、英語力は限りなくゼロな人間ではありますが、Google翻訳のお世話になりながら下手くそなりに頑張って英文作って質問しました。
そしたら、VDMS社からあっさり以下の回答が得られました。まぁそういうことなら多少の労苦は伴ってもええのかなと個人的には思います。
Hello,
VDMS<->MSとの問い合わせメールから引用
The origin server www-origin.bluecore.net appears to require that SNI be enabled. I parsed your request logs for today and found 79 total 502s, all were recorded when attempting to reach <AppGw Address>.
We can enable SNI via a back end config change, please let us know if you wish us to proceed with this.
Best Regards,
開通には5営業日かかるのが基本ですが、SNIの有効化はMS経由でお願いすれば、追加課金無しで実装してもらえます。今後の改修等でデフォルトSNI対応してもらえるとありがたいんですけどねー・・・なんて。
発展途上の部分も多いけど
Microsoft Azureは非常に面白いなぁと思います。安定面に欠けた部分や、開発途上じゃね?これ。って感じるところもそこそこあるんですが、それでもそれなりの品質に加えて、何よりコストが掛りにくいなと感じるところが多く、AWSと比べるといろんな機能へ手を出しやすい一面があるかなーと思っています。
無償サービスを駆使して開発環境を作ることも出来ます(例えば、WebApps/FreeとFunctionsとCloudFlare/Freeを組み合わせるだけで、CDN付きのWeb開発環境が出来るとか)。クラウドの手がかりの一歩目としてこいつに触れてみるのも良いかもしれないです。
Comments are closed