Elasticsearch+Kibanaでサーバメトリクスの可視化をする

Elasticsearch+Kibanaでサーバメトリクスの可視化をする

October 10, 2018
Middleware
docker, elasticsearch, kibana, dstat, fluentd

はじめに

サーバの運用監視といえばMackerelだったり、DataDogなりのSaasを使って綺麗に可視化したいものです。 が、仕事だと外部サービス使わせてもらえないので、ElasticsearchとKibanaを使ってオンプレでも可視化する方法を調べました。 Elasticsearch+Kibana+Fluentd+dstatは既に色々記事があるのですが、古めの記事が多く、そのままやってもうまく動かなかったため、2018/10時点で動作した方法をまとめます。

完成イメージとしてはこんな感じです

環境

  • サーバ
    • AWSインスタンス×2 (監視サーバと監視対象)
      • Amazon Linux 2 AMI
      • t2.medium
  • 各サービスのバージョン
    • Docker - 18.06.1-ce
    • docker-compose - 1.22.0
    • Fluentd - v1.0 (td-agent3)
    • Elasticsearch - 6.4.1
    • Kibana - 6.4.1

監視サーバの構築

まず監視サーバの構築を行います

Docker, docker-composeインストール

ElasticsearchとKibanaはdocker-composeで動かすためDockerを入れます

// インストール
$ sudo yum install docker-ce
// デーモン起動
$ sudo service docker start
// 一般ユーザーでも使えるようにdockerグループに所属させる
$ sudo usermod -a -G docker ec2-user
// 一度ログアウトしてから再度ログインすれば反映される
$ sudo service docker restart
$ exit

// 確認
$ docker version
Client:
 Version:           18.06.1-ce
 API version:       1.38
 Go version:        go1.10.3
 Git commit:        e68fc7a215d7133c34aa18e3b72b4a21fd0c6136
 Built:             Wed Sep  5 18:57:40 2018
 OS/Arch:           linux/amd64
 Experimental:      false

Server:
 Engine:
  Version:          18.06.1-ce
  API version:      1.38 (minimum version 1.12)
  Go version:       go1.10.3
  Git commit:       e68fc7a/18.06.1-ce
  Built:            Wed Sep  5 18:59:05 2018
  OS/Arch:          linux/amd64
  Experimental:     false

// docker-composeのインストール
// https://github.com/docker/compose/blob/master/CHANGELOG.md 最新を確認してインストール
$ sudo curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
// 確認
$ docker-compose version
docker-compose version 1.22.0, build f46880fe
docker-py version: 3.4.1
CPython version: 3.6.6
OpenSSL version: OpenSSL 1.1.0f  25 May 2017

Elasticsearch+Kibanaのインストール

適当なディレクトリを作って、docker-compose.ymlとesdataというフォルダを掘ります


$ tree
.
|-- docker-compose.yml
`-- esdata

// また事前にElasticsearch用に以下を設定しておく
// メモリマップの上限値を上げておく
$ sudo sysctl -w vm.max_map_count=262144
// ulimitの上限あげ 
$ sudo su  
## ulimit -n 65536
## exit
version: '3.7'
services:
  elasticsearch:
    ## https://hub.docker.com/_/elasticsearch/
    image: docker.elastic.co/elasticsearch/elasticsearch:6.4.1
    volumes:
      - ./esdata:/usr/share/elasticsearch/data
    environment:
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      nofile:
        soft: 65536
        hard: 65536
    ports:
      - 9200:9200
      - 9300:9300
    networks:
      - esnet

  kibana:
    ## https://hub.docker.com/_/kibana/
    image: docker.elastic.co/kibana/kibana:6.4.1
    ports:
      - 5601:5601
    environment:
      ELASTICSEARCH_URL: "http://elasticsearch:9200"
    links:
      - elasticsearch
    networks:
      - esnet

networks:
  esnet:
$ ls
docker-compose.yml  esdata
$ docker-compose up -d
$ docker-compose ps
            Name                           Command               State                       Ports
-----------------------------------------------------------------------------------------------------------------------
elastickibana_elasticsearch_1   /usr/local/bin/docker-entr ...   Up      0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp
elastickibana_kibana_1          /usr/local/bin/kibana-docker     Up      0.0.0.0:5601->5601/tcp
確認
$ curl <監視サーバのホスト名>:9200
{
  "name" : "oTmpxcX",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "f0L7EvzcTZeJA9OPsSVCUg",
  "version" : {
    "number" : "6.4.1",
    "build_flavor" : "default",
    "build_type" : "tar",
    "build_hash" : "e36acdb",
    "build_date" : "2018-09-13T22:18:07.696808Z",
    "build_snapshot" : false,
    "lucene_version" : "7.4.0",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}

Kibana確認 ブラウザでhttp://<監視サーバのホスト名>:5601へアクセス 画像 こんな感じの画面が見れれば一旦おk


監視サーバでの作業は一旦ここまでになります. 次に監視対象サーバでメトリクスの出力とfluentdの設定を行います。

監視対象サーバの構築

監視対象サーバではdstatを使ってサーバメトリクスを取得し、それをfluentdでElasticsearchに送ります

dstatの準備


$ sudo yum install dstat

$ dstat -cdlnmpr 3
----total-cpu-usage---- -dsk/total- ---load-avg--- -net/total- ------memory-usage----- ---procs--- --io/total-
usr sys idl wai hiq siq| read  writ| 1m   5m  15m | recv  send| used  buff  cach  free|run blk new| read  writ
  6   1  93   0   0   0|  99k 1460k|   0 0.05 0.17|   0     0 |1417M 2088k 1382M 1145M|  0   0  10|5.82  18.6
  0   0 100   0   0   0|   0     0 |   0 0.05 0.17|1657B 2323B|1417M 2088k 1382M 1145M|  0   0   0|   0     0
  1   0  99   0   0   0|   0   181k|   0 0.05 0.17|2236B 3058B|1418M 2088k 1382M 1143M|  0   0 0.7|   0  38.7

3秒ごとにCPU, ディスク, ロードアベレージ, ネットワーク, メモリ, プロセス, IOのメトリクスを出すオプションにしています。 オプションはdstat -hで確認して必要な情報あればそれを出すようにしましょう

fluentdインストール

サービスとしてはtd-agentという名前です

公式ページを参考に

$ curl -L https://toolbelt.treasuredata.com/sh/install-amazon2-td-agent3.sh | sh

// td-agent, td-agent-gemコマンドが使えるようになり, サービスも登録される
$ sudo systemctl status td-agent
● td-agent.service - td-agent: Fluentd based data collector for Treasure Data
   Loaded: loaded (/usr/lib/systemd/system/td-agent.service; disabled; vendor preset: disabled)
   Active: inactive (dead)
     Docs: https://docs.treasuredata.com/articles/td-agent
プラグインのインストール

次のプラグインをインストールする

プラグイン名説明
fluent-plugin-dstatdstatをfluentdのsourceにできる
fluent-plugin-elasticsearchfluendからelasticsearchにデータを送れる
fluent-plugin-filter_typecast型変換を行う(※後述)
fluent-plugin-filter-object-flattenネストしたデータ構造を展開して、処理しやすくするのに使う
// td-agent-gemコマンドでインストールする
$ sudo td-agent-gem install fluent-plugin-dstat fluent-plugin-elasticsearch fluent-plugin-filter_typecast fluent-plugin-filter-object-flatten
設定確認

とりあえずdstatをfluentdで取り込んで、標準出力に出して確認してみましょう

<source>
  @type dstat
  tag dstat
  option -cnm
  delay 3
</source>

<match dstat>
  @type stdout
</match>
$ td-agent -c fluent.conf
...
2018-10-09 15:40:05.237184928 +0000 dstat: {"hostname":"ip-172-31-26-80.ap-northeast-1.compute.internal","dstat":{"total_cpu_usage":{"usr":"0.203","sys":"0.120","idl":"99.644","wai":"0.031","hiq":"0.0","siq":"0.001"},"net/total":{"recv":"0.0","send":"0.0"},"memory_usage":{"used":"199806976.0","buff":"2138112.0","cach":"463761408.0","free":"3471278080.0"}}}
2018-10-09 15:40:05.237376395 +0000 dstat: {"hostname":"ip-172-31-26-80.ap-northeast-1.compute.internal","dstat":{"total_cpu_usage":{"usr":"0.0","sys":"0.166","idl":"99.834","wai":"0.0","hiq":"0.0","siq":"0.0"},"net/total":{"recv":"126.667","send":"105.333"},"memory_usage":{"used":"198103040.0","buff":"2138112.0","cach":"463761408.0","free":"3472982016.0"}}}

出力を見ると問題が2つあります。1つはデータの型がすべて文字列になっていることです。fluentdでは基本的に値は文字列で出すらしい。 Elasticsearch+Kibanaに突っ込んで可視化する際, 時系列グラフにできるのはNumericな型のみなので、型変換が必要

また、キーに/などの処理しづらい文字が入っていたり、ネストされており、このままじゃ扱いづらいので、これらもflatten_mapで処理しやすくする

<source>
  @type dstat
  tag dstat
  option -cnm
  delay 3
</source>

<filter **>
  @type object_flatten
  tr [" /", "__"]
</filter>

<filter **>
  @type typecast
  types dstat.total_cpu_usage.usr:float,dstat.total_cpu_usage.sys:float,dstat.total_cpu_usage.idl:float,dstat.total_cpu_usage.wai:float,dstat.total_cpu_usage.hiq:float,dstat.total_cpu_usage.siq:float,dstat.net_total.recv:float,dstat.net_total.send:float,dstat.memory_usage.used:float,dstat.memory_usage.buff:float,dstat.memory_usage.cach:float,dstat.memory_usage.free:float
</filter>

<match dstat>
  @type stdout
</match>
2018-10-09 16:00:03.369963227 +0000 dstat: {"hostname":"ip-172-31-26-80.ap-northeast-1.compute.internal"}
2018-10-09 16:00:03.369963227 +0000 dstat: {"dstat.total_cpu_usage.usr":0.209}
2018-10-09 16:00:03.369963227 +0000 dstat: {"dstat.total_cpu_usage.sys":0.107}
2018-10-09 16:00:03.369963227 +0000 dstat: {"dstat.total_cpu_usage.idl":99.657}
2018-10-09 16:00:03.369963227 +0000 dstat: {"dstat.total_cpu_usage.wai":0.027}
2018-10-09 16:00:03.369963227 +0000 dstat: {"dstat.total_cpu_usage.hiq":0.0}
2018-10-09 16:00:03.369963227 +0000 dstat: {"dstat.total_cpu_usage.siq":0.001}
2018-10-09 16:00:03.369963227 +0000 dstat: {"dstat.net_total.recv":0.0}
2018-10-09 16:00:03.369963227 +0000 dstat: {"dstat.net_total.send":0.0}
2018-10-09 16:00:03.369963227 +0000 dstat: {"dstat.memory_usage.used":200888320.0}
2018-10-09 16:00:03.369963227 +0000 dstat: {"dstat.memory_usage.buff":2138112.0}
2018-10-09 16:00:03.369963227 +0000 dstat: {"dstat.memory_usage.cach":464175104.0}
2018-10-09 16:00:03.369963227 +0000 dstat: {"dstat.memory_usage.free":3469783040.0}

ちゃんと型変換されて、ネストも解消されている.

Elasticsearchへ送る

fluent.confを編集して、Elasticsearchへ送るようにする

- <match dstat>
-   @type stdout
- </match>
+ <match dstat>
+    @type elasticsearch
+    host <監視サーバのホスト名>
+    port 9200
+    index_name dstat
+    logstash_format true
+    logstash_prefix dstat
+    type_name dstat
+    flush_interval 5
+ </match>

これで起動して問題なければ、デーモン化にしておきましょう

$ cd /etc/td-agent
// バックアップ
$  mv td-agent.conf td-agent.conf.bak
// ↑で作ったfluent.confを持ってくる
$ sudo mv ~/fluent/fluent.conf td-agent.conf 
// サービス起動
$ sudo systemctl start td-agent
$ $ sudo systemctl status td-agent
● td-agent.service - td-agent: Fluentd based data collector for Treasure Data
   Loaded: loaded (/usr/lib/systemd/system/td-agent.service; disabled; vendor preset: disabled)
   Active: active (running) since Tue 2018-10-09 16:11:27 UTC; 37s ago

Kibanaの設定

最後にKibanaで可視化をしていきます。 上のfluentdでうまく送れていたら、新たなインデックスができているはずです.

インデックスパターンの作成

まずはインデックスパターンを作成します

http://<監視サーバのホスト名>:5601/app/kibana#/management/kibana/index?_g=()

にアクセスしてみましょう

下のようにdstat-YYYY.MM.DDの候補があればおkです。 画像 上のようになっていれば

  1. Index patternにdstat-*を入れて、Next Step
  2. Time Filter field nameに@timestampを選択してCreate Index Patternをします

ヴィジュアライズ作成

それでは基本的な時系列グラフをつくってみます。 例としてネットワークのrecv,sendを時系列グラフにしてみます. 下へアクセスします http://<監視サーバのホスト名>:5601/app/kibana#/visualize?_g=()

  1. Create a visualizationをクリックし
  2. Areaを選択します
  3. dstat-*を選択すると、グラフ画面が表示されます.

画像

次にグラフの設定をしてきましょう

  1. まずはX軸を設定しますBucketsのX-Axisを選択しAggregationでDate Histogramを選択します(Field, Intervalはデフォでいいです)
  2. Y-Axis Count 左の三角ボタンを押して、AggregationでAverage, Fieldをdstat.net_total.recvに変更します
  3. さらにAdd metricsボタンを押して、Y-Axis, AggregationでAverage, Fieldをdstat.net_total.sendで追加します

この状態で上の青い再生ボタン(Apply Changesボタン)を押すと下のような画面になるはずです 画像

おkであれば上のSaveタブで保存しておきましょう 画像

こんな感じで、いろいろグラフが作れます. Visualizeをいろいろ作って、Dashboard画面でまとめて見ることも可能です(冒頭のスクショのような

参考