Dockerコンテナ環境でFluentdを使ってGrafana Lokiにログを送信してみた

AvatarPosted by

この記事は GRIPHONE Advent Calendar 2019 14日目の記事です。

こんにちは、SREの川野です。今回はGrafana LokiをDockerコンテナを使って試してみたので、ご紹介します!

Grafana Lokiについて

Lokiは、Prometheusにインスパイアされた、水平方向にスケーラブルで可用性の高いマルチテナントログ集約システムです。
https://github.com/grafana/loki

Prometheusがメトリックを対象としていることに対して、Lokiはログを対象にしています。また、ログの配信方法がPrometheusがプル型なのに対し、Lokiではプッシュ型です。Datadogのように監視対象のサーバーにエージェントをインストールすることでそのエージェントからログが配信されるようになります。

Lokiのロギングスタックは以下の3つのコンポーネントで構成されています。

  1. ログを収集してLokiに送信するエージェント
  2. ログの保存とクエリの処理を行うメインサーバー
  3. ログの照会、表示を行う監視ツール

今回の環境構成について

今回はDockerを使って環境を構築します。テスト用のログとして、Nginxコンテナを作成しアクセスログを使用したいと思います。

ロギングスタックの構成は以下の形になります。

  1. Fluentd : ログを収集してLokiに送信するエージェント
  2. Loki : ログの保存とクエリの処理を行うメインサーバー
  3. Grafana : ログの照会、表示を行う監視ツール

↓今回作成する環境
https://github.com/Takashi-Kawano/fluentd-out-loki-sample

環境構築

これから作成する設定ファイルの全体のディレクトリ構成は以下のようになっています。

$ tree .
.
├── docker-compose.yaml
├── fluent.conf
├── host_logs
└── plugin
    └── out_loki.rb

2 directories, 3 files

では、作成の手順について説明していきます。

手順1. 以下のdocker-compose.ymlを作成します。
loki, grafana, fluentd, nginxの4つのコンテナを作成するための設定をします。

version: "3"
networks:
  loki:
services:

  loki:
    image: grafana/loki:v1.2.0
    ports:
      - "3100:3100"
    command: -config.file=/etc/loki/local-config.yaml
    networks:
      - loki

  grafana:
    image: grafana/grafana:6.5.2
    ports:
      - "3000:3000"
    networks:
      - loki

  fluentd:
    image: fluentd:v1.6.2-1.0
    environment:
      FLUENT_CONF: /fluentd/etc/fluent.conf
    networks:
      - loki
    volumes:
      - ./host_logs:/var/log
      - ./fluent.conf:/fluentd/etc/fluent.conf
      - ./plugin:/etc/fluent/plugin

  nginx:
    image: nginx:1.17.6
    volumes:
      - ./host_logs:/var/log/nginx
    ports:
      - "8080:80"

手順2. ログを送信するためのFluentdの設定ファイルfluent.confを作成します。

  • matchディレクティブ
    Lokiプラグインを使用してendpoint_urlhttp://loki:3100を指定しています。FluentdコンテナからLokiサーバーへはDockerのlokiネットワークを介して接続できることに注意です。また、ここでGrafanaで見るとき用のラベリングを行います。
  • parseディレクティブ
    Nginxプラグインを使ってNginxログをパースするようにしています。
<source>
  @type tail
  path /var/log/*.log
  tag nginx.test
  <parse>
    @type nginx
    expression /^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)"(?:\s+(?<http_x_forwarded_for>[^ ]+))?)?$/
    time_format %d/%b/%Y:%H:%M:%S %z
  </parse>
</source>

<match **>
  @type loki
  endpoint_url http://loki:3100
  labels {"env":"prod","farm":"a"}
</match>

手順3. plugin ディレクトリを作成して、その配下にLokiプラグインとしてout_loki.rbを作成します。
Lokiプラグインの実装は以下をご確認ください。
https://github.com/Takashi-Kawano/fluentd-out-loki-sample/blob/master/plugin/out_loki.rb

手順4. Nginxログをコンテナ上にマウントするためにhost_logsというディレクトリを作成します。
こちらのディレクトリは、docker-compose.ymlを見ていただくとわかるかと思うのですが、Nginxコンテナの/var/log/nginxをホストのhost_logsにマウントしています。また、host_logsをFluentdコンテナにもマウントしているので、Fluentdコンテナ上でNginxアクセスログをFluentdのエージェントが収集して、Lokiコンテナへ送信することができます。

手順5. 各設定ファイルが準備できましたら、コンテナを起動します。

$ docker-compose up -d 

4つのコンテナが起動できていることを確認します。

$ docker ps
CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS              PORTS                            NAMES
4934b5481895        grafana/loki:v1.2.0     "/usr/bin/loki -conf…"   28 seconds ago      Up 23 seconds       80/tcp, 0.0.0.0:3100->3100/tcp   loki_loki_1
c9969a515fd1        fluentd:v1.6.2-1.0      "tini -- /bin/entryp…"   28 seconds ago      Up 26 seconds       5140/tcp, 24224/tcp              loki_fluentd_1
90562c989133        grafana/grafana:6.5.2   "/run.sh"                28 seconds ago      Up 26 seconds       0.0.0.0:3000->3000/tcp           loki_grafana_1
195bc71c1d05        nginx:1.17.6            "nginx -g 'daemon of…"   28 seconds ago      Up 23 seconds       0.0.0.0:8080->80/tcp             loki_nginx_1

手順6. ログを送信するためにNginxに適当にリクエストを投げておきます。

$ while true; do curl -I http://localhost:8080; sleep 1; done > /dev/null 2>&amp;1

つづいて、Lokiコンテナへ保存されているNginxログをGrafanaを使って確認してみます。

手順7. ブラウザでhttp://localhost:3000にアクセスし、ログインします。(初回は、ユーザー名とパスワードはそれぞれadminです)

スクリーンショット 2019-12-10 13.21.28.png

手順8. ログインしたら、トップページに表示されている「Add data source」を押下し、表示されるリストから「Loki」を選択します。

スクリーンショット 2019-12-10 10.42.52.png

手順9. HTTP URLにhttp://loki:3100を入力します。コンテナ間のネットワークはlokiで名前解決しているので、ドメイン名は、localhostではなくlokiとなります。他のフォームは空欄のままで下の緑の「Save & Test」ボタンを押下します。

スクリーンショット 2019-12-10 13.22.33.png

手順10. 以下のようなエラーが出る場合がございますが、データソースは作成されているので、気にせず左のサイドバーの「Explore」を押下します。

Data source connected, but no labels received. Verify that Loki and Promtail is configured properly.

手順11.「Log lables」をクリックするとfluent.confで設定したenvラベルとfarmラベルが表示されていることがわかります。

スクリーンショット 2019-12-10 14.24.18.png

手順12. envのprodを選択してみると、ログを確認することができます。

スクリーンショット 2019-12-10 14.25.42.png

Nginxプラグインを使ったパースも反映されていることを確認できます。

スクリーンショット 2019-12-10 14.26.43.png

終わりに

如何でしたでしょうか。
ログ収集するエージェントとしてはFluentdの他にpromtailやFluentBitなどを使用できます。はじめにFluentBitをチャレンジしましたが、中々上手くいきませんでした。今回のも終わってみれば簡単そうに見えるのですが、やっているときは試行錯誤が多く結構難しく感じました。あとDockerの勉強にもなりました。

個人的な次ステップとしては、以下のように考えています。

  • promtailをKubernetesクラスタにインストールさせてログを送信
  • Prometheusとサービスディスカバリと連携

最後まで読んでいただき、ありがとうございました。