【AWS初心者】システムメンテナンスを想定したDNS切り替えに挑戦した話

# 概要
* この記事は、[KDDI Engineer&Designer Advent Calendar 2022](https://qiita.com/advent-calendar/2022/engineer-designer)の23日目の投稿です。
* 通信が全断になるようなメンテナンスが計画されているシステムがあったとして、そのメンテナンスが終わるまでの間、メンテナンス中であることをユーザに示すことが必要です。それを実現するための実験として、AWS上で模擬的なシステムを構築し、DNSを切り替えてから実際にそれが反映されるまでの時間を調べます。

# 想定する状況
あるオンプレのシステムに短時間のメンテナンスが計画されており、そのメンテナンス中は完全にそのシステムとの接続が不可能になるという状況を考えます。
この場合、ユーザが対象システムに接続しようとすると、エラーになってしまいます。
それでは困るので、メンテナンス中は臨時の他システムに誘導し、そちらでメンテナンス中であることを示すメッセージを表示するようにします。
例えばその臨時システムをAWSで作成すると、下図のようなイメージになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961842/dc9c4cf2-d6c6-270b-f582-1616d0493228.png)

ユーザがオンプレシステムにアクセスしようとした際に臨時システムに誘導するのは、オンプレシステムのドメイン名のDNSレコードを書き換えることで実現します。
DNSを書き換える際の制約として次の2点を考えます。
* まず、ユーザがどちらかのシステムには必ずアクセスできるようにします。
* また、できるだけメインシステムにユーザがアクセスできるよう、ギリギリまでDNS切り替えはしないようにします。

これらの条件下でDNS切り替えを実現するために、DNSを切り替えてからユーザから見えるシステムが切り替わるまでにかかる時間を求めたい、というのが今回の取り組みになります。

# 今回のゴール
あるシステムに割り当てられているドメイン名のDNSレコードを変更し、他のシステムに誘導するようにしてから、実際にユーザがそのシステムにアクセスできるようになるまでの時間を計測すること。

# 構築するシステムの全体像
今回は、AWSのCloudFrontを利用し、オンプレシステムと臨時システムを模した2つのWebページを作成します。(オンプレシステムの代わりの方のwebページをメインシステムと呼びます)
そして、メインシステムに割り当てているドメイン名のレコードをAmazon Route53というサービスを利用して変更し、臨時システムに誘導できるようにします。
また、メインシステムと臨時システムに割り当てるドメイン名の証明書はAWS Certificate Managerを利用して発行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961842/3c8fa441-367e-64b2-0de8-02f7a00b00e2.png)

# 事前準備
事前準備の段階で行った内容は、このサイトを参考にさせていただきました

https://zenn.dev/wakkunn/articles/66a6e8372611dc

## 準備1. ドメインの準備
### ドメイン名の取得
Amazon Route53などのサービスを使ってもドメイン名は取得できますが、今回は[Freenom](https://www.freenom.com/ja/index.html?lang=ja)というサービスを利用して無料でドメイン名を取得します。
ここでは、 _'study-dns-switching.tk'_　というドメインを取得します。
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961842/0aca15df-c4fc-5e23-47da-c4f539bba845.png)


### Amazon Route53でホストゾーン作成
Amazon Route53を使うことで、先程作成したドメイン _'study-dns-switching.tk'_ に対するレコードを作成することができます。
下図のようにドメイン名を入力し、"ホストゾーンの作成"をクリックすると、NSレコードとSOAレコードが自動的に作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961842/116129e9-928c-441b-17c8-f4682a767516.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961842/15d1942b-6ed4-534a-309b-0fe6be47ada0.png)

また、Freenomの方にも忘れずにNameserversを登録します。
_'study-dns-switching.tk'_ の設定のページから、"Management Tools"→"Nameservers"へと進み、Amazon Route53で作成されたNSレコードの内容をセットします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961842/65cc8b0a-109b-79ec-7618-8b08c6e03062.png)

### AWS Certificate Manager (ACM) で証明書発行
続いてACMを用いてSSL証明書を発行します。
証明書がないと、先ほどのドメイン名の管理者が自分であることを示すことができないので、後でドメイン名をシステムに設定することができません。
リージョンを米国東部(バージニア北部) us-east-1に変更し、"パブリック証明書をリクエスト"というボタンから、証明書をリクエストすることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961842/f3e62fc0-5533-8eba-3f46-b08479f4d96e.png)

証明書を発行した後、_'study-dns-switching.tk'_ にCNAMEレコードを追加します。
今回はレコードの管理をRoute53で行っているので、下図のボタンから簡単にCNAMEレコードを追加することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961842/75081644-9aa3-f834-29ff-13a5ba30f5ea.png)

## 準備2. AWS上に2つのシステムを構築
### S3バケットを作成し、Webページをアップロード
メインシステム用と臨時システム用それぞれに対し、S3バケットを作成し、Webページの中身をアップロードします。
メインシステムの方は無料公開されているテンプレートを用いて作成しました。

https://freehtml5.co/preview/?item=air-free-html5-bootstrap-template-for-portfolio-and-landing-pages

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961842/8ca4c9f1-33c5-92c4-b59d-72cad6a57715.png)

### Cloudfrontのディストリビューションを用意し、オリジンにS3をそれぞれ設定
メインシステム用と臨時システム用それぞれに対し、CloudFrontディストリビューションを作成し、先ほど作成したS3をオリジンに設定します。
S3にアクセスできるようにするためには、バケットポリシーを編集する必要があることに注意が必要です。
また、"カスタム SSL 証明書"の欄において、事前準備1で発行したACM証明書を選択します。

### メインシステムのCloudFrontにドメイン名を割り当て
メインシステムの方のCloudFrontディストリビューションの代替ドメイン名 (CNAME)の欄に、_'study-dns-switching.tk'_ を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961842/a8d4b403-1519-c7d9-d8f2-f0e90acd2539.png)

また、Route53から _'study-dns-switching.tk'_ のAレコードを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961842/0dffd8ea-d160-3ecb-74bc-b43eb949258e.png)

これによって、インターネットから _'study-dns-switching.tk'_ の名前で先程のWebページにアクセスすることができるようになります。
実施にアクセスすると、下図のようにちゃんと表示されます。
![図6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961842/0fd5d891-9df3-e2d5-6005-f0c5d8ba5f48.png)

# DNS切り替え
事前準備が終わり、ドメイン名からメインシステムにアクセスできるようになりました。
ここからは、ドメイン名の割り当てをメインシステムから臨時システムに変更し、それが反映されるまでにどれくらいの時間がかかるかを確かめるという作業に取り組みます！

と思っていたのですが、1つ問題が生じました。
もともとは、予めメインシステムと同じCNAMEを臨時システムの方にも設定しておくことにより、Amazon Route53でAレコードを変更するだけでルート切り替えができると考えていました。
しかし、メインシステムと同じように臨時システムに対しても _'study-dns-switching.tk'_ を設定しようとすると、"この代替ドメイン(CNAME）は既に他のリソースに割り当てられているためできません"というエラーが出てしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961842/faa2b5ab-6913-634c-c806-7fe6019ce6bf.png)
本番環境では、メインシステムがオンプレであるという想定にしているため、このような問題は発生しないのですが、今回は2つのシステムを両方ともAWS上のCloudfrontを用いて構築しているため、エラーになってしまいます。

そのため、今回構築したシステムにおいてDNSを切り替えるためには、メインシステムにおいてCNAME削除→臨時システムにCNAME登録→Route53でレコード切り替え、の3ステップが必要になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961842/0f1fb372-2cb0-38fc-a625-59e09ab0393c.png)
分かりやすいよう、時系列で流れを図示すると下図のようになります。
* もともと想定していた手順では、DNSレコード切り替えを行った後、変更が反映されるまではメインシステムの画面が表示されており、変更が反映された時点で臨時システムの画面が表示されるようにな離ます。
* しかし、実際の作業ではCloudfrontディストリビューションにおいてCNAMEの削除と登録の作業が必要になります。メインシステムにおいてCNAMEを削除すると、その時点でメインシステムにはアクセスできなくなるため、画面に何も表示されない時間ができてしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961842/a6a42f14-1cd6-e3fb-e81b-1b43c60e53d0.png)

このように、今回の構成では画面に何も表示されない時間ができてしまいます。
これは臨時システム構築の目的である、ユーザがシステムにアクセスできない時間をなくすという内容に反しています。
しかし、今回のDNS切り替え試験の目的としては上図のtを求めることであり、これは何も表示されない時間の有無にかかわらず測定することが可能です。
そのため、今回はこのままの構成で続けることとします。

※今回は行いませんでしたが、構築する2つのシステムの少なくともどちらか一方を __証明書を必要としない構成にする__ ことが最もシンプルな解決策だと思います。例えば、EC2インスタンス上にWebページを展開したり、S3バケットで静的ウェブサイトホスティングを有効にすることで、証明書なしでもアクセスできるはずです。ただ、結果として求めたい値はどちらの方法でも変わらないので、今回は上記の内容で実施することにしました。

それでは実際に作業を進めていきます！
## 1. digコマンドによるレコードの確認
`dig`コマンドはドメイン名からIPアドレスを調べることができます。
Amazon Route53でAレコードを変更した際、それがDNSサーバに反映されるまでどれくらいの時間がかかるかを調べるために今回は使用します。
次のスクリプトを実行することで、1秒ごとに`dig`コマンドでDNSサーバに問い合わせた結果をテキストファイルに書き込むことができます。
問い合わせの際、どのDNSサーバに問い合わせるかを指定することができますが、今回はGoogle Public DNS(8.8.8.8)を指定します。
問い合わせの結果例を見ると、同じ時刻に4つの結果が帰ってきていることがわかります。
これは、study-dns-switching.tkが割り当てられているcloudfrontのディストリビューションに4つのIPアドレスがあることがわかります。
60という数字はTTL(キャッシュの生存時間)を表しています。
```sh:dig_command.sh
#! /bin/bash
while :
do
    dig +noall +answer @8.8.8.8 study-dns-switching.tk | gawk '{print strftime("%y/%m/%d %H:%M:%S"), $0}'
    sleep 1
done >> result.txt 
```


```text:結果例
22/12/21 17:54:00 study-dns-switching.tk.	60	IN	A	18.65.185.54
22/12/21 17:54:00 study-dns-switching.tk.	60	IN	A	18.65.185.46
22/12/21 17:54:00 study-dns-switching.tk.	60	IN	A	18.65.185.27
22/12/21 17:54:00 study-dns-switching.tk.	60	IN	A	18.65.185.62
22/12/21 17:54:01 study-dns-switching.tk.	60	IN	A	18.65.185.62
22/12/21 17:54:01 study-dns-switching.tk.	60	IN	A	18.65.185.54
22/12/21 17:54:01 study-dns-switching.tk.	60	IN	A	18.65.185.46
...
```

## 2. CloudFrontディストリビューションの設定変更
メインシステムのCloudFrontディストリビューションからCNAMEの設定を削除し、臨時システムの方にCNAMEとして _'study-dns-switching.tk'_ を設定します。

## 3. Amazon Route53でレコード切り替え
Route53からAレコードの中身を書き換えます。
臨時システムのCloudFrontディストリビューションのページから、ディストリビューションドメイン名をコピーし、Aレコードのトラフィックのルーティング先として設定します。
"正常に更新されました"というメッセージの表示からしばらくすると、_'study-dns-switching.tk'_ にアクセスした際、臨時システムのページが表示されるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961842/8b8a7c1e-ebba-b769-4c7d-562bfb3bfbb4.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961842/12a2a1bf-74ff-4b27-15ec-fee6bca710f8.png)

# 結果
結果は下図のようになりました。
14時40分ちょうどにAmazon Route53でレコードを切り替えたところ、20秒ほど経つと2つのシステムの結果がどちらも表示されるようになりました。
これは、キャッシュが残っているためだと考えられます。
その後、DNSレコード切り替えから61秒後にメインシステムのIPアドレスは表示されないようになりました。
つまり、1分ほどあればユーザから安定して臨時システムが表示されるようになるという結果になりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961842/31abaad9-9957-9004-5626-1665e7a1989d.png)
また、DNSレコード切り替えから66秒後のことですが、1回だけメインシステムでも臨時システムでもないと思われるIPアドレスが帰ってきました。
原因はわかっていませんが、CloudFrontの仕様が原因かもしれないと考えています。


# まとめ・感想
今回のシステム構成では、約1分ほどでDNSレコード切り替えの結果が反映されるという結果になりました。
ただ、よくあるオンプレシステムの設定として、レコード情報のTTLは300秒や6000秒に設定されていることがよくあるため、今回の結果とは異なる可能性があります。
実際にオンプレシステムで実施する際は、TTLをあらかじめ短くしておくなどの注意が必要です。

また、結果のセクションで説明したように、想定していたものと違うIPアドレスが表示された原因がまだわかっていません。
今後はこの原因調査も含め、さらに勉強を進めていきたいと思っています。