Shohhei1126's Blog

KubernetesのLoggingを考えてみた

ログ収集エージェントをDaemonSetでKubernetesの全nodeに配置してログを収集する、というのはクラスタレベルロギングと呼ばれていてよく目にする。アプリケーションが標準出力、標準エラーにログを吐くとコンテナがよしなにnodeのファイルシステムに書き込んでくれる。

Cluster-level logging architectures

FluentdとElasticsearch

GCP以外の場合はFluentdとElasticsearch(多分)一択で細かい設定は fluent/fluentd-kubernetes-daemonset が参考になる。ポイントは

  • fluent-plugin-elasticsearchfluent-plugin-kubernetes_metadata_filter を追加 (参考)
  • sourceのpathに /var/log/containers/*.log を指定して kubernetes.* タグをつける (参考)
  • filterで kubernetes_metadata を指定する(参考)

あたりかなと。kubernetes_metadata_filter でkubernetesのメタ情報を追加してElasticsearchにログを送れる。kibanaでみるとこんな感じ。

elasticsearch_dynamicで動的にindexを変える

ただこの設定だと /var/log/containers/*.log にすべてのコンテナのログを一つのindex(正確には日付で別れるけど)ぶち込むことになる。

色々調べてみると elasticsearch_dynamic というのがあったので使ってみた。

<match kubernetes.**>
  type copy
  <store>
    @type elasticsearch_dynamic
    host "#{ENV['ELASTICSEARCH_HOST']}"
    port "#{ENV['ELASTICSEARCH_PORT']}"
    flush_interval "#{ENV['FLUSH_INTERVAL_ES']}"
    logstash_format true
    logstash_prefix ${record['kubernetes']['namespace_name']}-${record['kubernetes']['container_name']}
  </store>
</match>

$record という変数でkubernetesのメタ情報を参照できたので {NAMESPACE}-{CONTAINER NAME} というようにindexを分けることができた。

でも本番でelasticsearch_dynamicは使えなさそう

ただしDynamic configurationに書かれているが Rubyのevalを使っているためパフォーマンスとセキュリティリスク が高い。

今回はnamespaceとcontainer名しか使っていないので悪意のあるコードが混入されるとは考えにくいがアクセスログなど滝のように流れるログに使うのは難しいかもしれない(ベンチ取ってないけど)。

アクセスログは別で収集するとか、開発環境だけで使うとかであればよさそう。

雑感

Elasticsearchにログが入ればPrometheusと組み合わせてログ監視とか面白そうだなーと思いを馳せつつ。ネストしたJSONでもkeyとして認識してくれるのでマイクロサービス間でログレベルと時刻のkey名を統一してそれを監視するExporter作るとかできそう(もしかしたらもうあるかもしれんけど)。

アクセスログは最近流行っている Service Mesh でも取れるし、モニタリングもMeshとかぶるところ多いからうまい具合に使い分けしたい。