AWS の DNS フェイルオーバーで、サーバレス&高可用性 Sorry ページを構築する
こんにちは、インフラストラクチャー部の沼沢です。
AWS の DNS フェイルオーバーの設定についての記事はたくさん出回っていますが、今回は Sorry ページに特化した設定をご紹介します。
以前、社内で AWS 上にシステム構築していた際に、例えば「急激なアクセス増で AutoScaling が間に合わないなどでユーザのリクエストに対して正常に応答できない状態に陥ってしまった時に “画面が真っ白な状態が続くこと” だけは避けたい」という要望を受け、最終手段的な位置付けで構築した Sorry ページ表示の仕組みについてご紹介させていただきます。
特段目新しい技術や情報ではありませんが、AWS にてサーバレスで高可用性な Sorry ページを構築する方法の参考になればと思います。
DNSフェイルオーバーとは?
そもそも、DNS フェイルオーバーとはなんなのかを軽くご説明させていただきます。
※DNS 自体の突っ込んだ説明はしませんので、ご了承ください。
DNS は、例えば
- example.com = xxx.xxx.xxx.xxx (Web サーバの IP アドレス)
というように、"ドメイン名" と “実体サーバの IP アドレスなど” を紐付けています。
この時に、"xxx.xxx.xxx.xxx (Web サーバ)“ になんらかの問題が生じ、サービスを継続できない状態に陥った場合に、
- example.com = yyy.yyy.yyy.yyy (別のサーバの IP アドレス)
に自動で変更する仕組みを DNS フェイルオーバーと呼びます。
つまり、とあるドメインへのリクエストを受けているサーバなどで何か問題が生じた場合に、ドメイン名は変更せずに、そのドメインへのリクエストを受ける先を変更する仕組みのことを言います。
AWS の Route53 には、この仕組みが予め用意されており、画面からポチポチするだけで DNS フェイルオーバーを簡単に設定できるようになっています。
サーバレスで高可用性な Sorry ページの仕組み
では本題です。AWS の DNS フェイルオーバー機能を利用し、サーバレスな Sorry ページを構築します。まずは図で見ていただくとわかりやすいと思いますので、以下の構成図をご覧ください。
上図に記載の通り、AWS のサービスは以下を利用しています。
- Route53
- ELB + EC2など (サービス本体のシステム)
- CloudFront + S3 (Sorry ページのシステム)
Route53 が ELB のヘルスチェックのステータスを確認し、ELB が正常と判断している時には ELB 側のレコード情報を、ELB のヘルスチェックで異常と判断されている時には DNS フェイルオーバーが発動し、CloudFront 側のレコード情報を、それぞれアクセス元に返します。
この構成のメリットとデメリット
メリット
・サーバレス
今回のメインのメリットです。サーバレス=自分たちで管理・保守するサーバは存在しません。S3 や CloudFront が動いているサーバの管理・保守は AWS に丸投げできます。
= EC2 で構築する場合よりも、運用コストを大幅に削減できます。
・高可用性
Sorry ページの HTML 自体は S3 に配置してあり、それを CloudFront でキャッシュさせて表示させるため、サーバレスな Sorry ページのシステムとなっています。
CloudFront, S3 の SLA は 99.9%以上であり、高い可用性を簡単に実現できます。
・正常時は Sorry ページシステムの維持費がほぼ0
本構成では、Sorry ページのために利用しているAWSのサービスは、CloudFront と S3 の2つで、これらの料金体系は以下の通りです。(2016年2月現在)
- CloudFront
- データ転送量に対しての課金のみ -> 正常時はデータ転送が発生しないので $0
- S3
- データ保存容量に対しての課金 -> 最高値でも $0.033
- データ転送量に対しての課金 -> In は全て $0、Out は CloudFront への転送は全て $0
- GET リクエストに対して課金 -> 正常時は GET リクエストも発生しないので $0
つまり、正常時の Sorry ページシステムだけのコストとしては、$0.033 だけということになります。
デメリット
・Alias レコードは TTL を変更できない
A レコードの Alias で ELB, CloudFront, S3 の何れかを指定した場合、TTL は 60 秒となり、こちらでは変更できません。
そのため、DNS フェイルオーバーが発動する前に、最大で 1 分間は、絶賛障害発生中の ELB 側にトラフィックが流れてしまうことに留意しなければなりません。
正確には、ELB が各インスタンスへのヘルスチェックで全台を Unhealthy と判定するまでの時間もプラスされます。
この間だけは、"画面が真っ白な状態” となってしまいますので、サービスの SLA 等をご確認の上、導入する必要があります。
各サービスの設定詳細
では、各AWSサービスの設定について、個々に解説していきます。
ELB + EC2 など (サービス本体のシステム)
ELBやその配下のインスタンス等には、特別な設定は一切不要です。
S3(Sorry ページ置き場)
S3 では以下の対応を行います。
- Sorry ページ用の Bucket を作成
- Bucket 名の決まりは特にありません
- 必ず Sorry ページだけのための S3 Bucket を作成してください(後述)
- Sorry ページの HTML を Bucket 直下に配置して Publish(公開)する
- クローラー対策として、以下の内容の robots.txt を Bucket 直下に配置して Publish(公開)する
User-agent: *
Disallow: /
以下の様な状態になっていればOK。
CloudFront(Sorry ページのキャッシュなど)
次に CloudFront です。
CloudFront では、以下の設定を行っていきます。
- 新規の CloudFront Distribution を作成
- Sorry ページ用の Bucket を Origin に指定
- [Alternate Domain Names] に、サービスのドメイン名を指定
今回は “dns-fo.mediba-lab.net” というドメイン名で設定し、設定後検証を行います。
- Sorry ページ用の Bucket を Origin に指定
- 作成した Distribution を選択し、[Error Pages] タブを選択 → [Create Custom Error Response] でカスタムエラーページを以下の通り定義
- [HTTP Error Code] 403: Forbidden
- バックエンド(本構成の場合は S3)からのレスポンスコードが 403 の場合
- [Error Caching Minimum TTL] 300
- エラーを 300 秒キャッシュする
- [Customize Error Response] Yes
- レスポンスをカスタマイズする
- [Response Page Path] /sorry.html
- S3 の Sorry ページ HTML へのパス
- [HTTP Response Code] 503: Service Unavailable
- ステータスコード 503 でレスポンスする
- [HTTP Error Code] 403: Forbidden
上記を図で表すと以下の様なイメージです。
こうすることで、本体サイトのどんな URL でアクセスが来ても、Sorry ページを返却することが可能です。
また、Google などのクローラーに対しても 503 を返せるため、一時的なものであると認識させる事ができます。
この仕組の実現のために、前述した Sorry ページだけのための S3 Bucket が必要となります。
実際に作成した CloudFront のドメインにアクセスすると、どんな URL をリクエストしても、503 で Sorry ページが返ってくることが確認できます。
Route53(DNS フェイルオーバー)
最後に今回のキモ、Route53 で DNSフェイルオーバーを設定します。
正常時のレコードを登録
以下のキャプチャのイメージで、A レコードの Alias で本体サービス側の ELB を指定
- [Routing Policy] Failover
- DNS フェイルオーバーを利用
- [Failover Record Type] Primary
- このレコードが Primary であると定義
- [Set ID] Primary
- 任意の値
- [Evaluate Target Health] Yes
- Alias(ELB)のヘルスチェックを利用する
- [Associate with Health Check] No
- 予め定義してあるヘルスチェックの利用有無
- 今回は ELB のヘルスチェックを利用するようしたので、No を選択
フェイルオーバー先のレコードを登録
以下のキャプチャのイメージで、A レコードの Alias で Sorry ページ用に作成した CloudFront を指定
- [Routing Policy] Failover
- DNS フェイルオーバーを利用
- [Failover Record Type] Secondary
- このレコードが Secondary であると定義
- [Set ID] Secondary
- 任意の値
- [Evaluate Target Health] No
- Alias に CloudFront を指定した場合は、No 固定
- [Associate with Health Check] No
- Secondary 側なので、特にヘルスチェックは入れない
以上の設定で、DNS フェイルオーバーを利用した Sorry ページ対応が完了です。
動作検証
では、最後にこの設定がちゃんと動作するか確認してみます。
正常稼働状態の確認
予め用意してあったトップページ、exmaple ページがステータスコード 200 で正常に表示できました。
DNS フェイルオーバーの確認
では、EC2 上で起動している Apache を停止して、ELB 配下にインスタンスが1台もいない状態を作り、大規模障害が発生したと仮定しましょう。
[ec2-user@ip-xxx-xxx-xxx-xxx ~]$ sudo service httpd stop
Stopping httpd: [ OK ]
Apache 停止直後は、ELB が 504 を返してきています。
その後、数十秒程度で ELB が 503 を返すようになりました。
さらにその後、待つこと 1 〜 2 分程度で、S3 に置いた Sorry ページが表示されるようになりました!
ステータスコードもしっかり 503 になっています。
DNS フェイルバックの確認
最後に、EC2 上で停止中の Apache を起動して、ELB 配下にインスタンスが存在する状態を作り、サービスが復旧したと仮定しましょう。
[ec2-user@ip-xxx-xxx-xxx-xxx ~]$ sudo service httpd start
Starting httpd: [ OK ]
Apache 起動後、同じく 1 〜 2 分程度で正常系のページが返ってくることが確認できます。
まとめ
いかがだったでしょうか。この仕組みを自前で全て構築することを考えた場合に想定されるインフラコストや工数を考えると、かなりのコスト削減&開発期間の短縮に繋がるのではないでしょうか。
また、今回の構成はサーバレスというところが一番のキモで、サービスがリリースされた後の運用面のコストも大幅に削減できると考えています。
少々長くなってしまいましたが、Sorry ページに高可用性を求めている方々の参考になれば幸いです。