Route53 ヘルスチェックのエンドポイント設定のわな

こんにちは！
こちらは、[ラクス Advent Calendar 2019](https://qiita.com/advent-calendar/2019/rakus)の20日目になります。
昨日は[@danonb10さん](https://qiita.com/west-c)の『[PostgreSQL 宣言的パーティショニングの制約事項](https://qiita.com/west-c/items/1fd0b08b8e919ec2b632)』でした。


# はじめに
2019年10月に現場に変わりました。
ちょうど配属前にAWSソリューションアーキテクト アソシエイトを取得、勉強したことがしっかり頭に残っている状態でのAWS現場だったので、なんだかテンションがあがります。とはいえ、実際に業務でサービスを触るのは初めてなのですが、毎日新鮮な気持ちで勤しんでおります。

はじめてしっかり携わったプロジェクトとして、マルチCDNをフェイルオーバー構成にするという、ちょっとめずらしいことをやりました。今の現場が映像配信サービスをしている会社さんだというのもあるのかな。今回、CDNフェイルオーバー構成をつくる際に直面する問題点・解決策を共有させていただきます。

# やりたいこと
ざっくりですが、概要。

+ AWSのRoute53のヘルスチェック・フェイルオーバールーティングを活用する
+ ヘルスチェック：2つのCDN→オリジンサーバの接続を見るように
+ ルーティング：加重ルーティングを採用、アクティブサーバに100、スタンバイサーバに0を設定

![構成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521220/a265b35f-e8a3-c7d9-e11d-34fe13d6ea95.png)

# 問題

ここで、CDNならではの問題が発生します。

CDNってフロントは複数のサーバーから構成され、複数のIPアドレスを持っていて、CDN自体も分散・冗長構成をとっています。ですので、Route53のヘルスチェックの設定をする際に、エンドポイントをIPアドレスで指定することができません。ドメインで指定します。なおかつ、CDN1/2とは同じドメインを設定したい。
普通にRoute53のヘルスチェックを設定しただけでは、下記のように、全く意味のない構成になります。

1. CDN1が故障し、ヘルスチェックが「異常」と判定される
![フェイルオーバー_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521220/c51ee066-f138-10cc-8d6e-752056070a49.png)

2. CDN2にフェイルオーバーする
![フェイルオーバー_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521220/29449841-98ed-d3ad-f9a1-c6a629e798a2.png)

3. __ヘルスチェックのエンドポイントをドメインで指定しており、CDN1/2のドメインは同じため、__ヘルスチェックはCDN2を見て「正常」と判定する（本来はCDN1を見て欲しい）
![フェイルオーバー_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521220/152f3c25-04ba-17c7-4783-ba1f8097eaf6.png)

4. CDN1にフェイルバックする（ああ…）
![フェイルオーバー_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521220/5c27bc6c-b7cf-42cc-7f59-69a91c77aa65.png)

5. CDN1は故障しているので、ヘルスチェックが「異常」と判定する（ふりだし戻ります笑）

というふうに、アクティブ・スタンバイを同じドメインにしたい、かつヘルスチェックのエンドポイントをドメインで指定せざるを得ない状況が重なると、ヘルスチェックがエンドポイントを正確にとらえてくれずに、フェイルオーバーとフェイルバックをバタバタと繰り返してしまいます。IPアドレスで設定できれば問題ないんですけどね。


# 解決策
色々調べたのですが、直接の解決方法はありませんでした。
そもそも、「アクティブ・スタンバイを同じドメインにしたい」かつ「ヘルスチェックのエンドポイントをIPアドレスではなくドメインで指定せざるを得ない」という、そんなことあるんかいなという状況下でのヘルスチェックのやり方なんて、ググれどググれど、どこにもなく。なので、これが間違いなくベストなやり方かは正直なんとも言えないのですが、唯一の苦肉の策ということで、下記参考になれば幸いです。



Route53のヘルスチェックには、__「高度な設定」にて「String Matching (文字列マッチング)」__という機能があります。とりあえず詳細はホワイトペーパーをご一読ください。

https://docs.aws.amazon.com/ja_jp/Route53/latest/DeveloperGuide/health-checks-creating-values.html#health-checks-creating-values-string-matching

> Route 53 で、HTTP または HTTPS リクエストをエンドポイントに送信、または指定文字列のレスポンス本文を検索することにより、エンドポイントの状態を判断するかどうか。[Search String] で指定した値がレスポンス本文に含まれる場合、Route 53 は、そのエンドポイントが正常であると見なします。レスポンス本文に含まれない場合、またはエンドポイントが応答しない場合、Route 53 は、そのエンドポイントを異常と見なします。

こいつを使って運用しようということになりました。
ヘルスチェックの内容が、指定のドメイン名、そしてレスポンス文に"I_AM_CDN1"が含まれるか、を加えていきます。

まず、CDN1のヘルスチェックの設定に、レスポンス文に"I_AM_CDN1"が含まれる、文字列マッチングの設定を行います。加えて、CDN側には、CDN1のみ、レスポンスに"I_AM_CDN1"の文字列を追加するよう設定変更を行います。
こうすることで、フェイルオーバー時、下記の通り問題なく動作するようになります。

+ フェイルオーバー前ヘルスチェックをすると、指定のドメイン名、かつCDN1からのレスポンスには"I_AM_CDN1"が含まれるため、正常とみなします。
![文字列_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521220/b1d05bed-47ee-294f-2fd0-f501664cd3a0.png)

+ CDN2へのフェイルオーバー後、指定のドメイン名ではありますが、CDN2からのレスポンスには"I_AM_CDN1"が含まれていないため、「異常」とみなされるようになります。
![文字列_2 .png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521220/df5d4d5f-cba2-9029-8e08-aa069b00cabd.png)


これで、フェイルオーバー・フェイルバックでバタバタすることはなくなりました。


# 文字列マッチングの設定箇所

+ ヘルスチェックの設定をします。[エンドポイントの指定]をドメイン名とします。ここで設定を終わらせず[高度な設定]をクリックします。
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521220/aa58f00a-eb4c-fe81-a72c-d0807c32a1d3.png)

+ 文字列マッチングは下記の箇所です。5120バイト以内の文字列にする必要があるとのことです。
![図2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521220/9e966a8d-50ad-d97f-6cd1-e2ef5ce08081.png)

+ CloudWatchの設定はひとまずなしとし、[ヘルスチェックの作成]をクリックします。 
![作成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521220/7e598a48-44fc-c0d4-1994-fdb582c6db17.png)

上記の設定をすれば、フェイルオーバー後もヘルスチェックが間違いなく動作します。設定も一瞬ですね。
また、Route53のフェイルオーバールーティングはフェイルバックは自動で行う仕様なのですが、エンドポイントをドメイン名で指定・文字列マッチングにて設定を行う、と自動フェイルバックを無効にすることができます。
フェイルオーバー後に、元アクティブサーバを復旧させた後、確実に手動フェイルバックさせたい、という要望も実現できる設計となりそうです。

# おわりに
よく触るAWSサービスも、実は使ったことがない、調べる機会がない機能ってたくさんあるんだなぁと、勉強になりました。常に好奇心を持ってお仕事をしていきたいと思ったし、あまりブログにてまとめられていないような機能など、積極的に発信していこうと思います。