こんにちは
ソーイ株式会社 Webエンジニア2年目の村上です。
Webサービスを運用していると、障害によってサービスが停止してしまったり、メンテナンスのために一時的にサービスを停止したりする場面があります。
そのような場合、ユーザーにエラー画面をそのまま表示するのではなく、 現在メンテナンス中です といった案内を表示する、いわゆる Sorryページ を用意することがあります。
AWSについて調べていると、Route 53の フェイルオーバールーティング を利用することで、通常のWebサイトにアクセスできなくなった際、S3に用意した静的なSorryページへアクセス先を切り替える構成が取れることを知りました。
ちょうどAWS資格の勉強を進めていることもあり、今回は実際にRoute 53とS3を使ってSorryページへの切り替えを構築し、フェイルオーバールーティングがどのように動作するのか試してみます。
この記事の概要
取り扱う内容
今回は実際に環境を構築してフェイルオーバーを発生させることで、以下の内容を確認していきます。
-
Route 53のフェイルオーバールーティング -
Route 53によるヘルスチェック - S3を利用した静的なSorryページ
-
Route 53を利用した独自ドメインの設定
前提条件
今回の検証では、以下を前提としています。
- AWSアカウントを利用できること
- 検証に使用できる独自ドメインを取得していること
-
Route 53、EC2、S3の基本的な操作ができること
検証にかかった料金
今回使用したRoute 53のホストゾーンやヘルスチェック、EC2など、一部のAWSリソースでは料金が発生します。
今回はネームサーバー変更後、DNSキャッシュの影響により反映まで時間がかかったため、検証環境を約1日稼働させました。
その際、今回の検証で使用したAWSサービスでは以下の料金が発生しました。
| サービス | 料金 |
|---|---|
| Route 53 | $0.50 |
| EC2 インスタンス | $0.33 |
| VPC | $0.12 |
| EC2 その他 | $0.02 |
| S3 | $0.00 |
| 合計 | $0.97 |
今回の検証では、合計で約 $0.97 の料金が発生しました。
上記は今回の検証時に実際に発生した料金です。
利用時間やリージョン、各サービスの料金改定などによって実際の料金は異なるため、あくまで参考値としてご確認ください。
構成図
通常時はRoute 53によって通常のWebページへルーティングし、障害を検知した場合はS3に用意したSorryページへ切り替えます。
Route 53のフェイルオーバールーティングとは
Route 53のフェイルオーバールーティングは、正常時と障害時でDNSの応答先を切り替えるためのルーティングポリシーです。
フェイルオーバールーティングでは、アクセス先を主に以下の2つに分けて設定します。
- Primary(プライマリ):通常時に利用するアクセス先
- Secondary(セカンダリ):Primaryが利用できない場合のアクセス先
今回の構成では、通常のWebページを提供するEC2をPrimary、Sorryページを配置するS3をSecondaryとして設定します。
また、Primary側にはRoute 53のヘルスチェックを設定します。
ヘルスチェックが正常な間はPrimaryへアクセスさせ、異常と判断された場合にはSecondaryへDNSの応答先を切り替えます。
つまり今回作成する構成では、
正常時:Route 53 -> EC2(通常ページ)
障害時:Route 53 -> S3(Sorryページ)
という切り替えをRoute 53のフェイルオーバールーティングによって実現します。
公式docs
検証環境の作成
Sorryページを表示するために、ドメインやEC2、S3などの環境を設定していきます。
1. Route 53へドメインを設定
まずは、今回の検証で使用するドメインをRoute 53で管理できるようにします。
今回は、お名前.comで取得した以下のドメインを使用します。
routetes.com
お名前.com
AWSマネジメントコンソールから Route 53 を開き、 ホストゾーン -> ホストゾーンの作成 を選択します。
ホストゾーンの設定では、以下の内容を入力し、 ホストゾーンの作成 を選択します。
ドメイン名:routetes.com(登録するアドレス名)
タイプ:パブリックホストゾーン
説明は管理用にこのドメインが何なのか記載しておくとよいです。
タグをつけておくのも管理用としてよいですが、今回はなしです。
ホストゾーンを作成すると、Route 53によってNSレコードとSOAレコードが自動的に作成されます。
この状態で生成されたNSレコードの、値/トラフィックのルーティング先 を確認すると、以下のような4つの値が確認できます。
Route 53のNSレコードでは、ネームサーバー名の末尾に . が付いています。これはDNS上で 完全修飾ドメイン名(FQDN) であることを表すものです。
お名前.comのネームサーバー設定では、末尾の . を除いた値を入力します。DNSサービスによって入力形式が異なる場合があるため、利用するサービスの仕様を確認してください。
ns-xxxx.awsdns-xx.com
ns-xxxx.awsdns-xx.net
ns-xxxx.awsdns-xx.org
ns-xxxx.awsdns-xx.co.uk
これはネームサーバーといわれるもので、そのドメインに関するDNSの問い合わせに対して、どの情報を返すかを管理するサーバーです。
今回は、お名前.comで取得したドメインのネームサーバーをこれらの値に変更することで、routetes.com のDNS管理をRoute 53に委任します。
routetes.com
│
│ DNS問い合わせ
▼
Route 53
お名前.comを使っている場合は、ネームサーバー設定のその他のネームサーバーを使うという設定欄に追加してください。
使っているサービスによって違うため、詳しいネームサーバー設定は割愛します。
2. EC2サーバーの準備
このセクションはサクッと行きます。
完成形としては以下の流れができる環境まで作成します。
Public Subnet
│
▼
EC2
Public IPv4あり
│
Security Group
│
TCP : 80
▲
│
インターネット
まず通常アクセス先(Primary)として使うためにEC2を起動します。
AWSマネジメントコンソールから EC2 -> インスタンス -> インスタンスを起動 を選択します。
今回は検証用で作成するため設定は以下で進めます。
IPv4 CIDR:10.0.0.0/16
AZの数:1
パブリックサブネット:1
プライベートサブネット:0
NAT Gateway:なし
VPC Endpoint:なし
DNSホスト名:有効
DNS解決:有効
AZ数や、パブリックサブネット数などの項目は、
VPCを作成 -> 作成するリソース欄の VPCなど を選択すると、設定項目が現れます。
AMI:Amazon Linux 2023
インスタンスタイプ:t2.micro
VPCは作成したものを選択
パブリックIP:有効
ストレージ:デフォルトでOK
キーペア:なし
次に後ほどRoute 53のヘルスチェックを行うため、セキュリティグループ設定からHTTP通信を許可します。
以下はインターネットにHTTPを公開する検証用の設定です。
タイプ:HTTP
プロトコル:TCP
ポート:80
ソース:0.0.0.0/0
今回は、接続できることとページの表示を確認できればよいため、EC2のユーザーデータを利用してApacheと簡単なHTMLを起動時に用意して確認します。
高度な詳細 -> ユーザーデータ に以下を記入しました。
ユーザーデータはインスタンス停止中のみ編集できます。
すでに作成済みの場合は一度インスタンスを停止して確認してください。
#!/bin/bash
dnf install -y httpd
systemctl enable httpd
systemctl start httpd
cat <<'EOF' > /var/www/html/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>通常ページ</title>
</head>
<body>
<h1>Webサイトは正常に稼働しています</h1>
</body>
</html>
EOF
インスタンスを起動後に、
EC2に割り当てられたパブリックIPv4アドレスを使って以下にアクセスします。
http://<EC2のパブリックIPv4アドレス>
以下の表示が確認できれば準備完了です。
Webサイトは正常に稼働しています
3. S3にSorryページを保存
次はS3側にSorryページを登録します。
AWSコンソールから S3 -> バケットを作成 を開き、作成を行います。
バケットタイプ:汎用
バケット名:routetes.com
オブジェクト所有者:ACL無効
パブリックアクセス:すべてオフ
デフォルトの暗号化:SSE-S3
バケットキー:デフォルトのまま
今回はS3の静的ウェブサイトホスティングを利用してSorryページを公開するため、ブロックパブリックアクセスをすべてオフにしています。
ここでポイントになるのが、バケット名です。
今回Route 53からS3の静的ウェブサイトへルーティングするため、S3バケット名をRoute 53で使用するドメイン名と同じ routetes.com にします。
AWS公式のS3へのルーティング手順でも、Route 53でS3 Website EndpointをAlias先として選択する場合、バケット名とルーティングするドメイン/サブドメイン名を一致させる構成になっています。
バケット作成後は、Sorryページとなる静的ファイルをアップロードしてください。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>メンテナンス中</title>
<style>
:root {
color-scheme: light dark;
}
body {
margin: 0;
font-family: "Segoe UI", "Noto Sans JP", sans-serif;
background: linear-gradient(135deg, #f8fafc, #e2e8f0);
color: #0f172a;
display: grid;
place-items: center;
min-height: 100vh;
padding: 24px;
box-sizing: border-box;
}
.card {
max-width: 640px;
width: 100%;
background: rgba(255,255,255,0.9);
border: 1px solid rgba(15,23,42,0.08);
border-radius: 20px;
box-shadow: 0 20px 45px rgba(15,23,42,0.12);
padding: 40px 32px;
text-align: center;
}
h1 {
margin: 0 0 12px;
font-size: clamp(1.8rem, 2.4vw, 2.6rem);
}
p {
margin: 0 0 16px;
line-height: 1.7;
font-size: 1rem;
color: #334155;
}
.badge {
display: inline-block;
padding: 8px 14px;
border-radius: 999px;
background: #2563eb;
color: white;
font-weight: 700;
margin-bottom: 20px;
}
</style>
</head>
<body>
<main class="card">
<div class="badge">メンテナンス中</div>
<h1>現在、サービスを更新しています</h1>
<p>ご不便をおかけして申し訳ありません。しばらくお待ちいただいたのち、再度アクセスしてください。</p>
<p>復旧まで今しばらくお待ちください。</p>
</main>
</body>
</html>
アップロード後に、
プロパティ -> 静的ウェブサイトホスティング -> 編集
と進み、有効にしてください。
設定時、インデックスドキュメントという項目に、アップロードした静的ファイル名を入力してください。
設定保存時に、以下のような バケットウェブサイトエンドポイント が表示されるので保存しておいてください。
http://routetes.com.s3-website-ap-northeast-1.amazonaws.com
最後に、ブロックパブリックアクセスを無効にしただけでは、インターネットからS3バケット内のオブジェクトを読み取ることはできません。
そのため、追加で バケットポリシー を設定し、オブジェクトの読み取りを許可します。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::routetes.com/*"
}
]
}
これで、routetes.com バケット内のオブジェクトに対する読み取り(GetObject) だけを公開します。
ここまで設定できたら、S3単体で表示を確認します。
最後、プロパティ->静的ウェブサイトホスティングに表示されているバケットウェブサイトエンドポイントを開き、ページが確認できれば設定完了です。
4. Route 53のヘルスチェック作成
フェイルオーバーの肝になるヘルスチェックの作成を行います。
AWSコンソールから、
Route 53 -> ヘルスチェック -> ヘルスチェックの作成 を選択します。
名前:自由記入
モニタリング対象:エンドポイント
エンドポイントの指定:IPアドレス
プロトコル:HTTP
IPアドレス:EC2のパブリックIPv4
ポート:80
パス:/
リクエスト間隔:30秒
失敗しきい値:3
ヘルスチェックでは、Route 53のヘルスチェッカーがEC2のパブリックIPv4アドレスへ定期的にアクセスします。
EC2側のSecurity Groupで
HTTP / TCP / 80 / 0.0.0.0/0
を許可しているのでRoute 53のヘルスチェッカーからもアクセスできます。
5. Primary、Secondaryレコードを作成する
ここまで作成したEC2とS3をRoute 53のフェイルオーバールーティングに設定していきます。
まず、Primary -> EC2から作成していきます。
Primaryレコードの作成
Route 53から、
ホストゾーン -> routetes.com -> レコードを作成
と進みます。
以下の設定を行います。
レコード名:空欄
レコードタイプ:A
エイリアス:OFF
値:EC2のパブリックIPv4
TTL:60秒
ルーティングポリシー:フェイルオーバー
フェイルオーバーレコードタイプ:プライマリ
ヘルスチェック:先ほど作成したEC2用Health Check
レコードID:primary-ec2などで登録
Secondaryレコードを作成する
続いて、同じ routetes.com にもう1つレコードを作成します。
以下の設定を行います。
レコード名:空欄
レコードタイプ:A
エイリアス:ON
トラフィックのルーティング先:S3ウェブサイトエンドポイントへのエイリアス
リージョン:S3を作成したリージョン
ルーティングポリシー:フェイルオーバー
フェイルオーバーレコードタイプ:セカンダリ
レコードID:secondary-s3などで登録
Secondary側にヘルスチェック設定は不要です。
Primary、Secondaryの設定により、以下のような状態になります。
routetes.com
│
├── Primary
│ A → EC2 Public IPv4
│ ↑
│ Health Check
│
└── Secondary
Alias → S3 Website Endpoint
動作確認
検証環境の作成が終わりましたので、実際にやってみます。
今回は検証として、正常時、障害発生時、復旧時の3項目で確認します。
正常時
まず、Primaryとして設定したEC2が正常に稼働している場合の動作を確認します。
EC2の管理画面から、対象インスタンスが実行中になっていることを確認します。
次にRoute 53から、
ヘルスチェック -> **作成したヘルスチェック
**
を開き、ステータスが以下になっていることを確認します。
ステータス:正常(Healthy)
この状態で、実際にブラウザから以下URLにアクセスします。
http://<設定したドメイン>
# 今回はhttp://routetes.com
アクセス後にEC2側の画面が表示されれば、正常時の動作確認は完了です。
ブラウザでの表示に加えて、nslookupを使用して正常時のDNS応答も確認します。
以下コマンドをコマンドプロンプトで実行してください。
nslookup routetes.com
今回の環境では以下が出力されました。
名前: routetes.com
Address: 52.195.175.204
Addressに表示されたIPアドレスが、設定したEC2のパブリックIPv4アドレスと一致しているか確認してください。
一致していれば正常に接続できています。
接続できない場合
接続できない場合は、以下のコマンドを用いて接続先の確認を行ってください。
# ネームサーバーが、割り当てられた4つのNSで適用されているか
nslookup -type=NS ドメイン名
# Route 53に登録したEC2のパブリックIPv4が返ってくるか
nslookup routetes.com
なお、ネームサーバーの変更直後は、DNSキャッシュの影響により変更前の情報が返ってくる場合があります。
今回の検証でも、nslookup -type=NS を実行したところ、変更前のお名前.comのネームサーバーが返ってくる場合があり、その状態でページにアクセスしてもお名前.comのページに飛ぶのみでした。
実際に遷移したページ
設定内容に問題がない場合は、DNSの反映を待ってから再度確認しましょう。
障害発生時
では、本題に入ります。
PrimaryのEC2を意図的に停止して、SecondaryのS3 Sorryページへフェイルオーバーするかを確認しましょう。
EC2のインスタンスを停止してみましょう。
Webサーバーへアクセスできなくなり、Route 53のヘルスチェックが失敗するようになるはずです。
EC2停止
↓
HTTPで応答できなくなる
↓
Route 53 Health Check
↓
Unhealthy
Route 53のヘルスチェックを開き、作成したヘルスチェックのステータスが、異常(Unhealthy) になっていることを確認しましょう。
確認したら、先ほどEC2で表示されていたページへ再度アクセスしてみましょう。
ここで、S3に配置したSorryページが表示されればフェイルオーバー成功です。
ブラウザでの表示に加えて、nslookupを使用してフェイルオーバー後のDNS応答も確認します。
以下コマンドをコマンドプロンプトで実行してください。
nslookup routetes.com
今回の環境では以下が出力されました。
名前: routetes.com
Addresses: 3.5.157.233
52.219.152.123
52.219.200.19
3.5.159.112
52.219.162.163
52.219.151.119
52.219.137.39
52.219.68.204
正常時はPrimaryレコードに設定したEC2のパブリックIPv4アドレスが返されていましたが、フェイルオーバー後は異なるIPアドレスが複数返されました。
S3の静的ウェブサイトエンドポイントはEC2のように単一の固定IPアドレスを持つものではないため、nslookupでは複数のIPアドレスが返される場合があります。
この結果から、DNSの応答先がPrimaryのEC2からSecondaryのS3へ切り替わったことを確認できました。
流れとしては構成図でも示しましたが、以下の流れになります。
EC2を停止
↓
Route 53のヘルスチェッカーが
http://EC2のIP:80/ へアクセス
↓
応答が返ってこない
↓
一定回数ヘルスチェックに失敗
↓
Unhealthyと判定
↓
PrimaryをDNS応答から除外
↓
Secondary(S3)を返す
今回はリクエスト間隔を30秒、失敗しきい値を3回として設定しています。
実際にEC2を停止してからSorryページが表示されるまでを計測したところ、2分31秒で切り替わることを確認できました。
復旧時
S3の静的ページが表示されることを確認したら、EC2インスタンスを再度起動します。
EC2 -> インスタンス -> route53-test -> インスタンスの状態 -> インスタンスを開始
ステータスが実行中になったら再度ページへ訪問して表示を確認しましょう。
EC2側で設定したページが表示されれば復旧確認成功です。
注意:再起動時のパブリックIPv4アドレス
今回の構成では、Route 53のPrimaryレコードおよびヘルスチェックの接続先として、EC2のパブリックIPv4アドレスを直接指定しています。
EC2に自動割り当てされたパブリックIPv4アドレスは、インスタンスを停止して再度起動すると変更される場合があります。
再起動時に変更を確認したら以下の設定を新しいIPアドレスへ変更してください。
Route 53のPrimary Aレコード
Route 53のヘルスチェックで指定したIPアドレス
パブリックIPv4アドレスを変更したくない場合は、Elastic IP(EIP)をEC2に割り当てることで固定のパブリックIPv4アドレスを利用できます。
今回は検証用で作成したので設定していません。
まとめ
今回は、Route 53のフェイルオーバールーティングを利用して、EC2で稼働しているWebサーバーに障害が発生した際に、S3でホストしているSorryページへ切り替える構成を作成しました。
実際にEC2を停止することで、正常時はPrimaryのEC2へアクセスするものが、SecondaryのS3へフェイルオーバーするという一連の動作を確認できました。
この動作が接続の結果に応じてDNSの応答先を切り替える仕組みであることが理解できました。
今回学んだフェイルオーバーの仕組みは、業務におけるWebサービスの障害対策や可用性を考える上でも活用できる知識だと感じました。
次回の展望
今回の検証では、EC2・S3ともにHTTPでアクセスする構成としました。
しかし一般的なWebサイトではHTTPSが利用されることが一般的です。
今回使用したS3の静的ウェブサイトホスティング用エンドポイントはSSL/TLS証明書を割り当てられず、HTTPSに対応していないため、今回の構成をそのままHTTPSのWebサイトに適用することはできません。
HTTPSの障害となると、証明書の期限切れやTLS関連の問題によってHTTPSで正常にアクセスできないといったケースも考えられます。
次回はCloudFrontやACMを活用してHTTPSでもSorryページが表示できるか検証してみたいと考えています。
お知らせ
技術ブログを週1〜2本更新中、ソーイをフォローして最新記事をチェック!
https://qiita.com/organizations/sewii





