web-dev-qa-db-ja.com

FilebeatおよびLogstashを使用したDockerアプリのロギング

複数のサーバーに散在するドッキングアプリケーションのセットがあり、ELKで実稼働レベルの集中​​ログを設定しようとしています。 ELK部分自体は問題ありませんが、ログをログスタッシュに転送する方法について少し混乱しています。ロードバランス機能のため、Filebeatを使用しようとしています。また、Filebeat(またはその他)をすべ​​てのDockerに詰め込むのを避け、分離、Docker化または非保存にしたいと思います。

どうすれば続行できますか?

私は次のことを試してきました。私のDockersはstdoutにログオンするので、標準化されていないFilebeatでstdinから読み取るように設定します:

docker logs -f mycontainer | ./filebeat -e -c filebeat.yml

最初はうまくいくようです。最初のログはlogstashに転送されます。私が推測するキャッシュされたもの。しかし、ある時点でスタックし、同じイベントを送信し続けます

それは単なるバグですか、それとも間違った方向に向かっていますか?どのソリューションをセットアップしましたか?

22
Gianluca

Dockerでは、使用中の logDriver を指定できます。この答えはFilebeatや負荷分散を気にしません。

プレゼンテーションでは、syslogを使用して、ポート5000でリッスンしているLogstash(ELK)インスタンスにログを転送しました。次のコマンドは、syslogを介してLogstashにメッセージを常に送信します。

docker run -t -d --log-driver=syslog --log-opt syslog-address=tcp://127.0.0.1:5000 ubuntu /bin/bash -c 'while true; do echo "Hello $(date)"; sleep 1; done'
9
michaelbahr

docker logsをELKスタックに転送する1つの方法を次に示します(gelfログドライバーの場合は、docker> = 1.8が必要です)。

  1. gelf input plugin でLogstashコンテナーを開始し、gelfから読み取り、Elasticsearch Host(ES_Host:port)に出力します。

    docker run --rm -p 12201:12201/udp logstash \
        logstash -e 'input { gelf { } } output { elasticsearch { hosts => ["ES_Host:PORT"] } }'
    
  2. Dockerコンテナーを起動し、 gelf Dockerロギングドライバー を使用します。馬鹿げた例です:

    docker run --log-driver=gelf --log-opt gelf-address=udp://localhost:12201 busybox \
        /bin/sh -c 'while true; do echo "Hello $(date)"; sleep 1; done'
    
  3. Kibanaをロードすると、docker logsに上陸したものが表示されます。 gelfソースコード は、いくつかの便利なフィールドが生成されることを示しています(ハットヒント: Christophe Labouisse ):_container_id_container_name_image_id_image_name_command_tag_created

Docker-composeを使用し(docker-compose> = 1.5を使用するようにしてください)、logstashコンテナーの起動後にdocker-compose.ymlに適切な設定を追加する場合:

log_driver: "gelf"
log_opt:
  gelf-address: "udp://localhost:12201"
19
Pete

Filebeatを使用すると、docker logs説明したとおりに出力します。表示されている動作は間違いなくバグのように聞こえますが、部分的な行の読み取り設定がヒットすることもあります(改行記号が見つかるまで部分的な行を再送信します)。

Logstashが利用できない場合、配管で見られる問題は背圧の可能性です。 filebeatがイベントを送信できない場合、イベントを内部でバッファリングし、ある時点で標準入力からの読み取りを停止します。どのように/ ifドッカーがstdoutが応答しなくなるのを防ぐのかわかりません。パイピングに関する別の問題は、docker-composeを使用している場合、filebeat + dockerの再起動動作です。 docker-composeはデフォルトで画像+画像状態を再利用します。そのため、再起動すると、すべての古いログが再度出荷されます(基になるログファイルがまだローテーションされていない場合)。

パイプする代わりに、Dockerによってホストシステムに書き込まれたログファイルを読み取ろうとすることができます。デフォルトのdockerログドライバーは json log driver です。 jsonログドライバーを設定して、ログローテーションを実行し、いくつかの古いファイルを保持します(ディスクにバッファリングするため)。 max-sizeおよびmax-fileオプションを参照してください。 jsonドライバーは、ログに記録されるすべての行に対して1行の「json」データを配置します。 Dockerホストシステムでは、ログファイルは/var/lib/docker/containers/container_id/container_id-json.logに書き込まれます。これらのファイルは、filebeatによってlogstashに転送されます。 logstashまたはネットワークが使用できなくなった場合、またはfilebeatが再起動された場合、ログ行の転送は続行されます(指定されたファイルはログローテーションにより削除されていません)。イベントは失われません。 logstashでは、json_linesコーデックまたはフィルターを使用してjson行を解析し、grokフィルターを使用してログからさらに情報を取得できます。

新しいログドライバーをdockerに追加するためにlibbeat(ログファイルを配布するためにfilebeatによって使用される)の使用について いくつかの議論 がありました。 docker logs apiを使用することで、将来的に dockerbeat を介してログを収集できる可能性があります(ただし、logs apiの利用に関する計画は知りません)。

Syslogの使用もオプションです。ドッカーホストの負荷分散ログイベントでsyslogリレーを取得できる場合があります。または、syslogにログファイルを書き込み、filebeatを使用して転送します。 rsyslogには少なくともいくつかのフェイルオーバーモードがあると思います。アクティブなlogstashインスタンスが使用できなくなった場合に備えて、logstash syslog入力プラグインとrsyslogを使用して、フェイルオーバーをサポートするlogstashにログを転送できます。

8
urso

Docker APIを使用して独自のdockerイメージを作成し、マシンで実行されているコンテナーのログを収集し、FilebeatのおかげでLogstashに発送しました。ホストに何かをインストールまたは構成する必要はありません。

それをチェックして、それがあなたのニーズに合っているかどうか教えてください: https://hub.docker.com/r/bargenson/filebeat/

コードはこちらから入手できます: https://github.com/bargenson/docker-filebeat

7
Brice Argenson

上記のコメントでerewokが書いたことを確認しました。

ドキュメントによると、prospectors.pathsで次のようなパターンを使用できるはずです:/var/lib/docker/containers/*/*.log – erewok 4月18日21:03

最初の「*」として表されるdocker container guidは、filebeatの起動時に正しく解決されます。コンテナが追加されるとどうなるかわかりません。

0
Arun Gupta

これを行う必要がある他の人を助けるためだけに、Filebeatを使用してログを送信できます。 @ brice-argensonでコンテナーを使用しますが、SSLサポートが必要なため、ローカルにインストールされたFilebeatインスタンスを使用しました。

Filebeatからのプロスペクターは次のとおりです(コンテナーの追加について繰り返します)。

- input_type: log
  paths:
    - /var/lib/docker/containers/<guid>/*.log
  document_type: docker_log
  fields:
    dockercontainer: container_name

更新時に変更される可能性があるため、GUIDを知る必要があるのは少し残念です。

Logstashサーバーで、logstashの通常のfilebeat入力ソースをセットアップし、次のようなフィルターを使用します。

filter {
  if [type] == "docker_log" {
    json {
      source => "message"
      add_field => [ "received_at", "%{@timestamp}" ]
      add_field => [ "received_from", "%{Host}" ]
    }
    mutate {
      rename => { "log" => "message" }
    }
    date {
      match => [ "time", "ISO8601" ]
    }
  }
}

これにより、DockerログからJSONが解析され、タイムスタンプがDockerによって報告されたものに設定されます。

Nginx Dockerイメージからログを読み取る場合、このフィルターも追加できます。

filter {
  if [fields][dockercontainer] == "nginx" {
    grok {
      match => { "message" => "(?m)%{IPORHOST:targethost} %{COMBINEDAPACHELOG}" }
    }
    mutate {
      convert => { "[bytes]" => "integer" }
      convert => { "[response]" => "integer" }
    }
    mutate {
      rename => { "bytes" => "http_streamlen" }
      rename => { "response" => "http_statuscode" }
    }
  }
}

変換/名前変更はオプションですが、これらの値を整数にキャストしないCOMBINEDAPACHELOG式の見落としを修正し、Kibanaでの集計に使用できないようにします。

0
Kenneth