cAdvisor, InfluxDB, GrafanaでDockerコンテナのリソース監視

# はじめに

1台のDockerホスト上のコンテナのリソース監視はcAdvisorが一般的になっているような気がします。
それでは複数台のDockerホスト上のコンテナのリソース監視はどうするのかなと調べてみると、以下のような方法があるようです。

- cAdvisorで直接InfluxDBに保存し、Grafanaで可視化
- HeapsterでcAdvisorから情報を収集してInfluxDBに保存し、Grafanaで可視化
- cAdvisorからfluentでInfluxDBに保存し、Grafanaで可視化

この記事では一つ目の方法を試してみようと思います。
とりあえず今出てきた登場人物の簡単な紹介とリンク紹介を。

なお、この記事はだいたい3月中旬に書いた内容です。

## cAdvisor

- Dockerコンテナのリソースモニタリングツール
- Kuberenetesで使うために主にGoogle社が開発したオープンソースソフトウェア
- cAdvisor自体もDockerコンテナとして動かすのが標準だが、Go言語で実装されており依存ライブラリの必要なく単体でもインストール可能。
- 公式サイト
 - [google/cadvisor](https://github.com/google/cadvisor)
- 解説記事
 - [cAdvisorとInfluxDBとGrafanaでDockerリソースの可視化を行うDockerコンテナ群をFigでデプロイしたPaaS上にてGo言語でRedisを叩く](http://nttpc.now.tl/ac2014/?p=132)

## InfluxDB

- 時系列データベース。
- 現在のStableバージョンは0.8.8
 - 0.9が3月末にリリース予定（が、今見たら4月リリースに書き換わっていた）
 - 根本からの全体的な改善であり、大きな機能追加はない。
- 特徴
 - HTTP APIでアクセス可能
 - databaseとseriesの2階層（seriesはRDBのテーブルに相当）
 - スキーマレス
 - SQLライクなクエリ言語
 - 時系列での集計関数が豊富
 - 分散ストレージ
 - 豊富なクライアントライブラリ
 - 管理Web UI
- 公式サイト
 - [InfluxDB - Open Source Time Series, Metrics, and Analytics Database](http://influxdb.com/)
- 解説記事
 - [InfluxDB の概要 - sonots #tokyoinfluxdb](http://www.slideshare.net/sonots/influxdb-study-20140627)
 - [InfluxDBきほんのき - Qiita](http://qiita.com/iyunoriue/items/1fcbc7c7fb9e6912816c)
 - [InfluxDBとGrafanaとfluentdで、twitterデータのリアルタイム集計・可視化 - Qiita](http://qiita.com/ixixi/items/a56ea15b582c7f014a57)
 - [便利な時系列データベースのInfluxDBと、その可視化ツールGrafanaについて - geniee’s tech blog](http://tech.geniee.co.jp/entry/2014/12/18/173000)

## Grafana

- Kibanaをベースに作られたダッシュボードツール。
- 特に時系列データのグラフ表示にフォーカスしている。
- Graphite、InfluxDB、OpenTSDBに対応。
- InfluxDB以外で使う場合は、ダッシュボードデータの保存のためにElasticsearchが必要。
- 公式サイト
 - [Grafana Documentation](http://docs.grafana.org/)
- 解説記事
 - [Grafana on InfluxDB をちょっとだけ触ってみた - Qiita](http://qiita.com/sonots/items/8fbc92ff1c3e57ee7de7)

## Heapster

- Kubernetesクラスタ内のコンテナのリソースモニタリングツール。
- Kubernetesのモニタリングツールとして作られたが、CoreOSでも動作、対象ホストを設定すればクラスタリングツールなしでも動作する。
- cAdvisorを各サーバーに入れ、Heapsterが各cAdvisorからデータを取得し、InfluxDBに保存、Grafanaで可視化する。という仕組み
- メリット
 - Kubernetesクラスタ内の全てのminionを自動で発見
 - pod ID、コンテナ名、pod IP、ホスト名、ラベルを統計情報と一緒に保存
 - クラスタリングツールを使わない場合、あまりメリットがない。
- 公式サイト
 - [GoogleCloudPlatform/heapster](https://github.com/GoogleCloudPlatform/heapster)
- 解説記事
 - [Monitoring Kubernetes - Hatena Developer Blog](http://developer.hatenastaff.com/entry/monitoring-kubernetes)
 - [Installing cAdvisor and Heapster on bare metal Kubernetes - Das Blinken Lichten](http://www.dasblinkenlichten.com/installing-cadvisor-and-heapster-on-bare-metal-kubernetes/)

# 環境構築手順

では、表題の「cAdvisor、InfluxDB、GrafanaでDockerコンテナのリソース監視」をする環境を構築していきましょう。

[cAdvisorとInfluxDBとGrafanaでDockerリソースの可視化を行うDockerコンテナ群をFigでデプロイしたPaaS上にてGo言語でRedisを叩く](http://nttpc.now.tl/ac2014/?p=132)の手順を参考に、Figは使わずに複数サーバーに対して構築していきます。（でも、今見るとページが開かなくなっている。。。）

以下のような構成を作っていきます。

![image](https://qiita-image-store.s3.amazonaws.com/0/27267/57f139da-bd99-264e-0d52-7b0a03a0e956.png)


## CentOS 7のインスタンスを作成

[CentOS 7 (x86_64) with Updates HVM on AWS Marketplace](https://aws.amazon.com/marketplace/pp/B00O7WM7QW)を３つ作成。

1. influxDB, Grafana
2. Dockerホスト、cAdvisor（2台）

としましょう。
全部同じセキュリティーグループにしておきます。（別にしなくてもいいです。）

SSHログインはcentosユーザです。

```bash
$ ssh -i <SSHキー> centos@<IPアドレス>
```

全サーバーのパッケージを最新にし、wgetをインストールしておきます。

```
$ sudo yum -y update
$ sudo yum -y install wget
```

## influxDB、Grafanaサーバーのセットアップ

### InfluxDBインストール

[InfluxDB Documentation](http://influxdb.com/docs/v0.7/introduction/installation.html)の通りインストールします。

```bash
$ wget http://s3.amazonaws.com/influxdb/influxdb-latest-1.x86_64.rpm
$ sudo rpm -ivh influxdb-latest-1.x86_64.rpm
```

InfluxDBを起動し、OS起動時に起動するように設定。

```bash
$ sudo service influxdb start
$ sudo chkconfig influxdb on
```

セキュリティグループで8083と8086を開けます。

管理Web UIにアクセスして動くことを確認します。

`http://<IPアドレス>:8083/` にアクセスすると以下の画面が表示されます。

![スクリーンショット 2015-03-12 16.15.45.png](https://qiita-image-store.s3.amazonaws.com/0/27267/b0895fb4-0355-a5ed-4242-ecd96a197dc5.png)

ユーザ、パスワードに`root/root`を入力し、ホスト名はサーバーのIPアドレス、ポートに`8086`を入力し、「Connect」を押します。

![スクリーンショット 2015-03-12 16.16.02.png](https://qiita-image-store.s3.amazonaws.com/0/27267/02b2c229-e189-310f-a6e0-de476e2c6aa7.png)

サンプルデータベースを作ってみます。Database Nameに`test`と入力し、「Create Database」をクリックします。
後でGrafanaの設定情報を入れる`grafana`データベースとcAdvisorのデータを入れる`cadvisor`データベースも作成しておいてください。

![スクリーンショット 2015-03-12 16.29.26.png](https://qiita-image-store.s3.amazonaws.com/0/27267/05554ddf-f5a3-64f5-d184-d35ca91974c7.png)

WebUIからもデータを入れられるのですが、一件ずつしか入れられないので、REST APIでデータを入れてみます。

```bash
$ curl -X POST 'http://localhost:8086/db/test/series?u=root&p=root' -d \
'[{"name": "nikkei_average", "columns": ["time", "price"], "points": [[1419778800000, 17729.84], [1419519600000, 17818.96], [1418083200000, 17450.77]]}]'
```

`test`データベースの「Explore Data »」からデータベースのRead/Writeをする画面に行き、`select * from nikkei_average`というQueryを実行すると以下のようにデータを見ることができます。

![スクリーンショット 2015-03-12 16.38.42.png](https://qiita-image-store.s3.amazonaws.com/0/27267/10d6eda1-b613-247e-ade7-31c62ff6a1d0.png)


### Grafanaインストール

[Install & Configure - Grafana Documentation](http://docs.grafana.org/installation/)を参考にインストール。

```bash
$ wget http://grafanarel.s3.amazonaws.com/grafana-1.9.1.tar.gz
$ tar zxvf grafana-1.9.1.tar.gz
$ sudo mv grafana-1.9.1 /opt/
$ cd /opt/grafana-1.9.1
$ cp config.sample.js config.js
```

influxdbの設定サンプルを参考に`config.js`を以下のように設定します。
とりあえず先ほど作成した`test`データベースに接続してみます。
`cadvisor`は後でcAdvisorが収集したデータを入れるデータベースです。まだありませんが、先に設定しておきます。
`grafana`データベースはGrafanaのダッシュボードの設定情報を保存するデータベースです。
`<IPアドレス>`にはこのサーバーのIPアドレスを指定します。

```
      datasources: {
        test: {
          type: 'influxdb',
          url: "http://<IPアドレス>:8086/db/test",
          username: 'root',
          password: 'root',
        },
        cadvisor: {
          type: 'influxdb',
          url: "http://<IPアドレス>:8086/db/cadvisor",
          username: 'root',
          password: 'root',
        },
        grafana: {
          type: 'influxdb',
          url: "http://<IPアドレス>:8086/db/grafana",
          username: 'root',
          password: 'root',
          grafanaDB: true
        },
      },
```

Webサーバーが入っていないので、Apacheをインストールします。

```
$ sudo yum -y install httpd
$ sudo vim /etc/httpd/conf.d/grafana.conf
```

`grafana.conf`は以下のように設定しました。

```
alias /grafana /opt/grafana-1.9.1
<Directory /opt/grafana-1.9.1>
  Require all granted
</Directory>
```

Webサーバープロセスからのアクセス許可設定。

```
$ sudo restorecon -R /opt/grafana-1.9.1/
```

セキュリティーグループで80も開けます。
Apacheを起動します。自動起動も設定します。

```
$ sudo systemctl start httpd
$ sudo systemctl enable httpd.service
```

`http://<IPアドレス>/grafana/`にアクセスすると以下のように表示されます。

![スクリーンショット 2015-03-12 17.35.10.png](https://qiita-image-store.s3.amazonaws.com/0/27267/19e59fbe-0710-62e8-1a38-af7caf0f9b4b.png)

グラフをEditし、日付範囲を2014/12/01-2014/12/31にして、条件を以下のように設定すると以下のようにInfluxDBのデータを見ることができます。

![スクリーンショット 2015-03-12 18.17.13.png](https://qiita-image-store.s3.amazonaws.com/0/27267/06d12784-0d45-2dec-bb7d-2db7ccffd32d.png)


## Dockerホストサーバーをセットアップ（2台）

監視対象の2台のサーバーです。DockerとcAdvisorを入れます。

Dockerをインストール

```bash
$ sudo yum install -y docker
$ sudo systemctl start docker
$ sudo systemctl enable docker
```

cAdvisorをDockerコンテナとして起動。

```bash
$ sudo docker run \
  --volume=/var/run:/var/run:rw \
  --volume=/sys:/sys:ro \
  --volume=/var/lib/docker/:/var/lib/docker:ro \
  --publish=8080:8080 \
  --detach=true \
  --privileged\
  --name=cadvisor_with_influxdb \
  google/cadvisor:latest \
  --log_dir=/ \
  --storage_driver=influxdb \
  --storage_driver_host=<InfluxDBサーバーのIP>:8086\
  --storage_driver_user=root \
  --storage_driver_password=root \
  --storage_driver_secure=False
```

cAdvisorの動作確認。`http://<cAdvisorサーバーのIP>:8080`にアクセス。2台とも確認。

![スクリーンショット 2015-03-13 9.10.14.png](https://qiita-image-store.s3.amazonaws.com/0/27267/58ae7ecb-7b38-2501-1399-2a5c50339fd0.png)

適当にDockerコンテナを立ち上げる。

```bash
$ sudo docker run --name redis -d redis
$ sudo docker run --name nginx -d -p 50080:80 dockerfile/nginx
```

## InfluxDBで確認

InfluxDBのダッシュボードでInfluxDBに入っていることを確認します。

`list series`でseries名を確認します。

![スクリーンショット 2015-03-13 9.40.07.png](https://qiita-image-store.s3.amazonaws.com/0/27267/462fa62e-94ce-5432-ff11-d2df78807ce3.png)

`stats`というseriesがあることがわかったので、`select * from stats limit 10`と中身を確認します。

![スクリーンショット 2015-03-13 10.00.08.png](https://qiita-image-store.s3.amazonaws.com/0/27267/bc415424-5b51-3cb2-56c9-faab115618d6.png)

![スクリーンショット 2015-03-13 10.00.32.png](https://qiita-image-store.s3.amazonaws.com/0/27267/27ebcb59-b8cb-e051-f774-ed1fb3dacf32.png)

stats seriesに入っているデータは以下のカラムで構成されています。

|カラム|説明|
|:----|:------|
|time|UNIX時間（ミリ秒）|
|sequence_number|シーケンス番号（InfluxDBによる自動採番）|
|machine|マシンID（/etc/machine-id, /var/lib/dbus/machine-id 起動時に設定も可能）|
|container_name|コンテナ名|
|memory_working_set|ワーキングセットメモリサイズ（バイト）|
|memory_usage|メモリ使用量（バイト）|
|cpu_cumulative_usage|累計CPU使用時間（ナノ秒）|
|fs_device|デバイス名|
|fs_usage|ディスク使用量（バイト）|
|fs_limit|ディスクサイズ（バイト）|
|rx_bytes|ネットワークの受信バイト数|
|rx_errors|ネットワークの受信エラー数|
|tx_bytes|ネットワークの送信バイト数|
|tx_errors|ネットワークの送信エラー数|


参考

- https://github.com/google/cadvisor/blob/master/info/v1/container.go
- https://github.com/google/cadvisor/blob/master/storage/influxdb/influxdb.go

## Grafanaで確認

ちょこちょこと設定するとこんな風に表示できます。
HeapsterのGrafanaのダッシュボード設定のサンプル（[heapster/grafana/kubernetes-dashboard.json](https://github.com/GoogleCloudPlatform/heapster/blob/f538b5da6ae7bf8b730879f1102c4d4549c9492d/grafana/kubernetes-dashboard.json)）を真似ると楽です。

![スクリーンショット 2015-03-19 22.49.13.png](https://qiita-image-store.s3.amazonaws.com/0/27267/8a4c426e-cf57-267c-64a8-92dad3749c60.png)

なかなかきれいに表示できました。

左上のグラフは以下の設定です。`cadvisor_with_influxdb`というコンテナのCPU使用率を表しています。
`derivative`関数は単位時間あたりの値の変化量つまり変化率を求めます。

```sql
select container_name, derivative(cpu_cumulative_usage) from "stats" where $timeFilter and machine = 'c563336a339b' and container_name = 'cadvisor_with_influxdb' group by time($interval) order asc
```

右上のグラフは以下の設定です。`cadvisor_with_influxdb`というコンテナのメモリ使用量を表しています。

```sql
select mean(memory_usage) from "stats" where $timeFilter and machine = 'c563336a339b' and container_name = 'cadvisor_with_influxdb' group by time($interval) order asc
```

```sql
select mean(memory_working_set) from "stats" where $timeFilter and machine = 'c563336a339b' and container_name = 'cadvisor_with_influxdb' group by time($interval) order asc
```

下の2つのグラフのように全コンテナのグラフを一度に表示する場合は、where句から`container_name`の条件を外し、group byでcontainer_nameを指定します。


# 終わりに

cAdvisor, InfluxDB, Grafanaを使うと簡単に複数台のDockerホスト上のコンテナの監視ができました。
ただ、cAdvisor APIで取れる全てのデータが入るわけではないとか、メタデータ的なものを追加できないとかちょっとデフォルトじゃ不満足な場合はfluentで入れるのがいいのかなあと思います。こんなfluentプラグイン（[Woorank/fluent-plugin-cadvisor](https://github.com/Woorank/fluent-plugin-cadvisor)）もあるようですし。