Sensu+Uchiwa+Grafanaでインフラ監視環境を構築する

こんにちは、@yuskuboです。
本記事は [LIFULL Advent Calendar 2018](https://qiita.com/advent-calendar/2018/lifull) の11日目の記事です。

最近、初めてインフラ監視環境を一から構築しました。監視ツールにはSensuとGrafanaを使用したのですが、複数のミドルウェアを連携させる必要があり、全体感の把握が難しかったり、繋ぎ込み部分で苦労したりしたので、一連の設定手順とポイントを記載していきます。

# 目的
SensuとGrafanaの仕組みと関連ミドルウェアを知り、基本的な設定手順を理解することが目的です。

# 前提事項
- どのように機能するかを理解することが目的なので、本手順ではPuppetやChefの様なサーバ環境構築/運用自動化ツールは使用しません。Sensuの[公式ページ](https://docs.sensu.io/sensu-core/1.6/installation/overview/)でも、学習のために自動化ツールを使わずにインストールすることで、Sensuのコンポーネントがどのように機能するかを深く理解できる旨のことが書かれています。ただし、本番環境への導入には、PuppetやChefを使用した構築が推奨されていますので、ご注意下さい。
- サーバはAmazon Linux2を使用します。
- サーバ間の通信はできる前提です。必要に応じて、セキュリティグループやネットワークACLを許可してください。Sensuが使用するプロトコルおよびポートは公式ページの[FAQ](https://docs.sensu.io/sensu-core/1.6/faq/#sensu-frequently-asked-questions)に書いてあります。
- 2018年12月時点の情報です。本記事で登場するミドルウェアを利用する際は、公式の最新情報も合わせてご確認下さい。

# 全体構成図
Sensuは登場するミドルウェアも多く、初めのうちは全体感を掴みにくいので、監視サーバと監視対象サーバ、それぞれに何を導入し、どう連携するのかをまずは把握して下さい。
![監視構成図.png](https://qiita-image-store.s3.amazonaws.com/0/174425/c54ba2f6-0209-ef95-cf88-8718473878f4.png)

※画像引用[^1] 
[^1]: https://github.com/sensu/sensu-logo | https://go.chatwork.com/ja/download/cw_logo.html

# 基本用語
- **監視サーバ**  
「監視をする側」のサーバのことを指します。
- **監視対象サーバ**  
「監視をされる側」のサーバのことを指します。
- **Sensu**  
SensuはRuby製のオープンソース監視ツールです。「Sensu Client」、「Sensu Server」、「Sensu API」の3つのコンポーネントから構成されています。
  - **Sensu Client**  
Sensu Clientは、監視対象サーバ上で動作し、Sensu Serverからの「Check Request」を取得して、その内容に応じたCheck処理を実行し、結果を返します。
  - **Sensu Server**  
Sensu Serverは、監視サーバ上で動作し、Sensu Clientに対して「Check Request」（チェック要求）を発行、チェック後Sensu Clientから返された「Check Results」（チェック結果）の処理とハンドリングを行います。取得した「Check Results」は、RedisやGraphiteへ蓄積します。
  - **Sensu API**  
Sensu APIは、監視サーバ上で動作し、収集した監視データへのアクセスを提供します。
- **Sensu Plugins**  
Sensu Pluginsは、チェック要求に対して実行されるRubyで書かれたチェックスクリプト群です。有志のコミュニティーで開発されていますが、自身で必要なスクリプトを作成し、使用することも可能です。
- **Redis**  
オープンソースのKey-Value型のインメモリデータベースです。Sensuでは、監視データを格納するために使用されます。
- **Uchiwa**  
Sensuのダッシュボードソフトウェアで、監視項目や取得したメトリクスなど、収集したSensuの情報を閲覧することができます。ただし、グラフ描画機能はないので、グラフ化したい場合は、他のダッシュボードソフトウェアも必要になります。
- **Graphite**  
データの収集、保存、解析、可視化の機能を提供する監視ツールです。主には、「carbon-cache」、「whisper」、「graphite-web」の3つのコンポーネントから構成されています。  
  - **carbon-cache**  
メトリクスを受信し、ディスクに書き込むデーモンです。
  - **whisper**  
  固定サイズの時系列データ​​ベースで、RRD（ラウンドロビンデータベース）と同様の設計で作られています。収集した一定期間のメトリクスデータをまとめて、平均値や最小最大値などを計算し、その計算結果を格納します。
  - **graphite-web**  
  graphite-webは、蓄積したメトリクスデータの読込要求を受け付けるWebアプリケーションで、Djangoで作られています。クライアントからのリクエストに応じて、whisperライブラリを通して該当ファイルのデータを読み出し、グラフをレンダリングします。 Webサーバには、gunicornやuWSGIを使用するのが一般的です。また、graphite-webには、ユーザープロファイルを格納するためにデータベースも必要で、デフォルトではSQLiteが使用されます。
- **SQLite**  
軽量コンパクトなRDBSで、アプリケーションに組み込まれて利用されることも多いです。Graphiteでは、graphite-webのユーザ情報やダッシュボード情報を格納するために使用されます。
- **Grafana**  
ダッシュボードソフトウェアで、蓄積されたメトリクスをグラフ描画し、視覚化することができます。
- **RabbitMQ**  
オープンソースのメッセージ指向ミドルウェアです。Sensu ServerからSensu Clientに監視実行を要求したり、Sensu ClientからSensu Serverに監視結果を送信したりする際に、Sensu ServerとSensu Client間の通信のために使用します。

# 監視対象サーバの設定
まずは、「監視される側」のサーバの設定を行なっていきます。

## 1. Sensuのインストール
Sensuをインストールすると、Sensu Server、Sensu Client、Sensu APIが含まれていますが、監視対象サーバでは、Sensu Clientだけを使用します。
特に理由がなければ、最新のバージョンをインストールすればOKです。通常、下記のように変数$releaseverを使用することで、最新バージョンを取得できます。

```bash:bash
baseurl=https://sensu.global.ssl.fastly.net/yum/$releasever/$basearch/
```
ただし、Red Hat系派生のプラットフォームの場合、$releasever変数の値は、Sensu Yumリポジトリに公開されているRHELリリースのバージョン（例えば6または7）と一致しないため、直接バージョン数を指定する必要があります。SysVinitを使用する場合は「6」、systemdを使用する場合は「7」を使用します。今回は、Amazon Linux2を使用するので、バージョン「7」を指定します。

```bash:bash
# sensuリポジトリの追加
$ echo '[sensu]
name=sensu
baseurl=https://sensu.global.ssl.fastly.net/yum/7/$basearch/
gpgkey=https://repositories.sensuapp.org/yum/pubkey.gpg
gpgcheck=1
enabled=0' | sudo tee /etc/yum.repos.d/sensu.repo
 
# sensuのインストール
$ sudo yum install sensu --enablerepo=sensu
```

## 2. Sensu Pluginsのインストール
プラグインは、[GitHub](https://github.com/sensu-plugins) に公開されているので、必要なプラグインを検索し、導入していきます。一般的に使用されるようなチェック項目については一通り揃っているので、例えば、「disk」や「network」、「aws」などで検索すれば、大抵のものは見つけられます。本記事では、ディスク監視とネットワーク監視のプラグインを導入してみます。
プラグインのインストールには、「sensu-install」コマンドを使用します。「-p」オプションは、プラグインを意味します。

```bash:bash 
# ディスク監視
$ sudo sensu-install -p sensu-plugins-disk-checks

# ネットワーク監視
$ sudo sensu-install -p sensu-plugins-network-checks 
```

## 3. 設定ファイルの作成
### ・ config.jsonの作成
Sensuのメイン設定ファイルであるconfig.jsonを作成します。ただし、設定内容は目的に応じてファイルを分けた方が管理しやすいと思うので、今回はこのファイルには何も設定せず、ファイルのみ作成します。個々の設定ファイルは、「conf.d」ディレクトリ以下に配置します。このあたりのファイル構成は、お好みで調整してみて下さい。

```bash:bash
$ echo '{
}' |sudo tee /etc/sensu/config.json
 
# 所有者/グループをsensuに変更
$ sudo chown sensu:sensu /etc/sensu/config.json
```
### ・ client.jsonの作成
監視対象サーバの情報を設定します。主な設定項目は下記の通りです。

- name： 監視対象サーバ自身のサーバ名を指定します。
- address： 監視対象サーバ自身のIPアドレスを指定します。
- subscriptions： 監視対象サーバで実行するチェックを決めるための項目です。ここで指定したRoleと、Sensu Serverで指定した「subscribers」が一致すると、チェックが実行されます。resourceやweb-appなど、チェックの役割を表すロール名は、自身で自由に決めることができます。
- keepalive： Sensu Clientからメッセージを発信することで死活監視の役割を担います。今回はhandlerにchatworkを指定し、疎通確認ができなくなった場合に、chatworkへエラー通知することにします。

```bash:bash
$ echo '{
  "client": {
    "name": "hoge-app01",
    "address": "192.168.xxx.xx",
    "subscriptions": [
      "resource"
    ],
    },
    "keepalive": {
      "handler": "chatwork"
    }
  }
}' |sudo tee /etc/sensu/conf.d/client.json
```
## 4. rabbitmg.jsonの作成
rabbitmqを通じてやり取りするSensu Serverの情報（監視サーバの情報）を指定します。vhost、user、passwordは、自身で決めることができ、監視サーバ側で定義します。また、portはデフォルトの5672を使用することにします。

```bash:bash
$ echo '{
  "rabbitmq": {
    "host": "192.168.xxx.xxx",
    "port": 5672,
    "vhost": "/sensu",
    "user": "sensu",
    "password": "sensu"
  }
}' |sudo tee /etc/sensu/conf.d/rabbitmq.json
 
# 所有者/グループをsensuに変更
$ sudo chown sensu:sensu -R /etc/sensu/conf.d/
```

## 5. sensu-clientの起動・停止
```bash:bash
# 自動起動設定を有効化
$ sudo systemctl enable sensu-client.service

# 自動起動されていることを確認
$ systemctl list-unit-files --type service | grep sensu
 
# Sensu Clientを起動
$ sudo systemctl start sensu-client.service

# Sensu Clientが正常起動していることを確認
$ sudo systemctl status sensu-client.service
```

## 6. その他ポイント
### ・ プラグインを手動実行したい場合  
プラグインから得られる結果が期待通りかわからない場合、手動で実行して確かめることができます。ただし、パラメータが必須のプラグインもあるので、その場合はパラメータも指定して下さい。また、実行時に「-help」オプションを付けることで必要なパラメータを確認することもできます。
下記は、ディスクチェックのプラグインです。使用率が85%未満なので、チェックOKとなってます。85%という閾値はデフォルト値なので、パラメータ指定で変更可能です。

```bash:bash
$ /opt/sensu/embedded/bin/ruby /opt/sensu/embedded/bin/check-disk-usage.rb
CheckDisk OK: All disk usage under 85% and inode usage under 85%
```

### ・ パラメータをSensu Client側に持たせたい場合  
上記でも述べたようにチェック系のプラグインは、警告やエラーの閾値を指定できることが多くあります。その場合、Sensu Server側のチェックスクリプト呼び出し時に一律指定することもできますが、運用上サーバによって閾値を変えたい場合が多いと思います。その場合は、Sensu Client側のclient.jsonに閾値を定義し、Sensu Server側から参照することで、サーバ毎の閾値設定が可能になります。なお、閾値に付ける名称は自身で自由に決めることができますが、監視対象サーバと監視サーバで一致させる必要があります。監視サーバから参照する場合は、Sensu Server側のチェックjsonで「-w :::boundary.disk-warn::: -c :::boundary.disk-crit:::」のように指定します。
監視対象サーバには、下記のように指定します。

```bash:client.json
{
  "boundary": {
    "disk-warn": 70,
    "disk-crit": 80
  },
}
```

監視サーバ側からは、下記のように参照できます。（一部抜粋）

```bash:check-disk.json
"command": "check-disk-usage.rb -w :::boundary.disk-warn::: -c :::boundary.disk-crit:::"
```

### ・ パラメータに機密情報を含む場合  
指定したパラメータの値はuchiwaのダッシュボード画面に出てしまうので、ユーザ名やパスワードのような機密情報は、パラメータに直接指定せず、別ファイルに格納し読み込ませることが望ましいです。ただし、別ファイル保存に対応していないプラグインの場合は、redact属性を指定することで、ダッシュボード上で見えないようにすることができます。

```bash:client.json
{
  "authentication": {
    "hoge-user": "hoge",
    "hoge-pass": "hogehoge"
  },
  "redact": [
    "hoge-user",
    "hoge-pass"
  ],
}
```

### ・ プラグインをアンインストールしたい場合  
不要となったプラグインをアンインストールしたい時は、下記のようにしてアンインストールすることができます。これで対象のプラグインに関する全てのモジュールが削除されます。

```bash:bash
$ sudo /opt/sensu/embedded/bin/gem uninstall sensu-plugins-disk-checks
```

### ・ ja_JP環境でプラグインがうまく動かない場合  
私の場合、ネットワーク監視系のプラグインであるmetrics-netif.rbを使用した時にこの事象が発生しました。metrics-netif.rbは、sarコマンドを実行し、その結果をgrepしてメトリクスデータを返すプラグインです。ja_JP環境ではsarコマンドの結果は「平均値」として得られるので、パラメータに「平均値」を指定したのですが、パラメータエラーで機能しませんでした。原因を特定できなかったので、Sensu Clientを「en_US」で起動するようにし、sarコマンドの結果を「Average」で得ることで回避しました。もし同様の事象が発生した場合は、試してみてください。

```bash:bash
# ユニットファイルから参照する環境設定ファイルを新規作成
$ sudo vim /etc/sysconfig/sensu.conf
LANG=en_US.UTF-8
export LANG

# ユニットファイルに環境設定ファイルの参照を追加(Group=sensuの下に追記)
$ sudo vim /usr/lib/systemd/system/sensu-client.service
EnvironmentFile=/etc/sysconfig/sensu.conf

# 再読み込み
$ sudo systemctl daemon-reload
```

### ・ Sensuプラグインの環境設定を確認したい場合
下記のようにして環境設定を確認できます。

```bash:bash
$ /opt/sensu/embedded/bin/gem env
```

### ・ Sensuプラグインのスクリプトを確認したい場合
実行するプラグインの起点となるスクリプトファイルは、以下に配置されます。

```bash:bash
$ ll /opt/sensu/embedded/bin/
```
プラグインの処理が書かれたスクリプトファイルは以下に配置されます。チェック処理を変更したい場合は、配下のスクリプトを修正することでカスタマイズすることもできます。

```bash:bash
$ ll /opt/sensu/embedded/lib/ruby/gems/2.4.0/gems/
```

# 監視サーバの設定
次に、「監視する側」のサーバの設定を行なっていきます。

## 1. パッケージ導入
SensuプラグインやGraphiteに下記パッケージが必要になるので、事前にインストールします。

```bash:bash
$ sudo yum groupinstall "Development Tools"
 
$ sudo yum install gcc gcc-c++ libxml2-devel zlib-devel python-devel cairo-devel libffi-devel
```

## 2. Sensuのインストール
監視対象サーバと同じようにSensuをインストールします。監視サーバには、Sensu Server、Sensu Client、Sensu APIの3つを設定します。Sensu Clientを監視サーバにも設定することで、監視サーバ自身を監視することも可能です。監視サーバに問題が出てしまっては、他のサーバの状況がわからなくなってしまうため、監視サーバのリソース使用状況等も監視しておくと良いでしょう。
なお、「[ja_JP環境でプラグインがうまく動かない場合](#-ja_jp環境でプラグインがうまく動かない場合)」で説明したように、今回は「en_US」環境で、Sensuを起動したいので、監視サーバも設定を合わせておきます。

```bash:bash
# sensuリポジトリの追加
$ echo '[sensu]
name=sensu
baseurl=https://sensu.global.ssl.fastly.net/yum/7/$basearch/
gpgkey=https://repositories.sensuapp.org/yum/pubkey.gpg
gpgcheck=1
enabled=0' | sudo tee /etc/yum.repos.d/sensu.repo
 
# sensuインストール
$ sudo yum install sensu --enablerepo=sensu

# ユニットファイルから参照する環境設定ファイルを新規作成
$ sudo vim /etc/sysconfig/sensu.conf
LANG=en_US.UTF-8
export LANG
 
# ユニットファイルに環境設定ファイルの参照を追加(Group=sensuの下に追記)
$ sudo vim /usr/lib/systemd/system/sensu-client.service
EnvironmentFile=/etc/sysconfig/sensu.conf

$ sudo vim /usr/lib/systemd/system/sensu-server.service
EnvironmentFile=/etc/sysconfig/sensu.conf

$ sudo vim /usr/lib/systemd/system/sensu-api.service
EnvironmentFile=/etc/sysconfig/sensu.conf
 
# 再読み込み
$ sudo systemctl daemon-reload
```

## 3. Sensu Pluginsのインストール
監視サーバ側でもプラグインをインストールしていきます。リソース監視用のプラグインに加えて、監視サーバには、graphiteやchatwork、mailer、AWSなど、チェック結果を処理するためのプラグインが必要です。AWSはメール通知をするにあたり、SESを利用するために必要なプラグインです。

```bash:bash
# ディスク監視
$ sudo sensu-install -p sensu-plugins-disk-checks

# ネットワーク監視
$ sudo sensu-install -p sensu-plugins-network-checks 

# graphiteへの整形
$ sudo sensu-install -p sensu-plugins-graphite
 
# chatwork通知
$ sudo sensu-install -p sensu-plugins-chatwork

# メール通知
$ sudo sensu-install -p sensu-plugins-mailer

# AWS監視
$ sudo sensu-install -p sensu-plugins-aws
```
AWS監視プラグインを使用するには、AWSへの認証情報が必要になります。AWSの認証情報は、セキュリティ面を考慮し、スクリプトのパラメータとして直接指定するのではなく、必ず別ファイルに格納するようにしましょう。

```bash:bash
# AWSの認証情報を配置するディレクトリを作成
$ sudo mkdir /opt/sensu/.aws

# アクセスキーを記載するファイルを作成
$ sudo vim /opt/sensu/.aws/credentials
[default]
aws_access_key_id = HOGE
aws_secret_access_key = HOGEHOGE

# 所有者/グループを変更
$ sudo chown sensu:sensu /opt/sensu/.aws
```

## 4. Sensuの設定ファイル作成
### ・ config.jsonの作成  
監視対象サーバと同様に設定は行わずに、ファイルだけ作成します。

```bash:bash
# config.jsonの作成
$ echo '{
}' |sudo tee /etc/sensu/config.json

# 所有者/グループを変更
$ sudo chown sensu:sensu /etc/sensu/config.json
```

### ・ client.jsonの作成  
監視サーバ自身の内容を設定します。

```bash:bash
$ echo '{
  "client": {
    "name": "hoge-resource-monitor",
    "address": "127.0.0.1",
    "subscriptions": [
      "resource"
    ],
  }
}' |sudo tee /etc/sensu/conf.d/client.json
```

### ・ api.jsonの作成  
監視サーバのホスト名と、Sensu APIが使用するportを設定します。デフォルトでは、4567ポートを使用します。

```bash:bash
# Sensu-apiがインストールされているサーバの
$ echo '{
  "api": {
    "host": "127.0.0.1",
    "bind": "0.0.0.0",
    "port": 4567
  }
}' |sudo tee /etc/sensu/conf.d/api.json
```

### ・ リソース監視用のChecksの追加  
収集したいメトリクスやチェックしたいプロセスに応じて、jsonファイルを作成していきます。主な設定項目は下記の通りです。  

- custom-summary：チェック処理の概要を記載します。  
- type：プラグインの監視タイプを指定します。「standard」と「metric」があり、デフォルトは「standard」なので、メトリクスの時だけ、「metric」を指定すればOKです。  
- command：実行するプラグインを指定します。sensu-installコマンドでインストールして、「/opt/sensu/embedded/bin/」に格納されている場合は、パスを指定する必要はありません。自身でプラグインを作成して別のディレクトリに格納したい場合は、パスも指定する必要があります。  
- occurrences：handlersの処理対象となる発生回数を指定します。1を指定した場合、一度でも閾値を超過すると、chatworkとメールでエラー通知されます。  
- interval：checkの実施間隔（秒）を指定します。  
- refresh：一度handlersで処理されてから、再度handlersの処理対象になるまでの間隔（秒）を指定します。3600の場合、1時間後に再度、chatworkとメールでエラー通知されます。この項目を設定しなかった場合、intervalが経過する度に通知がされてしまいます。  
- subscribers：どのサーバでこのチェックを実行するかの目印になります。監視対象サーバ側のclient.jsonに定義した「subscriptions」と一致すると、チェックが実行されます。  
- handlers：リソースの使用率チェックやプロセスチェックなど、警告/エラー通知が必要なものは、chatworkやメールを設定します。リソースの使用率やネットワーク速度など、蓄積するメトリクスの場合は、graphiteを指定します。

```bash:bash
# ディスク使用率チェック用jsonの作成
$ echo '{
  "checks": {
    "check-disk": {
      "custom-summary": "ディスク使用率の監視",
      "command": "check-disk-usage.rb -w :::boundary.disk-warn::: -c :::boundary.disk-crit:::",
      "occurrences": 1,
      "interval": 60,
      "refresh": 3600,
      "subscribers": [
        "resource"
      ],
      "handlers": [
        "chatwork",
        "mailer-ses"
      ]
    }
  }
}' |sudo tee /etc/sensu/conf.d/checks/check-disk.json

# ディスク利用状況の収集用jsonファイルの作成
$ echo '{
  "checks": {
    "metrics-disk-usage": {
      "custom-summary": "ディスク利用状況の監視",
      "type": "metric",
      "command": "metrics-disk-usage.rb",
      "interval": 60,
      "subscribers": [
        "resource"
      ],
      "handlers": [
        "graphite"
      ]
    }
  }
}' |sudo tee /etc/sensu/conf.d/checks/metrics-disk-usage.json

# ネットワーク情報の収集用jsonファイルの作成
$ echo '{
  "checks": {
    "metrics-network": {
      "custom-summary": "ネットワーク情報の監視",
      "type": "metric",
      "command": "metrics-netif.rb",
      "interval": 60,
      "subscribers": [
        "resource"
      ],
      "handlers": [
        "graphite"
      ]
    }
  }
}' |sudo tee /etc/sensu/conf.d/checks/metrics-network.json
```

### ・ デフォルトhandlerを作成  
handlerはチェック結果によって生成されるイベントに対して、どう対処するかを設定するためのものです。handlerが指定されていないイベントに対しては、デフォルトhandlerが使用されます。

```bash:bash
$ echo '{
  "handlers": {
    "default": {
      "type": "set",
      "handlers": [
        "stdout"
      ]
    },
    "stdout": {
      "type": "pipe",
      "command": "cat"
    }
  }
}' |sudo tee /etc/sensu/conf.d/handler.json
```

### ・ graphite用のhandlerを作成  
個別ハンドラ用のディレクトリを作成し、そこにgraphite用のhandlerを作成します。

```bash:bash
$ sudo mkdir /etc/sensu/conf.d/handlers

$ echo '{
  "handlers": {
    "graphite": {
      "type": "tcp",
      "mutator": "graphite_mutator",
      "socket": {
        "host": "127.0.0.1",
        "port": 2003
      }
    }
  }
}' |sudo tee /etc/sensu/conf.d/handlers/graphite.json
```

### ・ Mutatorの追加  
Mutatorは、チェック結果を変換するためのプラグインです。今回は、チェック結果をgraphiteへ格納できるように変換してくれうプラグインを設定します。mutator用のディレクトリを作成し、そこに格納していきます。

```bash:bash
$ sudo mkdir /etc/sensu/conf.d/mutators

# graphite用に整形するスクリプトを設定
$ echo '{
  "mutators": {
    "graphite_mutator": {
      "command": "mutator-graphite.rb",
      "timeout": 10
    }
  }
}' |sudo tee /etc/sensu/conf.d/mutators/graphite_mutator.json
```

## 5. chatworkの設定
chatwork通知するための設定をします。まずは、自身のサーバからchatworkへ繋がることを確認します。事前にchatworkのAPI Tokenを取得しておいて下さい。chatworkのAPIの詳細は、[chatworkの公式ページ](http://developer.chatwork.com/ja/)をご確認下さい。

```bash:bash
# 監視サーバからchatworkに投稿できることを確認
$ curl -X POST -H "X-ChatWorkToken: 1234567890hogehogehogehogehogeho" -d "body=Hello+ChatWork%21&self_unread=0" "https://api.chatwork.com/v2/rooms/123456789/messages"
```

### ・ プラグインのインストール  
他のプラグインと同様に、chatwork通知用のプラグインがコミュニティによって開発されていますが、日本語の通知内容が見にくいため、本記事では日本語対応のプラグインを使用することにします。

```bash:bash
$ sudo mkdir /etc/sensu/handlers

$ cd /etc/sensu/handlers

$ sudo wget https://gist.githubusercontent.com/doublemarket/b21439920dcaf6353a21/raw/84bcac4fee0b1c5ffdfc67542de38d6e9d013605/chatwork.rb

# ファイル名を変更
$ sudo mv chatwork.rb handler-chatwork.rb

# 実行権限を付与
$ sudo chmod 755 handler-chatwork.rb

# chatworkの最新エンドポイントはv2なので、v1からv2に変更する
$ sudo vim handler-chatwork.rb
# uri = URI("https://api.chatwork.com/v1/rooms/#{room_id}/messages")
uri = URI("https://api.chatwork.com/v2/rooms/#{room_id}/messages")

# 通知先chatwork情報を記載
$ echo '{
  "chatwork": {
    "api_key": "d1234567890",
    "room_id": "123456789",
    "admin_gui": "http://hoge-global-alb-123456.ap-northeast-1.elb.amazonaws.com:3000/"
  }
}' |sudo tee /etc/sensu/conf.d/chatwork.json

# chatwork handler用の設定ファイルを作成
$ echo '{
  "handlers": {
    "chatwork": {
      "type": "pipe",
      "command": "/etc/sensu/handlers/handler-chatwork.rb",
      "severities": [
        "ok","warning","critical","unknown"
      ]
     }
  }
}' |sudo tee /etc/sensu/conf.d/handlers/chatwork.json
```

## 6. Mailの設定
Mail通知するための設定をします。事前にAWS SESへのメールアドレス登録とAWS IAMによるアクセスキーの取得を行なっておいて下さい。

```bash:bash
# 通知先AWS SESの情報ファイルを作成
$ echo '{
  "mailer-ses": {
    "mail_from": "hoge@hoge.com",
    "mail_to": "hoge@hoge.com",
    "aws_access_key": "HOGE",
    "aws_secret_key": "HogeHoge",
    "aws_ses_endpoint": "email.us-west-2.amazonaws.com",
    "subject_prefix": ""
  }
}' |sudo tee /etc/sensu/conf.d/mailer-ses.json

# Mail handler用の設定ファイルを作成
$ echo '{
  "handlers": {
    "mailer-ses": {
      "type": "pipe",
      "command": "handler-mailer-ses.rb",
      "severities": [
        "ok","warning","critical","unknown"
      ]
    }
  }
}' |sudo tee /etc/sensu/conf.d/handlers/mailer-ses.json
```

## 7. Sensuの起動

```bash:bash
# 所有者/グループを変更
$ sudo chown sensu:sensu -R /etc/sensu/conf.d

# 自動起動設定を有効にする
$ sudo systemctl enable sensu-client.service && sudo systemctl enable sensu-server.service && sudo systemctl enable sensu-api.service

# 自動起動設定の確認
$ systemctl list-unit-files --type service | grep sensu

# sensu-client/sensu-server/sensu-apiを起動
$ sudo systemctl start sensu-client.service && sudo systemctl start sensu-server.service && sudo systemctl start sensu-api.service

# sensu-client/sensu-server/sensu-apiが動いていることを確認
$ sudo systemctl status sensu-client.service && sudo systemctl status sensu-server.service && sudo systemctl status sensu-api.service
```

## 8. uchiwaのインストール
下記手順に従ってuchiwaを起動後に、監視サーバのURLへ指定したポートでアクセスするとuchiwaの画面が表示されます。

```bash:bash
# uchiwaをインストール
$ sudo yum install uchiwa --enablerepo=sensu
```
### ・ uchiwa.jsonの作成
sensuがインストールされているサーバと使用するport、uchiwaのユーザ情報を定義します。主な設定項目は下記の通りです。

- sensu  
  - host： Sensu APIのホスト名を指定します。  
  - port： Sensu APIのポートを指定します。  
- uchiwa  
  - user： uchiwaダッシュボードにログインするユーザ名を指定します。
  - pass： uchiwaダッシュボードにログインするユーザのパスワードを指定します。
  - port： uchiwaダッシュボードにアクセスする際に使用するポートを指定します。　

```bash:bash
$ echo '{
  "sensu": [
    {
      "host": "127.0.0.1",
      "port": 4567
    }
  ],
  "uchiwa": {
    "user": "sensu",
    "pass": "sensu",
    "port": 3000,
    "refresh": 10
  }
}' |sudo tee /etc/sensu/uchiwa.json
```
### ・ Sensuの再起動
Sensuの設定ファイルに追加、変更があった場合は、Sensuの再起動が必要になります。

```bash:bash
# 所有者/グループを変更
$ sudo chown uchiwa:uchiwa /etc/sensu/uchiwa.json

# sensu-client/sensu-server/sensu-apiを再起動
$ sudo systemctl restart sensu-client.service && sudo systemctl restart sensu-server.service && sudo systemctl restart sensu-api.service

# sensu-client/sensu-server/sensu-apiが動いていることを確認
$ sudo systemctl status sensu-client.service && sudo systemctl status sensu-server.service && sudo systemctl status sensu-api.service
```

### ・ uchiwaの起動

```bash:bash
# システム起動時にuchiwaを起動(systemdに対応していないので、代わりにchkconfigが実行される)
$ sudo systemctl enable uchiwa.service
uchiwa.service is not a native service, redirecting to /sbin/chkconfig.
Executing /sbin/chkconfig uchiwa on

# uchiwaを起動
$ sudo systemctl start uchiwa.service

# uchiwaが起動していることを確認
$ sudo systemctl status uchiwa.service
```

## 9. Redisのインストール
Redisは2018年12月時点で最新の5.0.2をインストールしたいため、今回はソースからインストールすることにします。バージョンを気にしなければ、yumからインストールでもOKです。

### ・ コンパイルとインストール

```bash:bash
$ sudo su - root

# 最新バージョンを取得
[root]$ wget http://download.redis.io/releases/redis-5.0.2.tar.gz

# ダウンロードしたパッケージを展開
[root]$ tar xzf redis-5.0.2.tar.gz

[root]$ cd redis-5.0.2

# コンパイル
[root]$ make

# make testには、tcl 8.5以上が必要なので、インストールしていない場合は事前にインストールする
[root]$ yum install tcl

# テスト実行
[root]$ make test

# make testの結果が「All tests passed without errors!」になったら実行
[root]$ make install

# インストールされていることを確認する
[root]$ ll /usr/local/bin/

[root]$ exit
```

### ・ redisの設定

```bash:bash
# redisディレクトリを作成
$ sudo mkdir /etc/redis

# 設定ファイルの雛形をコピー
$ sudo cp redis.conf /etc/redis/

# 171行目の「logfile」にログ出力先ディレクトリを指定
# 264行目の「dir」に作業ディレクトリを指定
$ sudo vim /etc/redis/redis.conf
logfile /var/log/redis/redis.log
dir /var/lib/redis

# ユニットファイルの新規作成
# 「/etc/systemd/system/」ディレクトリは、システム管理者が作成、カスタマイズするユニットファイル用に予約されています
$ echo '[Unit]
Description=Redis In-Memory Data Store
After=network.target

[Service]
User=redis
Group=redis
ExecStart=/usr/local/bin/redis-server /etc/redis/redis.conf
ExecStop=/usr/local/bin/redis-cli shutdown
Restart=always

[Install]
WantedBy=multi-user.target
' |sudo tee /etc/systemd/system/redis.service

# ログ出力先ディレクトリを作成
$ sudo mkdir /var/log/redis

$ sudo chmod 755 /var/log/redis/

# 所有者/グループを変更
$ sudo chown redis:redis /var/log/redis/

# 自動起動設定を有効にする
$ sudo systemctl enable redis.service

# 自動起動設定を確認
$ sudo systemctl list-unit-files -t service | grep psacct

# redisを起動
$ sudo systemctl start redis.service

# redisの状態を確認
$ sudo systemctl status redis.service

# エラーログが出ていないことを確認
$ sudo cat /var/log/redis/redis.log

# 動作確認
$ redis-cli ping
PONG

$ redis-cli
127.0.0.1:6379> set hoge 123345
OK
127.0.0.1:6379> get hoge
"123345"
127.0.0.1:6379> keys *
1) "hoge"
127.0.0.1:6379> exit
```

### ・ redis.jsonの作成
redisがインストールされているサーバと、redisが使用するportをSensu側に設定します。

```bash:bash
$ echo '{
  "redis": {
    "host": "127.0.0.1",
    "port": 6379
  }
}' |sudo tee /etc/sensu/conf.d/redis.json
```
### ・ Sensuの再起動
Sensuの設定ファイルに追加、変更があった場合は、Sensuの再起動が必要になります。

```bash:bash
# 所有者/グループを変更
$ sudo chown sensu:sensu /etc/sensu/conf.d/redis.json

# sensu-client/sensu-server/sensu-apiを再起動
$ sudo systemctl restart sensu-client.service && sudo systemctl restart sensu-server.service && sudo systemctl restart sensu-api.service

# sensu-client/sensu-server/sensu-apiが動いていることを確認
$ sudo systemctl status sensu-client.service && sudo systemctl status sensu-server.service && sudo systemctl status sensu-api.service
```

## 10. RabbitMQのインストール

### ・ Erlangのインストール  
RabbitMQはErlangのランタイム上で実行されるため、まずはErlangをインストールします。

```bash:bash
# RabbitMQ用のErlangリポジトリを追加
$ echo '[rabbitmq_erlang]
name=rabbitmq_erlang
baseurl=https://packagecloud.io/rabbitmq/erlang/el/7/$basearch
repo_gpgcheck=1
gpgcheck=0
enabled=0
gpgkey=https://packagecloud.io/rabbitmq/erlang/gpgkey
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
metadata_expire=300' | sudo tee /etc/yum.repos.d/rabbitmq_erlang.repo

# Erlangのインストール
$ sudo yum install erlang --enablerepo=rabbitmq_erlang
```
### ・ RabbitMQのインストール

```bash:bash
# RabbitMqのリポジトリを追加
$ echo '[bintray-rabbitmq-server]
name=bintray-rabbitmq-rpm
baseurl=https://dl.bintray.com/rabbitmq/rpm/rabbitmq-server/v3.7.x/el/7/
gpgcheck=0
repo_gpgcheck=0
enabled=0' | sudo tee /etc/yum.repos.d/rabbitmq.repo

# インストールされるバージョンの確認
$ sudo yum info rabbitmq-server --enablerepo=bintray-rabbitmq-server

# rabbitmq-serverのインストール
$ sudo yum install rabbitmq-server --enablerepo=bintray-rabbitmq-server
```

### ・ RabbitMQの設定

```bash:bash
# 自動起動設定を有効化
$ sudo systemctl enable rabbitmq-server.service

# 自動起動設定を確認
$ systemctl list-unit-files -t service | grep rabbitmq-server.service

# rabbitmq-serverの起動
$ sudo systemctl start rabbitmq-server.service

# rabbitmq-serverの状態確認
$ sudo systemctl status rabbitmq-server.service

# Sensu専用のVirtual Hostを作成
$ sudo rabbitmqctl add_vhost /sensu

# Sensu用のRabbitMQユーザーを作成(左からユーザ名 パスワード)
$ sudo rabbitmqctl add_user sensu sensu

# 作成したvhostのユーザにキューに対する権限を付与(左から、設定変更権限、書き込み権限、読み込み権限)
# /sensuはvhost名、2つ目のsensuはユーザ名
$ sudo rabbitmqctl set_permissions -p /sensu sensu ".*" ".*" ".*"
```

### ・ transport.jsonの作成
Sensu ClientとSensu Server間の通信にrabbitmqを使用することをSensu側に設定します。

```bash:bash
$ echo '{
  "transport": {
    "name": "rabbitmq",
    "reconnect_on_error": true
  }
}' |sudo tee /etc/sensu/conf.d/transport.json
```
### ・ rabbitmq.jsonの作成
RabbitMQで使用する「ポート」、「Virtual Host」、「ユーザ情報」をSensu側に設定します。

```bash:bash
$ echo '{
  "rabbitmq": {
    "host": "127.0.0.1",
    "port": 5672,
    "vhost": "/sensu",
    "user": "sensu",
    "password": "sensu"
  }
}' |sudo tee /etc/sensu/conf.d/rabbitmq.json
```

### ・ Sensuの再起動
Sensuの設定ファイルに追加、変更があった場合は、Sensuの再起動が必要になります。

```bash:bash
# 所有者/グループを変更
$ sudo chown sensu:sensu /etc/sensu/conf.d/transport.json
$ sudo chown sensu:sensu /etc/sensu/conf.d/rabbitmq.json

# sensu-client/sensu-server/sensu-apiを再起動
$ sudo systemctl restart sensu-client.service && sudo systemctl restart sensu-server.service && sudo systemctl restart sensu-api.service

# sensu-client/sensu-server/sensu-apiが動いていることを確認
$ sudo systemctl status sensu-client.service && sudo systemctl status sensu-server.service && sudo systemctl status sensu-api.service
```

## 11. Grafanaのインストール
Grafanaをインストールしていきます。

```bash:bash
# Grafanaのリポジトリを追加
$ echo '[grafana]
name=grafana
baseurl=https://packagecloud.io/grafana/stable/el/7/$basearch
repo_gpgcheck=1
enabled=0
gpgcheck=1
gpgkey=https://packagecloud.io/gpg.key https://grafanarel.s3.amazonaws.com/RPM-GPG-KEY-grafana
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt' | sudo tee /etc/yum.repos.d/grafana.repo

# grafanaのインストール
$ sudo yum install grafana --enablerepo=grafana
```
### ・ Grafanaの設定
Grafanaで使用するポートを設定します。今回は、3001にしますが、自身で好きなポートを使用することができます。

```bash:bash
# 設定ファイルの編集し、http_port = 3001を追加
$ sudo vim /etc/grafana/grafana.ini
http_port = 3001
```

### ・ Grafanaの起動

```bash:bash
# 自動起動設定を有効化
$ sudo systemctl enable grafana-server.service

# 自動起動設定を確認
$ sudo systemctl list-unit-files -t service | grep grafana-server.service

# grafanaを起動
$ sudo systemctl start grafana-server.service

# 起動状況を確認
$ sudo systemctl status grafana-server.service
```

### ・ Pie Chartプラグインのインストール  
Grafanaのダッシュボードにデフォルトでないグラフは、pluginsとして追加することができます。例えば、Pie Chartを追加したい場合は、下記のようになります。他にもさまざまなプラグインが用意されていますので、興味のある方は[Grafana公式ページ](https://grafana.com/plugins)をご確認下さい。

```bash:bash
$ sudo grafana-cli plugins install grafana-piechart-panel
```

## 12. Graphiteのインストール
Graphiteはpipを使ってインストールしていきます。pipがインストールされていない方は、まず先にpipをインストールして下さい。
※pipとは、Pythonで作られたパッケージソフトウェアをインストール・管理するためのパッケージ管理ツールです。詳しくは[公式ページ](https://pip.pypa.io/en/latest/installing/)をご確認ください。

### ・ pipのインストール

```bash:bash
$ sudo su - root

# インストールスクリプトをダウンロード
[root]$ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py

# インストール
[root]$ python get-pip.py

# インストールスクリプトを削除
[root]$ rm get-pip.py

[root]$ exit
```

### ・ Graphiteのインストール

```bash:bash
# 環境変数の設定
$ export PYTHONPATH="/opt/graphite/lib/:/opt/graphite/webapp/"

# whisperのインストール
$ sudo pip install --no-binary=:all: https://github.com/graphite-project/whisper/tarball/master

# Carbonのインストール
$ sudo pip install --no-binary=:all: https://github.com/graphite-project/carbon/tarball/master

# graphite-webのインストール
$ sudo pip install --no-binary=:all: https://github.com/graphite-project/graphite-web/tarball/master
```

### ・ データベースのセットアップ  
Graphiteでは、ユーザープロファイル、ダッシュボード、およびイベント機能を格納するためにデータベースを使用します。今回はデフォルトのSQLiteを使用していきます。

```bash:bash
# データベースの作成
$ sudo PYTHONPATH=/opt/graphite/webapp django-admin.py migrate --settings=graphite.settings --run-syncdb

# sqliteに接続(動作確認)
$ sqlite3 /opt/graphite/storage/graphite.db

# 動作確認(table一覧を取得)
sqlite> select name from sqlite_master where type='table';

sqlite> .exit
```

### ・ graphite-web用のWebサーバ作成  
graphite-webのWebサーバはいくつか選択肢がありますが、今回は「nginx + gunicorn」で作成していきます。Amazon Linux2だとNginxはyumリポジトリに無いので、Extraリポジトリからインストールします。
なお、他に「Apache + mod_wsgi」や「nginx + uWSGI」の組み合わせもありますので、気になる方は[公式ページ](https://graphite.readthedocs.io/en/latest/config-webapp.html)をご確認ください。
### ・ nginxとGunicornのインストール

```bash:bash
# nginxのインストール
$ sudo amazon-linux-extras install nginx1.12

# gunicornのインストール
$ sudo pip install gunicorn

# graphite用のnginxログファイルを作成
$ sudo touch /var/log/nginx/graphite.access.log
$ sudo touch /var/log/nginx/graphite.error.log

$ sudo su - root

[root]$ chmod 640 /var/log/nginx/graphite.*

# 所有者/グループを変更
[root]$ chown nginx:nginx /var/log/nginx/graphite.*

[root]$ exit

# nginxにGraphite用のプロキシを追加
$ sudo vim /etc/nginx/nginx.conf
    server {
        listen       3002;
        server_name  localhost;
        root         /opt/graphite/webapp;

        access_log /var/log/nginx/graphite.access.log;
        error_log  /var/log/nginx/graphite.error.log;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location /static {
            alias /opt/graphite/webapp/content;
            expires max;
        }

        location / {
            try_files $uri @graphite;
        }

        location @graphite {
            proxy_pass_header Server;
            proxy_set_header Host $http_host;
            proxy_redirect off;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Scheme $scheme;
            proxy_connect_timeout 10;
            proxy_read_timeout 10;
            proxy_pass http://127.0.0.1:8080;
        }
    }
```

### ・ Webサーバの起動

```bash:bash
# 自動起動設定を有効化
$ sudo systemctl enable nginx.service

# 自動起動設定を確認
$ sudo systemctl list-unit-files -t service | grep nginx.service

# nginxの起動
$ sudo systemctl start nginx.service

# nginxが起動していることを確認
$ sudo systemctl status nginx.service

# Gunicornの起動
# 末尾の"&"はバックグラウンドで起動
# 起動後、port:3002でブラウザからアクセスするとgraphiteのページにアクセスできる
$ sudo PYTHONPATH=/opt/graphite/webapp gunicorn wsgi --workers=4 --bind=127.0.0.1:8080 --log-file=/var/log/gunicorn.log --preload --pythonpath=/opt/graphite/webapp/graphite &

# gunicornを停止したい場合
# $ sudo pkill gunicorn
```

### ・ graphite-webの設定

```bash:bash
# 設定ファイルをデフォルトの雛形からコピーして作成
$ sudo cp /opt/graphite/webapp/graphite/local_settings.py.example /opt/graphite/webapp/graphite/local_settings.py

# タイムゾーンの変更とDatabaseセクションのコメントアウト削除
$ sudo vim /opt/graphite/webapp/graphite/local_settings.py
#TIME_ZONE = 'America/Los_Angeles'
TIME_ZONE = 'Asia/Tokyo'

DATABASES = {
    'default': {
        'NAME': '/opt/graphite/storage/graphite.db',
        'ENGINE': 'django.db.backends.sqlite3',
        'USER': '',
        'PASSWORD': '',
        'HOST': '',
        'PORT': ''
    }
}
```

### ・ Carbonの設定

```bash:bash
# carbon.confをデフォルトの雛形からコピーして作成
$ sudo cp /opt/graphite/conf/carbon.conf.example /opt/graphite/conf/carbon.conf

# graphite.wsgiをデフォルトの雛形からコピーして作成
$ sudo cp /opt/graphite/conf/graphite.wsgi.example /opt/graphite/conf/graphite.wsgi

# storage-aggregation.confをデフォルトの雛形からコピーして作成
$ sudo cp /opt/graphite/conf/storage-aggregation.conf.example /opt/graphite/conf/storage-aggregation.conf

# storage-schemas.confをデフォルトの雛形からコピーして作成
$ sudo cp /opt/graphite/conf/storage-schemas.conf.example /opt/graphite/conf/storage-schemas.conf

# Carbonの起動
$ sudo /opt/graphite/bin/carbon-cache.py start
```
# 最後に
ここまで長かったですが、お疲れ様でした。これで一連の設定ができたと思います。
Sensuを使ってみて、監視サーバ側の設定変更やサービス再起動なしに監視対象サーバを追加できる点が特に便利だと感じました。今後、SensuやGrafanaを使う方のお役に立てばと思います。

明日もLIFULLアドベントカレンダーをよろしくお願いします！