
AWSでSorryページの実装:Route53によるフェールオーバー設定
こんにちは、TAMの石川です。
Webサイトが障害やメンテナンスで停止している際に表示するSorryページをAWS上で切り替える方法として、CloudFrontのカスタムエラーページを利用するケースが多いかと思います。
今回は、Route53を活用して同じことができるかを検証してみました。
この記事の目次
Sorryページの実現方法
AWSでSorryページを実現する方法はいくつかあります。
- CloudFrontのカスタムエラーページを利用(任意のページを表示可能)
- ALBのRule設定(カスタムページの表示可。ただし256バイトのサイズ制限あり)
- Route53のフェールオーバー設定を利用
今回は、あまり活用されていないRoute53を使った設定を試してみたいと思います。
Route53のフェールオーバー設定の仕組み
Route53はDNSのサービスであり、複雑な処理はできませんが、DNSのレコード応答を制御する以下の2つのオプションが用意されています。
Failover(フェールオーバー)
1つのDNSレコードに対し、プライマリとセカンダリを設定し、それぞれにヘルスチェックを用意します。 プライマリのヘルスチェックが失敗すると、セカンダリのレコードへ切り替わる仕組みです。
※プライマリは1つのみ登録可能です。
Weight(重み付け)
Route53の優先度付け機能を活用し、同じレコード内でヘルスチェックの状況に応じて複数のサーバーを名前解決先として設定できます。
例:
- web01(Weight: 50)
- web02(Weight: 50)
- Sorry(Weight: 0)
通常はweb01・web02へトラフィックが振り分けられますが、両方がダウンした場合はSorryページへ流れる仕組みです。
Sorryページへの遷移時の挙動とSEOの考慮点
Sorryページへのフェールオーバーは正常に動作しますが、1つ懸念点があります。
- SorryページがHTTP 200 OKで応答するため、一度Sorryに切り替わるとブラウザキャッシュが残り、ページを更新しても元のコンテンツが表示されないことがある。
- SEOを考慮すると、Sorryページのレスポンスコードは**403(Forbidden)や500(Internal Server Error)**で返すのが適切。
そのため、SEOを意識する場合は適切なエラーレスポンスを設定することが重要です。
Route53のFailoverとWeightを利用した環境構築
ここでは、Route53のFailoverおよびWeightを利用した環境を構築するためのyamlを紹介します。
注意: これらの設定にはVPC、Subnet、AMIのイメージID、Route53のHostedZoneIDなどが含まれており、適用環境を考慮する必要があります。
FilaOver設定の環境を作るyaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
Parameters: KeyName: Description: The EC2 Key Pair to allow SSH access to the instance Type: "AWS::EC2::KeyPair::KeyName" VPCID: Type: String Default: "vpc-6a3b310e" SubnetID01: Type: String Default: "subnet-989aecee" SubnetID02: Type: String Default: "subnet-989aecee" SubnetID03: Type: String Default: "subnet-989aecee" IMAGEID: Type: String Default: "ami-0f7691f59fd7c47af" ### Route53 ### HostedZoneId: Type: String Default: "Z3P0P51LUVW4NB" HostedZoneName: Type: String Default: "kapodev.work" HostedServerName: Type: String Default: "hogeraccho" SetIdentifierBase: Type: String Default: "hogeraccho" Resources: ### 1 dai me ### DEPLOYSG01: Type: AWS::EC2::SecurityGroup Properties: GroupName: deploy-CFn01 GroupDescription: Allow SSH and HTTP access only MyIP VpcId: !Ref VPCID SecurityGroupIngress: # http - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: "0.0.0.0/0" # ssh - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: "0.0.0.0/0" DEPLOYEC201: Type: AWS::EC2::Instance Properties: ImageId: !Ref IMAGEID KeyName: !Ref KeyName InstanceType: t4g.micro NetworkInterfaces: - AssociatePublicIpAddress: "true" DeviceIndex: "0" SubnetId: !Ref SubnetID01 GroupSet: - !Ref DEPLOYSG01 UserData: !Base64 | #!/bin/bash sudo yum update -y sudo amazon-linux-extras sudo amazon-linux-extras install nginx1 -y sudo systemctl enable nginx sudo systemctl start nginx sudo echo "deploy-CFn01" >/usr/share/nginx/html/index.html Tags: - Key: Name Value: deploy-CFn01 HealthCheck01: Type: 'AWS::Route53::HealthCheck' Properties: HealthCheckConfig: IPAddress: !GetAtt DEPLOYEC201.PublicIp Port: 80 Type: HTTP ResourcePath: '/' FullyQualifiedDomainName: !GetAtt DEPLOYEC201.PublicDnsName RequestInterval: 30 FailureThreshold: 2 HealthCheckTags: - Key: Name Value: deploy-CFn01 RecordSet01: Type: AWS::Route53::RecordSet Properties: Failover: PRIMARY # PRIMARY / SECONDARY HealthCheckId: !GetAtt HealthCheck01.HealthCheckId HostedZoneId: !Ref HostedZoneId Name: !Sub ${HostedServerName}.${HostedZoneName} ResourceRecords: - !GetAtt DEPLOYEC201.PublicIp SetIdentifier: !Sub ${SetIdentifierBase}01 TTL: "60" Type: "A" # Valid values for basic resource record sets: A | AAAA | CAA | CNAME | DS |MX | NAPTR | NS | PTR | SOA | SPF | SRV | TXT ### 2 dai me ### DEPLOYSG02: Type: AWS::EC2::SecurityGroup Properties: GroupName: deploy-CFn02 GroupDescription: Allow SSH and HTTP access only MyIP VpcId: !Ref VPCID SecurityGroupIngress: # http - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: "0.0.0.0/0" # ssh - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: "0.0.0.0/0" DEPLOYEC202: Type: AWS::EC2::Instance Properties: ImageId: !Ref IMAGEID KeyName: !Ref KeyName InstanceType: t4g.micro NetworkInterfaces: - AssociatePublicIpAddress: "true" DeviceIndex: "0" SubnetId: !Ref SubnetID02 GroupSet: - !Ref DEPLOYSG02 UserData: !Base64 | #!/bin/bash sudo yum update -y sudo amazon-linux-extras sudo amazon-linux-extras install nginx1 -y sudo systemctl enable nginx sudo systemctl start nginx sudo echo "deploy-CFn02" >/usr/share/nginx/html/index.html Tags: - Key: Name Value: deploy-CFn02 HealthCheck02: Type: 'AWS::Route53::HealthCheck' Properties: HealthCheckConfig: IPAddress: !GetAtt DEPLOYEC202.PublicIp Port: 80 Type: HTTP ResourcePath: '/' FullyQualifiedDomainName: !GetAtt DEPLOYEC202.PublicDnsName RequestInterval: 30 FailureThreshold: 2 HealthCheckTags: - Key: Name Value: deploy-CFn02 ### for Sorry ### DEPLOYSG03: Type: AWS::EC2::SecurityGroup Properties: GroupName: deploy-CFn03 GroupDescription: Allow SSH and HTTP access only MyIP VpcId: !Ref VPCID SecurityGroupIngress: # http - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: "0.0.0.0/0" # ssh - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: "0.0.0.0/0" DEPLOYEC203: Type: AWS::EC2::Instance Properties: ImageId: !Ref IMAGEID KeyName: !Ref KeyName InstanceType: t4g.micro NetworkInterfaces: - AssociatePublicIpAddress: "true" DeviceIndex: "0" SubnetId: !Ref SubnetID03 GroupSet: - !Ref DEPLOYSG03 UserData: !Base64 | #!/bin/bash sudo yum update -y sudo amazon-linux-extras sudo amazon-linux-extras install nginx1 -y sudo systemctl enable nginx sudo systemctl start nginx sudo echo "deploy-CFn03" >/usr/share/nginx/html/index.html Tags: - Key: Name Value: deploy-CFn03 HealthCheck03: Type: 'AWS::Route53::HealthCheck' Properties: HealthCheckConfig: IPAddress: !GetAtt DEPLOYEC203.PublicIp Port: 80 Type: HTTP ResourcePath: '/' FullyQualifiedDomainName: !GetAtt DEPLOYEC203.PublicDnsName RequestInterval: 30 FailureThreshold: 2 HealthCheckTags: - Key: Name Value: deploy-CFn03 RecordSet03: Type: AWS::Route53::RecordSet Properties: Failover: SECONDARY # PRIMARY / SECONDARY HealthCheckId: !GetAtt HealthCheck03.HealthCheckId HostedZoneId: !Ref HostedZoneId Name: !Sub ${HostedServerName}.${HostedZoneName} ResourceRecords: - !GetAtt DEPLOYEC203.PublicIp SetIdentifier: !Sub ${SetIdentifierBase}03 TTL: "60" Type: "A" |
Weight設定の環境を作るyaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
Parameters: KeyName: Description: The EC2 Key Pair to allow SSH access to the instance Type: "AWS::EC2::KeyPair::KeyName" VPCID: Type: String Default: "vpc-6a3b310e" SubnetID01: Type: String Default: "subnet-989aecee" SubnetID02: Type: String Default: "subnet-989aecee" SubnetID03: Type: String Default: "subnet-989aecee" IMAGEID: Type: String Default: "ami-0f7691f59fd7c47af" ### Route53 ### HostedZoneId: Type: String Default: "Z3P0P51LUVW4NB" HostedZoneName: Type: String Default: "kapodev.work" HostedServerName: Type: String Default: "hogeraccho" SetIdentifierBase: Type: String Default: "hogeraccho" Resources: ### 1 dai me ### DEPLOYSG01: Type: AWS::EC2::SecurityGroup Properties: GroupName: deploy-CFn01 GroupDescription: Allow SSH and HTTP access only MyIP VpcId: !Ref VPCID SecurityGroupIngress: # http - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: "0.0.0.0/0" # ssh - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: "0.0.0.0/0" DEPLOYEC201: Type: AWS::EC2::Instance Properties: ImageId: !Ref IMAGEID KeyName: !Ref KeyName InstanceType: t4g.micro NetworkInterfaces: - AssociatePublicIpAddress: "true" DeviceIndex: "0" SubnetId: !Ref SubnetID01 GroupSet: - !Ref DEPLOYSG01 UserData: !Base64 | #!/bin/bash sudo yum update -y sudo amazon-linux-extras sudo amazon-linux-extras install nginx1 -y sudo systemctl enable nginx sudo systemctl start nginx sudo echo "deploy-CFn01" >/usr/share/nginx/html/index.html Tags: - Key: Name Value: deploy-CFn01 HealthCheck01: Type: 'AWS::Route53::HealthCheck' Properties: HealthCheckConfig: IPAddress: !GetAtt DEPLOYEC201.PublicIp Port: 80 Type: HTTP ResourcePath: '/' FullyQualifiedDomainName: !GetAtt DEPLOYEC201.PublicDnsName RequestInterval: 30 FailureThreshold: 2 HealthCheckTags: - Key: Name Value: deploy-CFn01 RecordSet01: Type: AWS::Route53::RecordSet Properties: HealthCheckId: !GetAtt HealthCheck01.HealthCheckId HostedZoneId: !Ref HostedZoneId Name: !Sub ${HostedServerName}.${HostedZoneName} ResourceRecords: - !GetAtt DEPLOYEC201.PublicIp SetIdentifier: !Sub ${SetIdentifierBase}01 TTL: "60" Type: "A" # Valid values for basic resource record sets: A | AAAA | CAA | CNAME | DS |MX | NAPTR | NS | PTR | SOA | SPF | SRV | TXT Weight: 50 ### 2 dai me ### DEPLOYSG02: Type: AWS::EC2::SecurityGroup Properties: GroupName: deploy-CFn02 GroupDescription: Allow SSH and HTTP access only MyIP VpcId: !Ref VPCID SecurityGroupIngress: # http - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: "0.0.0.0/0" # ssh - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: "0.0.0.0/0" DEPLOYEC202: Type: AWS::EC2::Instance Properties: ImageId: !Ref IMAGEID KeyName: !Ref KeyName InstanceType: t4g.micro NetworkInterfaces: - AssociatePublicIpAddress: "true" DeviceIndex: "0" SubnetId: !Ref SubnetID02 GroupSet: - !Ref DEPLOYSG02 UserData: !Base64 | #!/bin/bash sudo yum update -y sudo amazon-linux-extras sudo amazon-linux-extras install nginx1 -y sudo systemctl enable nginx sudo systemctl start nginx sudo echo "deploy-CFn02" >/usr/share/nginx/html/index.html Tags: - Key: Name Value: deploy-CFn02 HealthCheck02: Type: 'AWS::Route53::HealthCheck' Properties: HealthCheckConfig: IPAddress: !GetAtt DEPLOYEC202.PublicIp Port: 80 Type: HTTP ResourcePath: '/' FullyQualifiedDomainName: !GetAtt DEPLOYEC202.PublicDnsName RequestInterval: 30 FailureThreshold: 2 HealthCheckTags: - Key: Name Value: deploy-CFn02 RecordSet02: Type: AWS::Route53::RecordSet Properties: HealthCheckId: !GetAtt HealthCheck02.HealthCheckId HostedZoneId: !Ref HostedZoneId Name: !Sub ${HostedServerName}.${HostedZoneName} ResourceRecords: - !GetAtt DEPLOYEC202.PublicIp SetIdentifier: !Sub ${SetIdentifierBase}02 TTL: "60" Type: "A" Weight: 50 ### for Sorry ### DEPLOYSG03: Type: AWS::EC2::SecurityGroup Properties: GroupName: deploy-CFn03 GroupDescription: Allow SSH and HTTP access only MyIP VpcId: !Ref VPCID SecurityGroupIngress: # http - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: "0.0.0.0/0" # ssh - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: "0.0.0.0/0" DEPLOYEC203: Type: AWS::EC2::Instance Properties: ImageId: !Ref IMAGEID KeyName: !Ref KeyName InstanceType: t4g.micro NetworkInterfaces: - AssociatePublicIpAddress: "true" DeviceIndex: "0" SubnetId: !Ref SubnetID03 GroupSet: - !Ref DEPLOYSG03 UserData: !Base64 | #!/bin/bash sudo yum update -y sudo amazon-linux-extras sudo amazon-linux-extras install nginx1 -y sudo systemctl enable nginx sudo systemctl start nginx sudo echo "deploy-CFn03" >/usr/share/nginx/html/index.html Tags: - Key: Name Value: deploy-CFn03 HealthCheck03: Type: 'AWS::Route53::HealthCheck' Properties: HealthCheckConfig: IPAddress: !GetAtt DEPLOYEC203.PublicIp Port: 80 Type: HTTP ResourcePath: '/' FullyQualifiedDomainName: !GetAtt DEPLOYEC203.PublicDnsName RequestInterval: 30 FailureThreshold: 2 HealthCheckTags: - Key: Name Value: deploy-CFn03 RecordSet03: Type: AWS::Route53::RecordSet Properties: HealthCheckId: !GetAtt HealthCheck03.HealthCheckId HostedZoneId: !Ref HostedZoneId Name: !Sub ${HostedServerName}.${HostedZoneName} ResourceRecords: - !GetAtt DEPLOYEC203.PublicIp SetIdentifier: !Sub ${SetIdentifierBase}03 TTL: "60" Type: "A" Weight: 0 |
まとめ
今回の検証では、AWSのRoute53を活用してSorryページのフェールオーバーを実現する方法を紹介しました。
- CloudFrontやALBのカスタムエラーページの代替手段として、Route53のFailoverやWeightを活用できる。
- Sorryページのレスポンスコードは適切に設定しないと、SEOやユーザー体験に影響を与える可能性がある。
- CloudFormationを活用することで、Failover/Weightの設定を簡単にデプロイ可能。
Sorryページの設計は、サイトの可用性とUXを考慮しながら、適切な手法を選択することが重要です。
今後、より柔軟なSorryページの実装方法についても検討していきたいと思います。