AWS LambdaとSSMを使用したEC2インスタンスの状態監視とALBの動的切り替え①

## はじめに
AWS LambdaとAWS Systems Manager (SSM) を活用し、EC2インスタンスのhttpdサービスの状態を監視して、状態に応じてApplication Load Balancer (ALB) のリスナールールを変更する手法について解説します。

具体的には、httpdサービスが停止している場合にメンテナンス用のSorryページを表示し、少なくとも1台のサービスが稼働している場合は通常のページを表示するように設定します。

## コード紹介
### 全体のコード
以下は、Lambda関数で実装されたコードです。SSM Run Commandを使用してhttpdサービスの状態を確認し、サービスの停止に応じてALBのルールを変更する処理を行います。

```py
import boto3
import time

def lambda_handler(event, context):
    ssm_client = boto3.client('ssm')
    elbv2_client = boto3.client('elbv2')

    # 監視するEC2インスタンスのID
    instance_ids = ["i-0458be1d8c980e8ec", "i-0b27db6a9b067f345"]
    httpd_stopped_count = 0

    for instance_id in instance_ids:
        # SSM Run Commandを使用してhttpdサービスの状態を確認
        response = ssm_client.send_command(
            InstanceIds=[instance_id],
            DocumentName='AWS-RunShellScript',
            Parameters={'commands': ['systemctl is-active httpd']}
        )

        # コマンドの実行結果を取得するために少し待機
        time.sleep(2)

        command_id = response['Command']['CommandId']
        output = ssm_client.get_command_invocation(
            CommandId=command_id,
            InstanceId=instance_id
        )

        # httpdサービスが停止している場合にカウント
        if output['Status'] == 'Success' and 'inactive' in output['StandardOutputContent']:
            httpd_stopped_count += 1

    # 2台ともhttpdサービスが停止している場合、リスナールールを切り替え
    if httpd_stopped_count == len(instance_ids):
        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台でもサービスが動いている場合）
        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},
            ]
        )

    return {
        'statusCode': 200,
        'body': 'Lambda execution completed successfully'
    }
```

## コードのポイント解説
### EC2インスタンスとALBクライアントの初期化
boto3ライブラリを使用して、SSMとElastic Load Balancing (ELB) のクライアントを作成します。これにより、AWSリソースへの操作が可能になります。

### SSM Run Commandの実行
send_commandメソッドを使って、EC2インスタンス上でsystemctl is-active httpdを実行します。このコマンドでhttpdサービスの状態を確認します。

### サービス状態のチェック
get_command_invocationメソッドを使用してコマンドの実行結果を取得し、inactiveが含まれているかを確認することで、サービスの停止状態を判断します。

### ALBのリスナールール変更
全てのインスタンスでhttpdサービスが停止している場合はSorryページを優先し、少なくとも1台のインスタンスでサービスが稼働している場合は通常のページを表示するようにルールを変更します。

## 必要なIAMポリシーの設定
Lambda関数に以下のポリシーをアタッチして、SSMとELBの操作を許可してください。

```
ssm:SendCommand
ssm:GetCommandInvocation
elasticloadbalancing:SetRulePriorities
```

また、EC2インスタンスには、SSMエージェントがインストールされていることと、以下のポリシーが設定されたIAMロールをアタッチする必要があります:

```
AmazonSSMManagedInstanceCore
```

## まとめ
このLambda関数を使用することで、EC2インスタンスのhttpdサービスが停止した際に自動的にメンテナンスページを表示する仕組みを構築できます。

これにより、サービスが停止した際に手動で設定を変更する手間を省け、効率的なシステム運用が可能になります。

さらに、必要に応じてエラーハンドリングやリトライ処理を追加することで、より堅牢なシステムを構築できます。

AWSリソースの自動化と管理を効果的に行うために、このようなSSMとLambdaの連携を活用してみてください。