fluentbitはコンパクトなログ加工・配信エージェントです。入力・出力のプラグインを切り替えることで多様な構成に対応できます。
k8sノードからコンテナログ収集する構成
fluentbitは多様なフォーマットに対応し、クラスタ内に複数のエージェントをセットアップする構成を想定しています。アプリケーションから直接取得するログはセマンティックな構造を極力保存し、構造を持たない単なる文字列は素朴なエントリとして加工・集約できます。
kubernetes標準のログは、コンテナのstdout
, stderr
に出力したメッセージがnodeのログファイルに記録されます。
このログは構造を持たず高度なフィルタなどを実装できませんが、シェルスクリプトのようなワークロードの場合には構造化する手段もないため現実的な実装方式と言えます。
DaemonSet
で各nodeにfluentbitを配備することで、クラスタ全体のログファイルを処理できます。
このほか、各コンテナのサイドカーとしてfluentbitをセットアップする構成も可能です。
サイドカーは単一podをデータソースとするため、json出力などを加工する用途に向いています。その場合、アプリケーションの仕様に合わせてfluentbitをセットアップすることとなり、kubernetesとはあまり関係のない構成になるため本記事の検討からは除外します。
fluentbitのconfig
公式dockerイメージは、/fluent-bit/etc/fluent-bit.conf
を参照しています。YAMLで記述する際は/fluent-bit/etc/fluent-bit.yaml
が同義です。configの拡張子でパース挙動が変わります。
2024年現在fluentbitのconfigフォーマットはYAMLに移行済で、TOML類似のクラシックフォーマットは2025年に終了するのですが、 YAMLの公式ドキュメント類は整備途上です。
kubernetesのログファイルを扱うサンプルは次のような記述で動作します。
service:
flush: 5
grace: 120
log_level: info
log_file: /dev/stderr
daemon: off
http_server: Off
pipeline:
inputs:
# NOTE: tektonネームスペースのログファイルを処理対象とする設定例
- name: tail
alias: kube_containers_tekton
tag: kube_<namespace_name>_<pod_name>_<container_name>
tag_regex: '(?<pod_name>[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)_(?<namespace_name>[^_]+)_(?<container_name>.+)-'
path: /var/log/containers/*_tekton_*.log
db: /var/lib/fluentbit-custom/kube_tekton.db
read_from_head: true
filters:
- name: parser
match: kube_*
key_name: log
reserve_data: true
parser: [cri]
- name: parser
match: kube_*
key_name: log
reserve_data: true
parser: [json]
outputs:
# TODO: 実用上はログストアに送信するプラグイン設定が必要
- name: stdout
match: '*'
parsers:
- name: cri
format: regex
regex: '^(?<time>[^ ]+) (?<stream>stdout|stderr) (?<logtag>[^ ]*) (?<log>.*)$'
time_key: time
time_format: "%Y-%m-%dT%H:%M:%S.%L%z"
- name: json
format: json
Podから参照するには、
Create a ConfigMap from a directoryの手順でConfigMapとして登録しておきます。
kubernetes向けのポイントは次のとおりです。
- ログファイルと作業DBはホストのファイルを参照している想定
inputs.[].path
とinputs.[].db
はホスト上の実ファイルをk8sのhostPath
でマウント
- kubernetesログの各ファイル名に、
<pod_name>_<namespace_name>_<container_name>
という文字列が含まれる規約を利用inputs.[].path
でネームスペースtekton
を指定して処理対象をフィルタしているinputs.[].tag_regex
でタグに設定する文字列の変数を抽出している
parsers
にCRI規約に沿ったパーサを定義parsers.[].regex
のマッチ結果はキーに追加される。この例では、time
,stream
,logtag
,log
というキーに値が入る
pipeline.filters
に加工プロセスを定義filters.[].parser
に複数のパーサを指定する方法は説明が存在しないが、配列を受けつける
service: { log_file: /dev/stderr }
を指定するとkubectl logs
でfluentdコンテナのログを参照できる
ログ加工時にコンテナ名称を参照する方法
既述のとおりコンテナ名称はログファイル名に含まれており、上の設定ではfluentbitのtagに抽出しました。tagはfilters.[].match
で複雑な処理分岐を制御するための変数です。
加工後のログでコンテナ名を参照したい場合には、tagと別にログレコードのキーに抽出しておく必要があります。関連するconfigパーツは次のようなものです。
pipeline:
inputs:
# NOTE: 既存のinputエントリにpath_keyオプション追加
- name: tail
# 指定したキーにログファイルのパスが入る
path_key: log_path
filters:
# NOTE: キー抽出処理を追加
- name: parser
match: kube_*
key_name: log_path
reserve_data: true
parser: pod_name
parsers:
# NOTE: キー抽出のためのパーサを追加
- name: pod_name
format: regex
# inputs.[].tag_regexと同じ処理
regex: '(?<pod_name>[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)_(?<namespace_name>[^_]+)_(?<container_name>.+)-'
これ以外にLuaで実装する方法もとれます。
ログレベルのフィルタ
ログ配信を整備する際、出力量の爆発によく直面します。
次のようなフィルタを追加するとログレベルに応じて配信をフィルタできます。
pipeline:
filters:
# remove low level logs from EventListener
- name: grep
match: kube_tekton_eventlistener-*
exclude: severity info|debug
ただし、この例のフィルタが機能するためには、severity
というキーにログレベルが入る必要があります。
特定のアプリケーションがjsonにログレベルを示す構造データを出力している場合には利用できます。シェルスクリプトなどのメッセージ出力にはログレベルがないため、この方法はとれません。
fluentbitコンテナマニフェスト
次のとおり、configとログファイルのセットアップがポイントです。
- configファイルはConfigMapから供給
- 起動時の
-c
オプションでconfigのパスを指定。fluentbitは拡張子でパース挙動がかわる - ホストのログを
hostPath
でマウントする
apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:
k8s-app: fluentbit-custom
name: fluentbit-custom
spec:
selector:
matchLabels:
k8s-app: fluentbit-custom
template:
metadata:
labels:
k8s-app: fluentbit-custom
spec:
containers:
- image: fluent/fluent-bit:3.2
name: fluentbit
args: ["-c", "/fluent-bit/etc/fluent-bit.yaml"]
volumeMounts:
- mountPath: /var/log
name: logdir
- mountPath: /var/lib/fluentbit-custom
name: workdir
- mountPath: /fluent-bit/etc/
name: configs
volumes:
- hostPath:
path: /var/log
type: Directory
name: logdir
- hostPath:
path: /var/lib/fluentbit-custom
type: DirectoryOrCreate
name: workdir
- configMap:
defaultMode: 420
# NOTE: 上のconfigを保持しているConfigMapを参照
name: fluentbit-config
name: configs
この例ではnodeのログファイル参照に絞っていますが、利用するプラグインによってはkubernetesクラスタへのアクセス権が必要なケースもあります。
GKE向けfluentbit構成のリポジトリには、ServiceAccountを指定するサンプルがあり参考になります。
Chuma Takahiro