Route 53 DNSフェイルオーバー完全ガイド:EC2障害時にS3静的サイトへ自動切り替えする方法
本番EC2インスタンスが深夜に突然ダウンした経験があるなら、DNSフェイルオーバーの重要性は身に染みているはずだ。Route 53のヘルスチェックとフェイルオーバールーティングを組み合わせれば、EC2が応答しなくなった瞬間にS3の静的サイトへ自動的にトラフィックを切り替えられる。このガイドでは、Route 53 DNSフェイルオーバーの仕組みから実際の設定手順まで、プロダクション環境で使える形で解説する。
TL;DR:Route 53 DNSフェイルオーバーの全体像
| 項目 | 内容 |
|---|---|
| 目的 | EC2障害時にS3静的サイトへ自動DNS切り替え |
| 主要コンポーネント | Route 53ヘルスチェック、フェイルオーバールーティングポリシー、S3静的ウェブサイトホスティング |
| 切り替えの目安 | ヘルスチェック失敗判定後、TTL経過で切り替わる(TTL設定値に依存) |
| 必要なレコードタイプ | PRIMARY(EC2向け)とSECONDARY(S3向け)の2レコード |
| コスト要因 | ヘルスチェック料金、Route 53クエリ料金(最新料金は公式ドキュメント参照) |
| 主な注意点 | S3静的ウェブサイトエンドポイントはHTTPSを直接サポートしない |
Route 53フェイルオーバーの仕組み
フェイルオーバールーティングポリシーは、レコードをPRIMARYとSECONDARYの2種類に分類する。Route 53はPRIMARYレコードに紐付けられたヘルスチェックを定期的に実行し、失敗と判定した場合にSECONDARYレコードを返すよう切り替える。ヘルスチェックはRoute 53のグローバルなヘルスチェッカーネットワークから実行されるため、単一リージョンの問題ではなく、広域での到達不能を検知する。
重要なのは、DNS応答の切り替えはTTLに依存するという点だ。ヘルスチェックが失敗を検知してもTTLが長ければ、クライアントはキャッシュされた古いIPアドレスを使い続ける。フェイルオーバーの応答速度を重視するなら、TTLを低く設定する必要がある。ただし、TTLを下げるとRoute 53へのクエリ頻度が上がり、コストに影響する。
- 通常時:クライアントのDNSクエリに対し、Route 53はPRIMARYレコード(EC2のIPアドレス)を返す。
- ヘルスチェック失敗:Route 53のヘルスチェッカーがEC2への疎通確認に失敗し、PRIMARYレコードを「不健全」と判定する。
- フェイルオーバー発動:以降のDNSクエリに対し、Route 53はSECONDARYレコード(S3静的ウェブサイトエンドポイント)を返す。
- 復旧後:EC2が回復してヘルスチェックが連続成功すると、Route 53は自動的にPRIMARYレコードの返却を再開する。
前提条件の確認
設定を始める前に、以下が揃っていることを確認する。
- Route 53でホストゾーンが作成済みであること(ドメインのNSレコードがRoute 53を向いていること)
- EC2インスタンスにElastic IPが割り当て済みであること(IPアドレスが変わるとヘルスチェックが機能しない)
- S3バケットが静的ウェブサイトホスティング用に設定済みであること
- フェイルオーバー先のS3バケット名がドメイン名と一致していること(例:
example.comというドメインならバケット名もexample.com)
ステップ1:S3バケットの静的ウェブサイトホスティング設定
フェイルオーバー先となるS3バケットを準備する。バケット名はRoute 53で使用するドメイン名と完全一致させる必要がある。これはS3の静的ウェブサイトホスティングの仕様であり、エイリアスレコードでS3エンドポイントを参照する際に必須となる。
# バケットの静的ウェブサイトホスティングを有効化
aws s3api put-bucket-website \
--bucket example.com \
--website-configuration '{
"IndexDocument": {"Suffix": "index.html"},
"ErrorDocument": {"Key": "error.html"}
}'
# バケットのパブリックアクセスブロック設定を確認・調整
# 静的ウェブサイトとして公開するには、パブリックアクセスを許可する必要がある
aws s3api get-public-access-block --bucket example.com
# パブリックアクセスブロックを無効化(静的ウェブサイト公開に必要)
aws s3api put-public-access-block \
--bucket example.com \
--public-access-block-configuration \
'BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false'
次に、バケットポリシーでパブリック読み取りを許可する。
# バケットポリシーを適用してパブリック読み取りを許可
aws s3api put-bucket-policy \
--bucket example.com \
--policy '{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::example.com/*"
}
]
}'
# メンテナンスページ(index.html)をアップロード
aws s3 cp index.html s3://example.com/index.html
S3の静的ウェブサイトエンドポイントのURLはリージョンによって形式が異なる。設定後に確認しておく。
# ウェブサイトエンドポイントを確認
aws s3api get-bucket-website --bucket example.com
ステップ2:Route 53ヘルスチェックの作成
ヘルスチェックはPRIMARYレコードの健全性を監視する核心部分だ。ここでの設定ミスがフェイルオーバーの精度を左右する。EC2インスタンスのElastic IPに対してHTTPまたはHTTPSでチェックを行う。
# EC2インスタンスへのHTTPヘルスチェックを作成
aws route53 create-health-check \
--caller-reference "$(date +%s)" \
--health-check-config '{
"IPAddress": "203.0.113.10",
"Port": 80,
"Type": "HTTP",
"ResourcePath": "/health",
"FullyQualifiedDomainName": "example.com",
"RequestInterval": 30,
"FailureThreshold": 3
}'
RequestIntervalは30秒(標準)または10秒(高速)を選択できる。FailureThresholdは連続失敗回数の閾値で、デフォルトは3回だ。標準インターバルで閾値3の場合、最大で約90秒後にフェイルオーバーが発動する計算になる(ヘルスチェック判定後、TTLの経過も必要)。
# 作成したヘルスチェックのIDを確認
aws route53 list-health-checks \
--query 'HealthChecks[*].{ID:Id,Config:HealthCheckConfig}' \
--output table
返ってきたヘルスチェックIDを控えておく。次のステップで使用する。
ステップ3:フェイルオーバーレコードの作成(PRIMARY)
PRIMARYレコードはEC2インスタンスを向き、先ほど作成したヘルスチェックと紐付ける。ヘルスチェックIDの紐付けを忘れると、EC2が落ちてもフェイルオーバーが発動しない。これは設定ミスの中で最も多いパターンだ。
# ホストゾーンIDを確認
aws route53 list-hosted-zones \
--query 'HostedZones[*].{Name:Name,ID:Id}' \
--output table
# PRIMARYフェイルオーバーレコードを作成
# HEALTH_CHECK_IDは前のステップで取得した値に置き換える
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890ABC \
--change-batch '{
"Changes": [
{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "example.com",
"Type": "A",
"SetIdentifier": "primary-ec2",
"Failover": "PRIMARY",
"TTL": 60,
"ResourceRecords": [
{"Value": "203.0.113.10"}
],
"HealthCheckId": "HEALTH_CHECK_ID"
}
}
]
}'
TTLを60秒に設定した場合、フェイルオーバー発動後もクライアントが最大60秒間は古いIPをキャッシュし続ける可能性がある。これは信号機のタイムラグに似ている。青信号(EC2)が赤に変わっても、交差点に入ってしまった車(キャッシュされたDNS応答)はすぐには止まれない。
ステップ4:フェイルオーバーレコードの作成(SECONDARY)
SECONDARYレコードはS3の静的ウェブサイトエンドポイントをエイリアスで参照する。S3エンドポイントへのエイリアスレコードはIPアドレスではなくDNS名で参照するため、AliasTargetを使用する。S3静的ウェブサイトのエイリアスターゲットのホストゾーンIDはリージョンごとに異なるため、AWS公式ドキュメントのS3エンドポイント一覧で確認すること。
# SECONDARYフェイルオーバーレコードをS3エイリアスで作成
# HostedZoneIdはS3のリージョン別ホストゾーンID(us-east-1の場合はZ3AQBSTGFYJSTF)
# DNSNameはS3静的ウェブサイトエンドポイントのDNS名
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890ABC \
--change-batch '{
"Changes": [
{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "example.com",
"Type": "A",
"SetIdentifier": "secondary-s3",
"Failover": "SECONDARY",
"AliasTarget": {
"HostedZoneId": "Z3AQBSTGFYJSTF",
"DNSName": "s3-website-us-east-1.amazonaws.com",
"EvaluateTargetHealth": false
}
}
}
]
}'
SECONDARYレコードにはヘルスチェックを紐付けない。SECONDARYはPRIMARYが不健全な場合の最終フォールバックであり、常に有効である必要があるからだ。
ステップ5:設定の確認と動作検証
設定が完了したら、実際にフェイルオーバーが機能するか確認する。ヘルスチェックの状態をモニタリングしながら、EC2を意図的に停止してみるのが最も確実な検証方法だ。
# ヘルスチェックの現在の状態を確認
aws route53 get-health-check-status \
--health-check-id HEALTH_CHECK_ID
# 現在のDNSレコード設定を確認
aws route53 list-resource-record-sets \
--hosted-zone-id Z1234567890ABC \
--query 'ResourceRecordSets[?Name==`example.com.`]'
# EC2インスタンスを停止してフェイルオーバーをテスト
aws ec2 stop-instances --instance-ids i-0123456789abcdef0
# ヘルスチェックが失敗に変わるまで状態を監視
aws route53 get-health-check-status \
--health-check-id HEALTH_CHECK_ID \
--query 'HealthCheckObservations[*].{Region:Region,Status:StatusReport.Status}'
EC2停止後、ヘルスチェックがFailureに変わるまで待つ。その後、digやnslookupでDNS応答が変わったことを確認する。
# DNS応答を確認(TTL経過後にS3エンドポイントのIPが返るはず)
dig example.com +short
# Route 53のDNSサーバーに直接クエリして確認
dig @ns-XXXX.awsdns-XX.com example.com
- HEALTHY状態:ヘルスチェックが成功し続けている通常状態。PRIMARYレコード(EC2)が返される。
- チェック失敗:EC2への接続が失敗し始める。
FailureThreshold回連続失敗するまでPRIMARYのまま。 - UNHEALTHY判定:閾値を超えてPRIMARYが不健全と判定される。Route 53はSECONDARY(S3)を返し始める。
- 復旧確認:EC2が再起動してヘルスチェックが成功し始める。連続成功後にPRIMARYへ自動復帰。
実際の障害で学んだこと:よくある誤診パターン
フェイルオーバーを設定したのに切り替わらない、という問い合わせで最も多い原因はヘルスチェックとPRIMARYレコードの紐付け漏れだ。Route 53コンソールでレコードを見ると、ヘルスチェックの列が空欄になっている。「設定した」という記憶があるのに動かない。
実際に確認すると、ヘルスチェックは作成されているが、フェイルオーバーレコードのHealthCheckIdフィールドが未設定だった。Route 53はヘルスチェックIDが紐付いていないPRIMARYレコードを「常に健全」として扱う。EC2が落ちていても、Route 53の視点ではPRIMARYは正常なのでフェイルオーバーが発動しない。
もう一つの落とし穴は、S3バケット名とドメイン名の不一致だ。エイリアスレコードでS3静的ウェブサイトエンドポイントを参照する場合、バケット名がドメイン名と一致していないと、S3側でリクエストを処理できずに301リダイレクトや403エラーが返る。フェイルオーバー自体は機能しているのに、ユーザーにはエラーページが表示されるという状況になる。
ヘルスチェックIDの紐付けは、フェイルオーバーの「引き金」そのものだ。引き金のない銃は、どれだけ狙いを定めても撃てない。
HTTPSとCloudFrontを使う場合の考慮点
S3の静的ウェブサイトエンドポイントはHTTPSを直接サポートしない。フェイルオーバー先でもHTTPSを維持したい場合は、S3の前段にCloudFrontを配置する構成が必要になる。この場合、SECONDARYレコードはS3エンドポイントではなくCloudFrontディストリビューションのドメイン名をエイリアスで参照する形になる。
CloudFrontを使う構成では、CloudFrontのオリジンとしてS3静的ウェブサイトエンドポイントを設定し、Route 53のSECONDARYレコードがCloudFrontを向く。ただし、CloudFrontのキャッシュ動作がフェイルオーバーの見え方に影響する点は理解しておく必要がある。
IAMポリシー:CLI操作に必要な権限
上記のCLI操作を実行するIAMユーザーまたはロールには、以下の権限が必要だ。最小権限の原則に従い、対象リソースを絞ること。
🔽 必要なIAMポリシーの例(クリックして展開)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Route53FailoverManagement",
"Effect": "Allow",
"Action": [
"route53:CreateHealthCheck",
"route53:GetHealthCheck",
"route53:GetHealthCheckStatus",
"route53:ListHealthChecks",
"route53:UpdateHealthCheck",
"route53:ChangeResourceRecordSets",
"route53:ListResourceRecordSets",
"route53:ListHostedZones",
"route53:GetHostedZone"
],
"Resource": "*"
},
{
"Sid": "S3WebsiteConfiguration",
"Effect": "Allow",
"Action": [
"s3:PutBucketWebsite",
"s3:GetBucketWebsite",
"s3:PutBucketPolicy",
"s3:GetBucketPolicy",
"s3:PutPublicAccessBlock",
"s3:GetPublicAccessBlock",
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::example.com",
"arn:aws:s3:::example.com/*"
]
},
{
"Sid": "EC2InstanceControl",
"Effect": "Allow",
"Action": [
"ec2:StopInstances",
"ec2:StartInstances",
"ec2:DescribeInstances"
],
"Resource": "arn:aws:ec2:us-east-1:123456789012:instance/i-0123456789abcdef0"
}
]
}
Route 53のヘルスチェック操作やレコード操作は、多くのRead/List系アクションで"Resource": "*"が必要になる。Service Authorization Referenceで各アクションのリソースレベルサポートを確認すること。
Route 53 DNSフェイルオーバーのまとめと次のステップ
Route 53 DNSフェイルオーバーの設定は、ヘルスチェックの作成、PRIMARYレコードへの紐付け、SECONDARYレコードのS3エイリアス設定という3つのステップが核心だ。設定後は必ず実際にEC2を停止して動作を確認すること。フェイルオーバーは「設定した」だけでは不十分で、「実際に切り替わることを確認した」状態にして初めて信頼できる。
次のステップとして、以下を検討することを推奨する。
- CloudWatch Alarmとヘルスチェックを連携させて、フェイルオーバー発動時にSNS通知を受け取る
- フェイルオーバー先のS3サイトに「メンテナンス中」のメッセージだけでなく、問い合わせ先や復旧見込みを記載する
- TTL値を本番環境の許容ダウンタイムに合わせて調整する
- 定期的なフェイルオーバーテストをRunbookに組み込む
公式ドキュメント:Amazon Route 53 Developer Guide - DNS Failover
用語集
| 用語 | 説明 |
|---|---|
| フェイルオーバールーティングポリシー | Route 53のルーティングポリシーの一種。PRIMARYレコードが不健全な場合にSECONDARYレコードへ自動切り替えする。 |
| ヘルスチェック | Route 53がエンドポイントの可用性を定期的に確認する仕組み。HTTP/HTTPS/TCPプロトコルをサポート。 |
| エイリアスレコード | AWSリソース(S3、CloudFrontなど)のDNS名を参照するRoute 53固有のレコードタイプ。CNAMEと異なりゾーンApexでも使用可能。 |
| TTL(Time To Live) | DNSレコードがキャッシュされる秒数。低いほどフェイルオーバーが速く反映されるが、クエリ頻度が上がる。 |
| S3静的ウェブサイトホスティング | S3バケットをHTTPウェブサーバーとして機能させる機能。HTMLやCSSなどの静的コンテンツを配信できる。 |
コメント
コメントを投稿