【AWS】EC2上で起動しているプロセスが落ちたら、自動的に再起動する機構をつくる

こんにちは

ちょっとタイトルがうまくまとめられず、残念な日本語力のものです

 

今回は以前書いた下記記事を利用して、httpdプロセスが落ちたら自動的に再起動する機構を作ってみました

なお、機構としては、割とよくあるものなので、完全自分用の備忘録です

【AWS】AlmaLinux9にCloudWatch エージェントを導入してhttpdプロセスを監視してみる

 

▼前提 (※記事の通りに対応していれば下記は完了しています)

・EC2にhttpdがインストールずみ

・EC2にCLoudWatchエージェントがインストール済み

・CloudWatchコンソール上でhttpdプロセスのメトリクスが取得できていること

 

▼機構

1. CloudWatchでhttpdプロセスが0になったらアラームが発火

2. トリガーに設定しているLambda関数の実行

3. EC2のhttpdが再起動される

4. アラームの復旧

 

▼手順

1. Lambda用IAMロールの作成

信頼されたエンティティタイプ:AWSのサービス

ユースケース:Lambda

許可ポリシー:AmazonSSMFullAccess、CloudWatchLogsFullAccess

ロール名:lambda-to-ssm-role

→内容に問題がないことを確認したら、ロールを作成する

 

2. Lambda関数の作成

・関数の作成

Lambda > 関数 > 関数を作成 > 1から作成 を選択する

:restart-httpd-function

アーキテクチャ:x86_64

実行ロール:lambda-to-ssm-role

コード:
import boto3
import logging
import json

logger = logging.getLogger()
logger.setLevel(logging.INFO)

ssm = boto3.client('ssm')

def lambda_handler(event, context):

    try:
        # CloudWatchから渡ってきたjsonデータのログを出力
        #logger.info("Received event: " + json.dumps(event, indent=2))

        # metricsはリストなので [0] で最初の要素を指定
        instance_id = event['alarmData']['configuration']['metrics'][0]['metricStat']['metric']['dimensions']['InstanceId']

        # instance_idを出力
        logger.info(instance_id)

        # instance_idで取得したEC2に対して、コマンドを実行
        command = "systemctl restart httpd"
        ssm.send_command(
            InstanceIds = [
                instance_id
            ],
            DocumentName = "AWS-RunShellScript",
            Parameters = {
                "commands": [
                    command
                ],
                "executionTimeout": ["600"]
            },
        )
        logger.info("send_command")
    except Exception as e:
        logger.error(e)

→コードを記載したら、Deployを押下して更新する

 

★CloudWatchLogsから送られてるの下記のようになっています

{
    "source": "aws.cloudwatch",
    "alarmArn": "arn:aws:cloudwatch:ap-northeast-1:xxxxxxxxxxxx:alarm:restart-httpd-alarm",
    "accountId": "xxxxxxxxxxxx",
    "time": "xxxx-xx-xxxx:xx:xx.xxx+xxxx",
    "region": "ap-northeast-1",
    "alarmData": {
        "alarmName": "restart-httpd-alarm",
        "state": {
            "value": "ALARM",
            "reason": "Threshold Crossed: 1 out of the last 1 datapoints [0.0 (xx/xx/xx xx:xx:xx)] was less than or equal to the threshold (0.0) (minimum 1 datapoint for OK -> ALARM transition).",
            "reasonData": "{\"version\":\"1.0\",\"queryDate\":\"xxxx-xx-xxxx:xx:xx.xxx+xxxx\",\"startDate\":\"xxxx-xx-xxxx:xx:xx.xxx+xxxx\",\"statistic\":\"Maximum\",\"period\":60,\"recentDatapoints\":[0.0],\"threshold\":0.0,\"evaluatedDatapoints\":[{\"timestamp\":\"xxxx-xx-xxxx:xx:xx.xxx+xxxx\",\"sampleCount\":1.0,\"value\":0.0}]}",
            "timestamp": "xxxx-xx-xxxx:xx:xx.xxx+xxxx"
        },
        "previousState": {
            "value": "OK",
            "reason": "Threshold Crossed: 1 out of the last 1 datapoints [5.0 (xx/xx/xx xx:xx:xx)] was not less than or equal to the threshold (0.0) (minimum 1 datapoint for ALARM -> OK transition).",
            "reasonData": "{\"version\":\"1.0\",\"queryDate\":\"xxxx-xx-xxxx:xx:xx.xxx+xxxx\",\"startDate\":\"xxxx-xx-xxxx:xx:xx.xxx+xxxx\",\"statistic\":\"Maximum\",\"period\":60,\"recentDatapoints\":[5.0],\"threshold\":0.0,\"evaluatedDatapoints\":[{\"timestamp\":\"xxxx-xx-xxxx:xx:xx.xxx+xxxx\",\"sampleCount\":1.0,\"value\":5.0}]}",
            "timestamp": "xxxx-xx-xxxx:xx:xx.xxx+xxxx"
        },
        "configuration": {
            "metrics": [
                {
                    "id": "xxxxxxxxxxxxxxxxxxxxxxxx",
                    "metricStat": {
                        "metric": {
                            "namespace": "CWAgent",
                            "name": "procstat_lookup_pid_count",
                            "dimensions": {
                                "InstanceId": "i-xxxxxxxxxxxx"
                            }
                        },
                        "period": 60,
                        "stat": "Maximum"
                    },
                    "returnData": true
                }
            ]
        }
    }
}

 

・CloudWatch からのアクセス権限を付与

関数 > 設定 > アクセス権限 > アクセス権限を追加 を押下する

プリンシパル:lambda.alarms.cloudwatch.amazonaws.com
アクション:lambda:InvokeFunction
→リソースベースのポリシーステートメント に追加されたことを確認する

 

3. CloudWatchアラームの作成

CloudWatch > アラーム > アラームの作成 を押下

メトリクス名:procstat_lookup_pid_count

統計:1

期間:1分

条件:0 以下

アラーム状態トリガー:アラーム状態

関数タイプ:サインインしたアカウントから Lambda 関数を選択

関数:restart-httpd-function

アラーム名:restart-httpd-alarm

→内容に問題がなければ、アラームを作成する

 

→OKになれば準備完了です

 

4. テスト実行

・httpdの停止

systemctl stop httpd

 

・CloudWatch

→アラーム状態になることを確認

 

・Lambdaが実行されることを確認

→モニタリング より関数の実行が成功していることを確認

 

・CloudWatchLogsから確認

→エラーが出ずに、send_command が出力されていることを確認する

 

・プロセスの確認

→EC2でhttpdプロセスが active (running) になっていること、および CloudWatchアラームが復旧することを確認する

※アラームの復旧まで結構時間がかかります

 

▼まとめ

いかがでしたでしょうか?

機構自体はそこまで難しくはなかったですが、どのIAMロールが必要になるのかや、CLoudWatchとLambdaの接続でアクセス権限を付与する必要があるなど少し厄介なところもありました

ただ、簡単な再起動などのオペレーションを自動化するときに便利であり、SNSと組み合わせてSlackやメール通知を組み込めばかなり実務でも使えそうでした

それではまたーー

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA