GPU サーバのログを ELK サーバに送信して管理する

# はじめに
　GPU サーバのログを別の ELK (Elasticsearch + Logstash + Kibana) サーバで管理したい人向けのものです．

## 注意
　サーバの基本的なセットアップは済んでるものとして話を進めます．

## 導入環境
　まずは筆者の環境を載せておきます．

- GPU サーバ(1台の例)
  - Ubuntu 16.04 LTS
  - Geforce GTX 1080
  - Geforce Driver Version: 396.26
- ELK サーバ
  - Ubuntu 16.04 LTS
  - Elasticsearch 2.4.6
  - Kibana 4.5.4

　他のディストリビューションを使ってる場合や Kibana のバージョンが異なる場合は，コマンドなど適当に読み替えてください．

## 全体像
　今回、Logstash の input 形式に HTTP POST を選択しました．HTTP POST の利点として、 curl でログを送れるため，他のパッケージをインストールしなくよく、設定ファイル等もいじらなくていい点があります．
　（今回多数の GPU サーバのログを収集したかったため，GPU サーバ側の手順を簡略化したかったという理由もあります．）

# ELK サーバ側の設定
　まず GPU のログを受け取る ELK サーバの設定から始めていきます． root 権限が必要になりますので、 root 権限を持ったユーザーでログインすることを勧めます．

## Logstash
　Logstash の設定ファイルを[公式サイト](https://www.elastic.co/blog/introducing-logstash-input-http-plugin)を参考に編集していきます．
　Logstash の設定は input, filter, output の段階で設定します．今回は service として起動するためファイルを分けていますが，1つの設定ファイルにまとめても構いません．

### 注意
- すでに Logstash で他のログを収集している場合は追記するかファイル名を変えてください．
- テキストエディタとして vim を使いますが、好きなテキストエディタで編集してください．
- __Logstash と Elasticsearch の待ち受けポートに 5141番と 9200番を指定していますが、既に使用してる場合は適当なポートを指定してください．__


```console
$ cd /etc/logstash/conf.d/
$ sudo vim ./01-inputs.txt
```

```conf:01-inputs.conf
# http input from gpu server on port 5141
input {
  http {
    port => 5141
    type => "gpu"
  }
}
```

```console
$ sudo vim ./10-gpu-filter.conf
```

```conf:10-gpu-filter.conf
filter {
  if ［type］ == "gpu" {
    grok {
      match => ["message", "(?<name>[^,]*),(?<Date>[^,]*),(?<gpu_util>[^,]*),(?<memory_util>[^,]*),(?<memory_total>[^,]*),(?<memory_free>[^,]*),(?<memory_used>[^,]*),(?<temperature>[^,]*)"]
    }
    date{
      match => ["Date" , "yyyy/MM/dd HH:mm:ss.SSS"]
      timezone => "Asia/Tokyo"
    }
    mutate{
      convert => {
        gpu_util => float
        memory_util => float
        memory_total => float
        memory_free => float
        memory_used => float
        temperature => float
      }
      remove_field => ["headers"]
    }
  }
}
```

```console
$ sudo vim ./30-outputs.conf
```

```conf:30-outputs.conf
output {
    if [type] == "gpu" {
    elasticsearch {
        hosts =>  ["localhost:9200"]
        index => "logstash-gpu-%{+YYYY.MM.dd}"
    }
}
```

## port 開放
　Logstash の待ち受けポートに設定した 5141 番ポートを開けます．__ディストリビューション毎に方法が違いますので注意してください．__
　ファイアウォールを有効化してない場合は読み飛ばして構いません．

```console
$ sudo ufw allow 5141
```

# GPU サーバ側の設定
次にログを送る側の GPU サーバーの設定をします．

## nvidia-smi でログをみる
　nvidia 社のグラフィックボードに対応するドライバーを入れ、 [nvidia-smi](https://developer.nvidia.com/nvidia-system-management-interface) を実行するとグラフィックボードの状態が分かります．正常に動作することを確かめるため、 nvidia-smi を実行してください．
　筆者の環境では，下のように表示されます．

```console
$ nvidia-smi
Sat Jun 23 16:24:39 2018
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 396.26                 Driver Version: 396.26                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 1080    Off  | 00000000:01:00.0 Off |                  N/A |
|  0%   35C    P0    35W / 180W |      0MiB /  8119MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+
```

もし，正常に表示されない場合，下のように表示されることがあります．

```console
Failed to initialize NVML: Driver/library version mismatch
```

その場合は，再起動やドライバーの再インストール等を試してください．(筆者も再起動後に表示できたサーバがありました)

## シェルスクリプトを書く
　nvidia-smi のクエリを用いて上記の中から必要なログを出力させます．出力形式には csv を指定し、，curl で ELK サーバに POST します．
　__ELK サーバの IP アドレスと GPU マシン名には自身の環境に合わせます．__

```console
$ cd ~
$ sudo vim ./sendlog.sh
```

```shell:sendlog.sh
#!/bin/bash
nvidia-smi --query-gpu=timestamp,utilization.gpu,utilization.memory,memory.total,memory.free,memory.used,temperature.gpu --format=csv,noheader,nounits | (read log ; curl -XPUT ${ELK サーバの IP }:5141 -d "${GPU サーバの名前},${log}" > /dev/null 2>&1)
```

実行権限を与えます

```console
$ sudo chmod +x ./sendlog.sh
```

### curl を入れてない場合
```console
$ sudo apt install curl
```

## 定期的にログを送る
　cron を用いて先程のスクリプトを1分間隔で定期実行させます．
　cron を有効化してない場合は有効化させます．

```console
$ crontab -e
```

最終行に以下の1行を追記してください

```config
* * * * * bash /home/${ユーザー名}/sendlog.sh
```

# 終わりに
　以上で作業は完了です．
　Kibana でうまく log を受け取れていることが確認できれば成功です．グラフとダッシュボードを作成して可視化しましょう．