Amazon EventBridgeを使用したEC2上のApache監視/停止検知から自動再起動までの設定手順

## はじめに
AWS EC2インスタンス内でApache（httpd）のサービスを実行している場合、Apacheが停止することを検知する仕組みを導入することは、システムの可用性を確保する上で重要です。

この記事では、Amazon EventBridgeを活用してApacheのサービス停止を監視する方法について解説します。

Apacheサービスの停止を監視し、迅速な対応を可能にするための設定手順を紹介します。

## 前提条件
:::note 
この記事では以下のものが前提となります。

**・EC2インスタンスが稼働中で、Apache（httpd）がインストールされていること。**
**・EC2インスタンスにCloudWatchエージェントがインストールされていること。**
**・AWS CLIが設定されていること。**
:::

## 手順1: CloudWatchエージェントのインストールと設定
まず、EC2インスタンスにCloudWatchエージェントをインストールし、Apacheプロセスを監視できるように設定します。

### CloudWatchエージェントのインストール 
CloudWatchエージェントをまだインストールしていない場合は、次のコマンドでインストールします。
```
sudo yum install amazon-cloudwatch-agent
```

### CloudWatchエージェントの設定ファイル作成
Apache（httpd）のプロセスを監視するための設定ファイルを作成します。この設定ファイルにより、httpdプロセスが停止した場合にCloudWatchへメトリクスを送信します。

```json
{
  "metrics": {
    "append_dimensions": {
      "InstanceId": "${aws:InstanceId}"
    },
    "aggregation_dimensions": [["InstanceId"]],
    "metrics_collected": {
      "procstat": {
        "measurement": ["cpu_usage", "memory_rss"],
        "pid_file": "/var/run/httpd/httpd.pid",
        "process_name": "httpd",
        "interval": 60
      }
    }
  }
}
```

この設定では、Apacheのプロセス（httpd）が動作しているかどうかを60秒ごとに確認し、その状態をCloudWatchに送信します。

### CloudWatchエージェントの開始 
次に、CloudWatchエージェントを起動し、設定を適用します。

```
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
-a start \
-c file:/path/to/your/config.json \
-m ec2
```

## 手順2: CloudWatchアラームの設定
CloudWatchに送信されたApacheのプロセス状態を元に、アラームを設定します。

### CloudWatchメトリクスを確認 
CloudWatchコンソールにログインし、「メトリクス」セクションでprocstatメトリクスを確認します。httpdプロセスに関連するメトリクスが記録されていることを確認してください。

### アラーム作成 
メトリクスに基づいてアラームを作成します。httpdプロセスが停止したとき（cpu_usageがゼロになった場合）にアラームが発火するよう設定します。

CloudWatchコンソールで「アラーム」を選択し、「アラームの作成」をクリックします。
対象のメトリクス（procstat.cpu_usage）を選択し、しきい値を「0」に設定します。

アラームのアクションとして、通知や自動的なリカバリプロセスを設定します（例: SNSを使用して通知を送信する）。

## 手順3: EventBridgeルールの作成
EventBridgeを使用して、Apacheが停止したときにカスタムイベントをトリガーするルールを作成します。

例えば、Apacheが停止した場合に通知を送信する、もしくはLambda関数を呼び出して自動的にApacheを再起動することが可能です。

### EventBridgeルールの作成 
AWSマネジメントコンソールにログインし、EventBridgeの「ルール」セクションに移動します。

「ルールの作成」をクリックします。
ルール名を入力し、ルールのイベントソースとして「CloudWatchアラーム状態変更」を選択します。
アラームがALARM状態になったときにトリガーするアクションを設定します。例えば、SNSトピックを使用してメール通知を送信するか、Lambda関数をトリガーしてApacheを再起動することができます。

### SNSトピックの作成 
SNSを使用して通知を受け取る場合は、以下の手順でSNSトピックを作成します。

SNSコンソールに移動し、「トピックの作成」をクリックします。
トピック名を入力し、通知を受け取るメールアドレスを登録します。

### アクションの設定 
EventBridgeルールのアクションとして、SNSトピックを指定し、Apacheが停止した際に通知を送信します。

また、必要に応じてLambda関数をトリガーし、Apacheの自動再起動や他のリカバリアクションを実行することも可能です。

## 手順4: Lambda関数によるApacheの自動再起動（オプション）
Apacheが停止した場合に自動で再起動させたい場合は、Lambda関数をトリガーしてApacheを再起動することができます。

### Lambda関数の作成 
以下のような簡単なLambda関数を作成し、Apacheの再起動を実行します。
```python
import boto3
import paramiko

def lambda_handler(event, context):
    ec2 = boto3.resource('ec2')
    instance = ec2.Instance('i-0123456789abcdef0')
    
    if instance.state['Name'] == 'running':
        # SSH接続しApacheを再起動
        key = paramiko.RSAKey.from_private_key_file("/path/to/key.pem")
        client = paramiko.SSHClient()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        client.connect(hostname=instance.public_ip_address, username="ec2-user", pkey=key)
        
        stdin, stdout, stderr = client.exec_command("sudo systemctl start httpd")
        print(stdout.read().decode())
        client.close()
    return "Apache restarted"
```

### Lambdaのトリガー設定 
EventBridgeのルールにより、アラームが発生したときにこのLambda関数がトリガーされるように設定します。

## まとめ
AWS EventBridgeを使用して、EC2インスタンス上のApacheサービスの監視と自動対応を実装することができます。

CloudWatchエージェントを使用してApacheのプロセスを監視し、停止時にアラームをトリガーすることで、システム管理者に通知したり、サービスの自動再起動を行うことが可能です。

これにより、システムのダウンタイムを最小限に抑えることができ、可用性の向上に寄与します。

## おまけ：2つのインスタンスが「両方停止」したときにイベントをトリガーする場合

EventBridge単独では「両方のインスタンスが停止した」ことを直接的にトリガー条件として扱うことはできません。しかし、Lambda関数を使用して、両方のインスタンスの状態をチェックすることで実現可能です。

:::note
以下のステップで構築できます。
**EventBridgeルールで個別のインスタンス停止イベントをキャッチ** 
上記のようなルールを設定し、各インスタンスが停止したときにLambda関数をトリガーします。

**Lambda関数で両方のインスタンスの状態を確認** Lambda関数内で、AWS SDK (Boto3など) を使用して、両方のインスタンスの現在の状態を確認します。もし両方とも停止している場合、次のアクションを実行するように設定します。
:::

これにより、2台のインスタンスが両方停止したときにアクションをトリガーすることができます。