サーバーがUnhealthyになった時に自動でターゲットグループを切り替える

こんにちは。ねこしまです。
今回は、ELBにリスナーとして登録されているEC2①が落ちてしまった際にEC2②のターゲットグループにリスナーを切り替えるという作業を行う機会があったのでその内容を共有したいと思います。

## はじめに
### 全体の流れ
ELBにリスナーとして登録されているターゲットグループのEC2がUnHealthyになった際にCloudWatchアラームで検知し、SNSに流します。
SNSではメール送信と共にLambdaのトリガーとします。
LambdaではEC2①のターゲットグループをリスナーから外し、EC2②のターゲットグループを新たにリスナーとして登録をします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/c6f54dfb-8160-b8a2-1dc4-af58fa8ed6b8.png)


### 前提条件						
　・VPCやサブネット・ELB・EC2が作成済みであること						
### 対象外事項						
　・ターゲットグループ切り替え後のEC2②の起動						
### 対象事項						
　・EC2①②それぞれのターゲットグループの作成
　・EC2①のUnhealthyを検知するCloudWatchアラームの作成
　・Lambda起動のトリガーとなるSNSの作成
　・ターゲットグループの切り替えを行うLambdaの作成				

## 設定
### ターゲットグループの作成
EC2①を登録したターゲットグループ（first-tg）を作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/722454b9-cc65-b39e-7bed-2ab8534cef25.png)
続いてEC2②を登録したターゲットグループ（second-tg）を作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/a78cc5a2-2263-b561-4dc3-200e98fba2a0.png)

ターゲットグループが2つできました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/a770ff0b-ae64-e2bb-b8f8-7e19d3c31185.png)

### ロードバランサーの作成
では、ALBを作成します。
まず、[ロードバランサーの作成]を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/3b44b636-0930-4cc3-b175-b7ca95f5be37.png)
今回の作成はALBです！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/7dd0ad73-3b52-bb66-b0dd-fb566b56cd1c.png)

ターゲットグループはEC2①が登録されているfirst-tgで設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/89323438-c4bc-f0db-e05f-8594988f2f8c.png)

ロードバランサーを作成し、しばらくたつと、登録しているターゲットグループがHealthyになりました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/565a9e4c-bdb9-e752-7b27-a8939bf4c474.png)

ALBのDNS名でアクセスすると、下記のようにEC2①のページを見ることが出来ました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/a6ab1278-0e38-7007-f281-2c5354e9465b.png)

### Lambdaの作成
では、Lambda関数を作成します。
下記リンクを参考に作成しました。
[lambdaでalbのターゲットグループ変更の仕方](https://repost.aws/ja/questions/QUC_U4WD0OT9y3BzBd_E8fRg/lambda%E3%81%A7alb%E3%81%AE%E3%82%BF%E3%83%BC%E3%82%B2%E3%83%83%E3%83%88%E3%82%B0%E3%83%AB%E3%83%BC%E3%83%97%E5%A4%89%E6%9B%B4%E3%81%AE%E4%BB%95%E6%96%B9 "lambdaでalbのターゲットグループ変更の仕方")


まず[関数の作成]を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/f10ebbf1-39d0-6100-9efd-3fc2ba64cef4.png)

ランタイムはPython3.12を使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/0c48c8f7-3cd8-f132-387b-d492a797a660.png)

関数は下記を入力してDeployします！※インスタンスの起動や停止は含まず、TGの切り替えのみを行っています。
```
import boto3
import json
import time

elbv2_client = boto3.client('elbv2')
ec2_client = boto3.client('ec2')

target_group_arn1 = '1台目のインスタンスが紐づいたターゲットグループのARN'
target_group_arn2 = '2台目のインスタンスが紐づいたターゲットグループのARN'
listener_arn = '変更するリスナーのARN'

def lambda_handler(event, context):
    MESSAGE = json.loads(event['Records'][0]['Sns']['Message']) 
    Deregister_tg_ID = MESSAGE['Trigger']['Dimensions'][0]['value']
    
    Message = json.dumps(MESSAGE) 
    deregister_target_group_arn = json.dumps(Deregister_tg_ID) 

    elbv2_client.modify_listener(
        ListenerArn=listener_arn,
        DefaultActions=[
            {
                'Type': 'forward',
                'TargetGroupArn': target_group_arn2,
            },
        ]
    )
```

これでLambda関数は完成しました。

### SNSの作成
では続いてSNSを作成します。
※今回は通知も同時に行いたかったためSNSを使用します。

まず[トピックを作成]を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/a478787a-cee8-2817-c83f-4cac31f7eaa9.png)

トピック名を記入して作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/73832c17-f7df-a35d-2140-e9f6ceff2621.png)

次は作成したトピックのサブスクリプションを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/773e8d9b-10e4-5088-5604-a9b1200348dd.png)

プロトコルはLambdaを選択し、エンドポイントには先ほど作成したSNSのARNを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/011d9fd8-f6ed-5c47-549e-b3e1faa49e2b.png)

作成を押下し、Lambdaに戻るとトリガーとしてSNSが入力されていることが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/f5b55135-e0fd-36fa-ee98-b29cd9f912b0.png)

ここまでの設定を行ったら、最後はCloudWatchアラームのみになりました！最後にここを作成したら完成です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/2aec0e71-bb08-23e7-dac5-cccc3a8afba9.png)

### CloudWatchアラームの作成
EC2①が登録されたターゲットグループ（first-sg）のUnHealthyHostCountメトリクスでアラームを作成します！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/8021b32d-50c2-c99b-4943-c0b0083d7283.png)

今回は1分間の平均で統計を取り、3分以内の3データポイントでUnhealthyだった場合にターゲットグループが切り替わるように設定したいと思います。
また、本メトリクスはHealthyの場合データ不足になってしまうので「欠落データを適正」として扱うようにします。こうすることで、普段はアラームがOKとなるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/79c70000-f975-c351-3f33-84be7916313d.png)

アラームになった時のアクションでは、LambdaのトリガーとなっているSNSを登録します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/5412ef4d-3c95-fd5a-b215-7b31cada17fa.png)

しばらくすると、アラームがOK状態になりました！これで設定は完了となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/bde9d674-ae8a-5d99-7f98-e06dc97cba10.png)

### 切り替わりの確認
では、ターゲットグループの切り替えが出来るか動かしていきます！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/98296325-d434-c974-d39d-2484450294d3.png)

EC2①をUnhealthyにし、ターゲットグループがEC2②が登録されているsecond-tgに切り替われば成功となります。

まず現在のALBのリスナーと画面を確認します。
現在は下記のようにEC2①が登録されたfirst-tgが登録されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/656f66ca-333d-d428-72b5-6a21fc16ee23.png)

そして、ALBにアクセスするとこのようなページが出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/6e738996-ea35-a86c-e915-d1fcecbb000f.png)

前提の確認が済んだので、テスト開始します。
今回はEC2①のindex.htmlを削除する形でUnhealthyにしていきます。
・
・
・
ターゲットグループが切り替わり、ページも変わりました！（※EC2②は起動済み）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/e6d42ca4-308d-4183-47b1-bd96cd2c958d.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883742/0d9e72b8-97f4-4a61-da5c-26b3d4436289.png)

## 最後に
今回は、EC2①がUnhealthyとなった場合にEC2①のターゲットグループからEC2②のターゲットグループへ変更するという内容を設定しました。
また、今回の要件とは違ったため省略していますが、EC2②の自動起動とTG切り替え後の自動での戻しについても今後検証してみたいと思います！

この記事がどなたかのお役に立てばとっても嬉しいです！
最後までお読みいただきありがとうございましたー！