Monitが生きていることをCloudWatchで監視する（Ruby版）


## Monit

サーバーの運用監視を行うために色々なソフトウェアがあります。
その中でもMonitは設定が簡単で、サービスの再起動も自動で行えるなど、非常に使いやすいです。

なので、基本的には全サーバーにMonitを入れて自分自身の監視を行わせています。

ただ、Monit自体が異常停止してしまうと気付かない、という問題があります。
これまで突然死に遭遇したことは無いですが、仮に死んでしまった時には気付きたいです。

複数台サーバーがあればお互いに監視させても良いですが、SPOFを作らないように5台のサーバーに相互監視させる、となると結構面倒です。

そんな時は、CloudWatchにMonitを監視させると便利です。
AWSを良く利用するので、リソース監視と併せて、Monitも監視させましょう。

## 環境

ざっくりと要点は以下です。

* Ubuntu 12.04
* Ruby 2.1.0
* rvm

Rubyがインストールされていて、Javaがインストールされていない環境を想定しています。
rvmはシステムインストールしています。

## 設定

以下の2ステップで設定します。

1. 監視対象のサーバーから定期的にMonitのプロセス数を CloudWatchへカスタムメトリックとして送信する
2. CloudWatchで 1. で設定したカスタムメトリックの数字が1になっていることを監視する

## 監視対象サーバーでの作業

### Monitのプロセス数を確認するRubyスクリプトを作成

こんな感じです。

```ruby:/usr/local/bin/check_procs.rb
#!/usr/local/rvm/rubies/ruby-2.1.0/bin/ruby

require "aws"
instance_name = Net::HTTP.get "169.254.169.254", "/latest/meta-data/instance-id"
count_of_monit_process =  `ps -e|grep monit|wc -l`.chomp
cw = AWS::CloudWatch.new(
  access_key_id: ENV["CW_ACCESS_KEY_ID"],
  secret_access_key: ENV["CW_SECRET_ACCESS_KEY"],
  region: "ap-southeast-1"
)
cw.put_metric_data(
  namespace: "Processes",
  metric_data: [{
    metric_name: "MonitProcesses",
    dimensions: [{
      name: "InstanceId",
      value: instance_name
    }],
  value: count_of_monit_process}]
)
```

監視対象サーバーがAWSであれば、そのサーバーから http://169.254.169.254/latest/meta-data/instance-id にアクセスすると、インスタンスIDが取れます。

監視対象サーバーがAWSで無ければ適当なものを指定します。

また、AWSというgemを利用するので、適切な権限を持ったユーザーでインストールしておきます。

```bash
$ gem install aws
```

### `~/.profile`ファイルにAWSのAPI認証情報を追加

deployというユーザーで監視するとします。このユーザーの`~/.profile`ファイルの最後に下記を追加します。

```bash:/home/deploy/.profile
export CW_ACCESS_KEY_ID="ABCDEFGHI0JKL1MNOPQR"
export CW_SECRET_ACCESS_KEY="abcdefghijklmnopqrstuvwxyz1234567890ABCD"
```

環境変数名は先のRubyスクリプトと合わせておきます。
CloudWatchに書き込みができるIAMユーザーのものを設定して下さい。

試しに実行してみましょう。

```bash
$ /usr/local/bin/check_procs.rb
```

何もエラー等が表示されなければOKです。
CloudWatchの管理画面へログインして、カスタムメトリックが増えているか確認しましょう。`Processes`というnamespaceに`MonitProcesses`というmetric名で登録しました。

![スクリーンショット 2014-07-31 18.24.37.png](https://qiita-image-store.s3.amazonaws.com/0/15184/8e45415e-fad3-48e1-6265-e9559de38f5d.png "スクリーンショット 2014-07-31 18.24.37.png")

実行したサーバーのインスタンスIDで「1」が登録されていればOKです。

![スクリーンショット 2014-07-31 18.26.22.png](https://qiita-image-store.s3.amazonaws.com/0/15184/b056c8af-3046-e126-0461-d4f44a5887ea.png "スクリーンショット 2014-07-31 18.26.22.png")


可能であれば、Monitを停止した状態で再度スクリプトを実行し「0」が登録されることも確認します。

### cronに設定して定期的に情報をCloudWatchへ送る

動作確認ができたらこれをcronから自動実行しましょう。5分間隔に設定しました。

```bash
$ crontab -e
```

1行追加します。

```bash:/tmp/crontab.a1b2c3/crontab
*/5 * * * * . /home/deploy/.profile; GEM_HOME=/usr/local/rvm/gems/ruby-2.1.0 /usr/local/bin/check_procs.rb >> /home/deploy/cron.log 2>&1
```

cronからの起動も`~/.profile`が呼ばれたように記憶していたのですが、しなかったので読み込ませています。
また、rvmのために`GEM_HOME`環境変数を付けて起動しています。

この状態で、しばらく放置して、先程と同様にCloudWatchの管理画面のカスタムメトリックにちゃんと数字を登録できているか確認しましょう。

もし、CloudWatch側に登録がされなかったらログファイル`/home/deploy/cron.log`を確認して対応します。

## CloudWatch管理画面での作業

### 監視項目を追加する

CloudWatchの管理画面から「Create Alarm」を選択します。
「Custom Metric」をプルダウンから選択すると簡単に絞り込めます。

![CloudWatch_Management_Console.png](https://qiita-image-store.s3.amazonaws.com/0/15184/073999ea-08a2-da24-cc59-4da849c83cbb.png "CloudWatch_Management_Console.png")

対象のサーバーにチェックを付けて「Next」を押します。

![CloudWatch_Management_Consoles.png](https://qiita-image-store.s3.amazonaws.com/0/15184/88336d04-8e43-ecbf-ab3d-268e7287238b.png "CloudWatch_Management_Consoles.png")

アラートを出す閾値は「1未満（< 1）」にします。その他の条件は運用ポリシーに沿って決めます。
最後に「Create Alarm」を押せば完了です。

可能ならば、実際にMonitを停止して動作確認をします。