Pythonで学ぶAWS Lambdaを活用したEC2インスタンス監視とALBルールの自動切り替え

## はじめに
本記事では、AWS Lambda関数を用いたEC2インスタンスの監視と、ALB（Application Load Balancer）のルール切り替えについて解説します。

EC2インスタンスが停止した場合に、ALBをSorryページに切り替える仕組みをコードと共に紹介します。


## コードの部品紹介
Lambda関数のコードを大きなまとまりごとに解説していきます。

### 1. 必要なライブラリとクライアントの準備

```python
import boto3

def lambda_handler(event, context):
    ec2_client = boto3.client('ec2')
    elbv2_client = boto3.client('elbv2')
```

**解説:**
まず、AWS SDK for Python（boto3）をインポートし、EC2とELBv2（Elastic Load Balancing v2）のクライアントオブジェクトを作成します。これにより、Lambda関数内でEC2インスタンスとALBのルール設定を操作することが可能です。

### 2. 監視するEC2インスタンスの設定
```python
    instance_ids = ["i-0458be1d8c980e8ec", "i-0b27db6a9b067f345"]
```

**解説:**
この行では、監視対象の2台のEC2インスタンスのIDを指定しています。instance_idsリストに、チェックしたいインスタンスのIDを格納します。

### 3. EC2インスタンスの状態確認

```python
    response = ec2_client.describe_instances(InstanceIds=instance_ids)
    
    instances_stopped_count = sum(
        1 for reservation in response['Reservations']
        for instance in reservation['Instances']
        if instance['State']['Name'] == 'stopped'
    )
```

**解説:**
describe_instancesメソッドを使用して、指定したインスタンスの状態を取得します。返された情報から、停止しているインスタンスの数をinstances_stopped_count変数に計算します。

各インスタンスがstopped状態かどうかをチェックし、その数をカウントしています。

### 4. EC2インスタンスが停止しているかの条件分岐
```python
    if instances_stopped_count == 2:
```

**解説:**
2台のインスタンスが共に停止しているかを確認する条件です。もし両方のインスタンスが停止していたら、次の段階でSorryページに切り替える処理が実行されます。

### 5. ALBルールの切り替え（Sorryページへ）
```python
        response = elbv2_client.set_rule_priorities(
            RulePriorities=[
                {
                    'RuleArn': 'arn:aws:elasticloadbalancing:ap-northeast-1:YOUR_SORRY_PAGE_RULE_ARN',
                    'Priority': 1
                },
                {
                    'RuleArn': 'arn:aws:elasticloadbalancing:ap-northeast-1:YOUR_NORMAL_RULE_ARN',
                    'Priority': 2
                },
            ]
        )
```

**解説:**
2台のインスタンスが停止している場合、ALBのルールを切り替えてSorryページを優先させます。ALBのルールには優先順位があり、この部分ではSorryページのルールを優先順位1に設定し、通常ページのルールを優先順位2に設定しています。

### 6. ALBルールの切り替え（通常ページへ）
```python
    else:
        response = elbv2_client.set_rule_priorities(
            RulePriorities=[
                {
                    'RuleArn': 'arn:aws:elasticloadbalancing:ap-northeast-1:YOUR_NORMAL_RULE_ARN',
                    'Priority': 1
                },
                {
                    'RuleArn': 'arn:aws:elasticloadbalancing:ap-northeast-1:YOUR_SORRY_PAGE_RULE_ARN',
                    'Priority': 2
                },
            ]
        )
```

**解説:**
もし1台でもインスタンスが動作している場合、このelseブロックが実行され、通常のページを優先的に表示するようにALBのルールを再設定します。

通常ページの優先順位を1に、Sorryページを2に設定している点が前述の部分と逆になっています。

### 7. 現在のルール設定の確認と結果の返却
```python
    result = elbv2_client.describe_rules(
        ListenerArn='arn:aws:elasticloadbalancing:ap-northeast-1:YOUR_LISTENER_ARN'
    )
    return result
```

**解説:**
最後に、ALBのリスナーに設定されている現在のルール情報を取得し、Lambda関数の結果として返します。これにより、設定がどのように適用されているかを確認することができます。

## 完成したコード
完成したコードは以下になります。

```python
import boto3

def lambda_handler(event, context):
    ec2_client = boto3.client('ec2')
    elbv2_client = boto3.client('elbv2')

    # 監視する2台のEC2インスタンスのID
    instance_ids = ["i-0458be1d8c980e8ec", "i-0b27db6a9b067f345"]
    
    # EC2インスタンスの状態を取得
    response = ec2_client.describe_instances(InstanceIds=instance_ids)
    
    # 停止しているインスタンスをカウント
    instances_stopped_count = sum(
        1 for reservation in response['Reservations']
        for instance in reservation['Instances']
        if instance['State']['Name'] == 'stopped'
    )

    if instances_stopped_count == 2:  # 2台とも停止している場合
        # Sorryページに切り替え
        response = elbv2_client.set_rule_priorities(
            RulePriorities=[
                {
                    'RuleArn': 'arn:aws:elasticloadbalancing:ap-northeast-1:YOUR_SORRY_PAGE_RULE_ARN',
                    'Priority': 1
                },
                {
                    'RuleArn': 'arn:aws:elasticloadbalancing:ap-northeast-1:YOUR_NORMAL_RULE_ARN',
                    'Priority': 2
                },
            ]
        )
    else:
        # 通常ページに戻す（1台でも起動している場合）
        response = elbv2_client.set_rule_priorities(
            RulePriorities=[
                {
                    'RuleArn': 'arn:aws:elasticloadbalancing:ap-northeast-1:YOUR_NORMAL_RULE_ARN',
                    'Priority': 1
                },
                {
                    'RuleArn': 'arn:aws:elasticloadbalancing:ap-northeast-1:YOUR_SORRY_PAGE_RULE_ARN',
                    'Priority': 2
                },
            ]
        )

    # 現在のルール設定を確認
    result = elbv2_client.describe_rules(
        ListenerArn='arn:aws:elasticloadbalancing:ap-northeast-1:YOUR_LISTENER_ARN'
    )
    return result
```

## 処理のフローチャート
コード全体のフロー処理の流れは、以下になります。

```python
+----------------------------------------+
|    Lambda関数のトリガー                |
+----------------------------------------+
               |
               v
+----------------------------------------+
| EC2インスタンスの状態を確認            |
| (describe_instances APIを使用)         |
+----------------------------------------+
               |
               v
+----------------------------------------+
| 2台のEC2インスタンスが停止しているか？|
+----------------------------------------+
     |                                         |
   YES                                         NO
     |                                         |
     v                                         v
+----------------------------------------+   +----------------------------------------+
| ALBをSorryページに切り替え              |   | ALBを通常ページに切り替え              |
| (set_rule_priorities APIを使用)         |   | (set_rule_priorities APIを使用)         |
+----------------------------------------+   +----------------------------------------+
               |                                |
               v                                v
+----------------------------------------+
| 現在のALBルール設定を返す              |
| (describe_rules APIを使用)             |
+----------------------------------------+
               |
               v
+----------------------------------------+
|    処理終了                           |
+----------------------------------------+
```


## まとめ
今回紹介したLambda関数を用いることで、EC2インスタンスの状態に応じてALBのルールを動的に切り替えることが可能になります。

これにより、サーバーの停止時に自動でSorryページを表示させることができます。サービス停止時のユーザー体験を向上させる仕組みとして、非常に有効な手法です。

## 参考記事

https://qiita.com/free-honda/items/cef3fd945ee4abd196d3#%E5%8F%82%E8%80%83%E8%A8%98%E4%BA%8B