[Elasticsearch][Logstash] Multiple Pipelinesを試す。

# 概要

https://www.elastic.co/blog/logstash-multiple-pipelines

この記事を見て試した内容です。
Logstash 6.0になると、Pipeline（複数）が定義できるようになるとのこと。それができると、何が便利になるのか、というところを見ていきます。
Qiitaを見てると、fluentdタグをつけられているのが多いですが、Logstashタグのは少ないので、１つ記事数を増やすためにこれを書きます。

試した環境は以下の通りです。

| product | version |
|:---------:|:---------:|
| Elasticsearch | 6.0.0-beta1 |
| Kibana        | 6.0.0-beta1 |
| Logstash      | 6.0.0-beta1 |



# 設定地獄 (Pipelineがないとき　551風に）

Pipelineがないとき、複数のinputやfilter、outputが存在するような設定はどのように実現していたでしょうか。

> ![](https://www.elastic.co/assets/bltaea598a83ff9d133/meh.png)
引用元： https://www.elastic.co/blog/logstash-multiple-pipelines

## １つの設定ファイルに全部書く

if文の分岐とか、間違えそうなポイントが多いです。可読性も良くないです。
後からここに何かを追加するときにバグを作り込みそうな空気です。


```yaml
    input {
      beats { port => 3444  tag => apache   }
      tcp { port => 4222  tag => firewall   }
    }
    filter {
       if "apache" in [tags] {  
        dissect { ... }
       } else if "firewall" in [tags] {  
        grok { ... }
       }  
    }
    output {
       if "apache" in [tags] {  
        elasticsearch { ... }
       } else if "firewall" in [tags] {  
        tcp { ... }
       }  
    }
```

## 5.xまででの解決策

冒頭にあげた例では、このようになっていました。

> TCP -> Grok -> TCP
> Beats -> Dissect -> ES

TCPのinputに対して、DissectやESは不要なのに、１つの設定ファイルで書こうとした結果、前述したような全部入りの設定ファイルになっていました。

これを5.xで解決しようとすると、ファイルを分けて、logstashのインスタンスを分けて実行する手立てがありました。

```shell-session
logstash -f aaa.config
logstash -f bbb.config
```

ただし、logstashごとにJavaのインスタンスが起動するし、メモリは食うし、あまり効率的ではないです。
そこで、Pipelineですよというわけですね。

# Pipeline

Pipelineは、input, filter, outputと処理の系統ごとに分けて記述できます。
最初の例でいうと、TCPから始まる処理のパイプラインとBeatsで始まる処理のパイプラインを分けて管理できるようになります。

参考にした記事の記載例が以下です。
apacheの処理用のパイプラインと、TCP待ち受け用のパイプラインと２つわけて定義されていることが分かります。

```pipelines.yml
- pipeline.id: apache
  pipeline.batch.size: 125
  queue.type: persisted
  path.config: "/path/to/config/apache.cfg"
  queue.page_capacity: 50mb
- pipeline.id: test
  pipeline.batch.size: 2
  pipeline.batch.delay: 1
  queue.type: memory
  config.string: "input { tcp { port => 3333 } } output { stdout {} }"
```

公式DockerイメージのLogstashだと、このpipeline.ymlは、以下にあります。

> /opt/logstash/config/pipelines.yml

各設定値の詳細は[Settings File](https://www.elastic.co/guide/en/logstash/master/logstash-settings-file.html)を参照いただくとして、ここでは、最低限動作確認に必要な大事なポイントだけ書いておきます。

| 項目 | 説明 |
|---|----|
| pipeline.id | **[必須]** 一意となる文字列を設定する |
| path.config | 個別のPipelineの設定ファイルのパス |
| config.string | 文字列としてPipelineの設定を渡すときに使う |

実際は、config.stringで書くとpipelines.ymlの可読性が悪くなると思うので、path.configしか使わない気がします。



## 実行

logstashの実行時に -e(config.stringの指定） や -f(path.configの指定) をつけなければ、pipelines.ymlが読まれて実行されます。

pipelines.ymlを書き換えているなら、logstashを引数無しで実行すれば良いです。
-rオプションを付与することで、pipelines.ymlを自動的にリロードしてくれます。

実行例としては、こうやりました。pipelines.ymlなど必要なファイルを渡して、logstashコマンドを叩いているだけです。

```shell-session
docker run --rm -it --name logstash \
 -v $(pwd)/pipelines.yml:/opt/logstash/config/pipelines.yml \
 -v $(pwd)/logstash.yml:/opt/logstash/config/logstash.yml \
 -v $(pwd)/sc.conf:/opt/logstash/pipeline/sc.conf \
 --link elasticsearch6b:elasticsearch \
 --network default \
 docker.elastic.co/logstash/logstash:6.0.0-beta1 logstash
```

logstash.ymlを渡しているのは、logstashからモニタリング用のElasticsearchサーバにデータを送るのですが、
この接続文字列が含まれているからです。

Pipelineができることで、こんなメリットがあると思います。

- Logstashの設定ファイルの簡素化！（分離できるところが一番大きいかな）
- 処理の系統ごとに細かな個別設定が可能（バッチサイズや、Queueの持ち方など）
- 可視化、モニタリングもある！


# [参考] Monitoring 

モニタリングを使用している場合は、Kibanaの画面よりLogstashの処理状況やPipelineの状況が見えます。
Pipelineとあわせてモニタリングを利用すると良い感じです。


## Monitoring画面

Kibanaの横にあるハート形のアイコンのようなものを押します。
Logstashのモニタリング情報が取得できていれば、Kibanaの下の枠に表示されます。

![Monitoring   docker cluster   Overview.png](https://qiita-image-store.s3.amazonaws.com/0/111676/282ed984-45fe-7e18-c2a7-206a428f1cd0.png)

## Nodeの状況

負荷状況が見えます。

![Node.png](https://qiita-image-store.s3.amazonaws.com/0/111676/51a86807-8601-f759-89dc-42eb98d905b1.png)

## Pipelineの状況

logstashの実行を行うと、Pipelineの内容が見えるようになります。

![Monitoring   docker cluster   Logstash Pipelines.png](https://qiita-image-store.s3.amazonaws.com/0/111676/b7b8f308-44f9-b403-9a8f-03a5c02237a5.png)

Version～となってるリンク部分をおすと、Pipelineの中身が確認できます。

![3.png](https://qiita-image-store.s3.amazonaws.com/0/111676/69c2003d-cbcc-a7ed-8549-00ee0a452172.png)


# 留意点

## 留意点1

path.configの値で、存在しないファイルを指定するなどした場合はINFOでメッセージが出ます。全然Pipelineが動いてないように見える場合は、確認すると良いです。

`No config files found in path {:path=>"*************************"}`

![20170829.png](https://qiita-image-store.s3.amazonaws.com/0/111676/1f84c7e7-12bb-b697-4683-438c01501555.png)

Pipelineが正常に起動すると、`Pipelines running` のあとに、起動されたPipelineのカウントが出ます。
モニタリング用のPipelineが１つあるので、ここで表示された値から１引いた数が、期待するPipelineの数ならOKです。

## 留意点2

モニタリングに関するところなのでMultiple Pipelineとは直接関係ありません。

```logstash.yml
xpack.monitoring.elasticsearch.url: http://elasticsearch:9200
xpack.monitoring.elasticsearch.username: HogeHoge
xpack.monitoring.elasticsearch.password: BarBar
```

例えば、`"xpack.security.enabled=false"`などと設定していて、認証がない状態でやっている場合は、
username、passwordの設定値は空にしてください。設定項目を削除してはいけません。

- 良い例

  ``` logstash.yml
xpack.monitoring.elasticsearch.url: http://elasticsearch:9200
xpack.monitoring.elasticsearch.username: 
xpack.monitoring.elasticsearch.password: 
  ```
- 悪い例　(コメントアウトしてしまう)

  ``` logstash.yml
xpack.monitoring.elasticsearch.url: http://elasticsearch:9200
# xpack.monitoring.elasticsearch.username: 
# xpack.monitoring.elasticsearch.password: 
  ```
  悪い例の場合は、以下のようなエラーがログに出力されます。

```
[2017-08-29T06:07:24,928][ERROR][logstash.pipeline        ] Pipeline aborted due to error {:pipeline_id=>".monitoring-logstash", :exception=>#<ArgumentError: You must set the password using the xpack.monitoring.elasticsearch.password in logstash.yml>, :backtrace=>["/usr/share/logstash/vendor/bundle/jruby/2.3.0/gems/x-pack-6.0.0.beta1-java/lib/license_checker/license_reader.rb:29:in `initialize'", "/usr/share/logstash/vendor/bundle/jruby/2.3.0/gems/x-pack-6.0.0.beta1-java/lib/license_checker/licensed.rb:86:in `license_reader'", "/usr/share/logstash/vendor/bundle/jruby/2.3.0/gems/x-pack-6.0.0.beta1-java/lib/license_checker/licensed.rb:48:in `setup_license_checker'", "/usr/share/logstash/vendor/bundle/jruby/2.3.0/gems/x-pack-6.0.0.beta1-java/lib/monitoring/inputs/metrics.rb:63:in `register'", "/usr/share/logstash/logstash-core/lib/logstash/pipeline.rb:376:in `register_plugin'", "/usr/share/logstash/logstash-core/lib/logstash/pipeline.rb:387:in `block in register_plugins'", "org/jruby/RubyArray.java:1734:in `each'", "/usr/share/logstash/logstash-core/lib/logstash/pipeline.rb:387:in `register_plugins'", "/usr/share/logstash/logstash-core/lib/logstash/pipeline.rb:551:in `start_inputs'", "/usr/share/logstash/logstash-core/lib/logstash/pipeline.rb:433:in `start_workers'", "/usr/share/logstash/logstash-core/lib/logstash/pipeline.rb:321:in `run'", "/usr/share/logstash/logstash-core/lib/logstash/pipeline.rb:281:in `block in start'"], :thread=>"#<Thread:0x64c80450@/usr/share/logstash/logstash-core/lib/logstash/pipeline.rb:278 run>"}
```

**You must set the password using the xpack.monitoring.elasticsearch.password in logstash.yml**　と出ています。


# 参考

今回使用したESとKibanaの起動はこちらを`docker-compose up -d`で行いました。

```yaml
version: '2'
services:
  elasticsearch6b:
    image: docker.elastic.co/elasticsearch/elasticsearch:6.0.0-beta1
    container_name: elasticsearch6b
    ports:
      - 9200:9200
      - 9300:9300
    environment:
      - "xpack.security.enabled=false"
  kibana6b:
    image: docker.elastic.co/kibana/kibana:6.0.0-beta1
    container_name: kibana6b
    ports:
      - 5601:5601
    depends_on:
      - elasticsearch6b
    links:
      - elasticsearch6b:elasticsearch
    environment:
      - "xpack.security.enabled=false"
```