zaki work log

作業ログやら生活ログやらなんやら

[Kubernetes] Fluent Bitを使ってリモートのSyslogサーバーへPodのログを集約する

Fluent Bitを使ってKubernetesのPodのログをSyslogサーバー(rsyslog)へ転送してみた。

Fluent Bitとは

高いパフォーマンスと低リソースでの動作を考慮して設計されC言語で実装された、ログのコレクター・アグリゲータ。
ライセンスはApache License v2.0で、CNCFではgraduatedのプロジェクト。

docs.fluentbit.io

Fluentdとの違いは以下

docs.fluentbit.io

KubernetesへのFluent Bitインストール

Kubernetesへのインストール自体はHelmチャートが用意されている。

docs.fluentbit.io

リポジトリを追加し、

helm repo add fluent https://fluent.github.io/helm-charts

インストールするのが基本。

helm upgrade --install fluent-bit fluent/fluent-bit -n logging --create-namespace

なお、デフォルト設定では以下の構成でデプロイされる。

  • DaemonSetでデプロイ
  • ノードOS上に生成されるpodのログの保存先をhostPathでボリュームマウント
  • 上記のpodのログをTail inputプラグインで取得
  • 取得したログをKubernetesフィルタメタデータ含めてオブジェクト化
  • "elasticsearch-master"でアクセスできるElasticsearchサーバーへ転送

本記事では、レガシーなシステムも含んだ構成であれば割とありがちのような気がする、リモートのSyslogサーバーへの転送についてのまとめ。

Syslog転送設定

やることは、デフォルトではElasticsearch outputプラグインが指定されている箇所を、Syslog outputプラグインを使うように置き換える。
Syslog outputプラグインは以下。

docs.fluentbit.io

kubernetesフィルタ使用時のデータ構造

ドキュメントのどこかに載ってるかもしれないけどよくわからなかったのでfilestdoutで確認。サンプルとしてApache HTTP ServerのログであればJSON形式に整形すると以下の通り。
Apacheのログ自体はlogキー以下にある。Pod名、コンテナ名、イメージ名、ネームスペース名などのKubernetesの情報はkubernetesキー以下で確認できる。

[
    1680840043.426684408,
    {
        "time": "2023-04-07T04:00:43.426684408Z",
        "stream": "stdout",
        "_p": "F",
        "log": "192.168.0.131 - - [07/Apr/2023:04:00:43 +0000] \"GET / HTTP/1.1\" 200 45",
        "kubernetes": {
            "pod_name": "sample-http-6bf6795c4-shn9t",
            "namespace_name": "sample-web",
            "pod_id": "136e2e0b-0a71-4a0c-9a18-13f335c03e83",
            "labels": {
                "app": "sample-http",
                "pod-template-hash": "6bf6795c4"
            },
            "annotations": {
                "cni.projectcalico.org/containerID": "8f6ece5e3158043f9b9243b8a8a7979662151f1c4c603e7f087fabc7105d76a5",
                "cni.projectcalico.org/podIP": "10.244.56.6/32",
                "cni.projectcalico.org/podIPs": "10.244.56.6/32"
            },
            "host": "k8su-worker02",
            "container_name": "httpd",
            "docker_id": "94b43c48d5f2861fbaf4ade9a8e3263fa50579a066dc275b6e066b5856d7eb24",
            "container_hash": "docker.io/library/httpd@sha256:83e99e7c437898cb564bbd3ceba7f1ea3f2d86e1cbd7a5324940086e59082f2b",
            "container_image": "docker.io/library/httpd:latest"
        }
    }
]

Syslog outputプラグイン設定

結論から言うと以下の内容で最低限「Pod内のアプリケーションのログ」を基本的な設定のSyslogサーバーへ転送できる。

キー 設定内容
name syslog
match kube.*
host Syslogサーバーのアドレス
port Syslogサーバーのポート(default:514)
mode プロトコル(default:udp)
syslog_message_key log

設定例は以下。

  outputs: |
   [OUTPUT]
       name               syslog
       match              kube.*
       host               192.168.0.16
       syslog_message_key log

ホスト名やアプリ名などを指定

ログの構造データのkubernetesキーの配下にあるhostcontainer_nameをSyslogのホスト名やアプリ名に指定したい場合、kubernetes.hostなどのように指定しても残念ながら認識しない。(少なくともSyslog outputプラグインはネストを解釈しないっぽい)
どうすれば良いかと言うと、まさにネストを処理するnest filterプラグインがあり、operation liftの指定でフラットな構造に展開できる。

[FILTER]
    name nest
    match kube.*
    operation lift
    nest_under kubernetes
    add_prefix kubernetes_

これでkubernetesキー配下の辞書になっていたPodのメタデータkubernetes_hostkubernetes_container_nameで参照できるようになる。

configfiltersおよびoutputs全体は以下のような感じ。

  filters: |
    [FILTER]
        Name kubernetes
        Match kube.*
        Merge_Log On
        Keep_Log Off
        K8S-Logging.Parser On
        K8S-Logging.Exclude On
    [FILTER]
        name       nest
        match      kube.*
        operation  lift
        nest_under kubernetes
        add_prefix kubernetes_

  outputs: |
   [OUTPUT]
       name syslog
       match kube.*
       host  192.168.0.16
       syslog_message_key  log
       syslog_hostname_key kubernetes_namespace_name
       syslog_appname_key  kubernetes_pod_name
       syslog_procid_key   kubernetes_container_name

Appendix

Syslogサーバー側設定

以下参照 (若干古い)

zaki-hmkc.hatenablog.com

ログ構造の確認

hostportmodeなどはSyslogサーバーの設定に合わせれば良いが、key関連はFluent Bitが取り込んだログデータの構造がわからないと指定のしようがない。
ということで、Syslog転送設定の前にまずはデータ形式を確認してみた。

手っ取り早く、Standard Outputプラグインを使用。

  outputs: |
    [OUTPUT]
        Name stdout
        Match kube.*

確認できるPodのログは例えばApache HTTP ServerのPodであればこんな感じ。

[0] kube.var.log.containers.sample-http-6bf6795c4-dcn9s_sample-web_httpd-c02fe813a7bfdc5206951a53c87f59e85df124cbc47bf97edfd2edcfb00c8b3e.log: [1680839704.357093483, {"time"=>"2023-04-07T03:55:04.357093483Z", "stream"=>"stdout", "_p"=>"F", "log"=>"192.168.0.131 - - [07/Apr/2023:03:55:04 +0000] "GET / HTTP/1.1" 200 45", "kubernetes"=>{"pod_name"=>"sample-http-6bf6795c4-dcn9s", "namespace_name"=>"sample-web", "pod_id"=>"15d48c8a-36b2-4faf-b5fc-f0550b7aa923", "labels"=>{"app"=>"sample-http", "pod-template-hash"=>"6bf6795c4"}, "annotations"=>{"cni.projectcalico.org/containerID"=>"80881d377d4b50307d972991fcb7ec2a7e9cb3419bd5547b640f6a7c5f74a1af", "cni.projectcalico.org/podIP"=>"10.244.165.70/32", "cni.projectcalico.org/podIPs"=>"10.244.165.70/32"}, "host"=>"k8su-worker01", "container_name"=>"httpd", "docker_id"=>"c02fe813a7bfdc5206951a53c87f59e85df124cbc47bf97edfd2edcfb00c8b3e", "container_hash"=>"docker.io/library/httpd@sha256:83e99e7c437898cb564bbd3ceba7f1ea3f2d86e1cbd7a5324940086e59082f2b", "container_image"=>"docker.io/library/httpd:latest"}}]

Fluent Bit自体のログは以下

[2023/04/07 03:54:34] [ info] [input:tail:tail.0] inotify_fs_add(): inode=541802 watch_fd=9 name=/var/log/containers/fluent-bit-clj5h_logging_fluent-bit-1f073e12bfef2f617e7a973953eaac518b4564253f550eb3735b8b101251bf2f.log

ホスト上のファイルシステムにアクセスできるなら、/var/log/pods/*/*/*.logにあるはずのログファイルを直接見れば良い。

root@k8su-master:~# ls -F /var/log/pods/*/*/*.log
/var/log/pods/calico-system_calico-kube-controllers-6b7b9c649d-6h9l7_34ddcac2-7f99-46fb-9824-e09915c6b6e2/calico-kube-controllers/0.log
/var/log/pods/calico-system_calico-kube-controllers-6b7b9c649d-6h9l7_34ddcac2-7f99-46fb-9824-e09915c6b6e2/calico-kube-controllers/1.log
/var/log/pods/calico-system_calico-node-x2zzv_47bd0f4f-7b6f-4007-966a-213bb9e95b8e/calico-node/0.log
/var/log/pods/calico-system_calico-node-x2zzv_47bd0f4f-7b6f-4007-966a-213bb9e95b8e/flexvol-driver/0.log
/var/log/pods/calico-system_calico-node-x2zzv_47bd0f4f-7b6f-4007-966a-213bb9e95b8e/install-cni/0.log
/var/log/pods/calico-system_calico-typha-78cf4b6dfb-k9pp7_af899e10-6897-42ad-ae11-1f6ad80de873/calico-typha/0.log
/var/log/pods/calico-system_csi-node-driver-d84sz_870ea5e3-9885-4f68-aa7a-3f4fa6b26ddd/calico-csi/0.log
/var/log/pods/calico-system_csi-node-driver-d84sz_870ea5e3-9885-4f68-aa7a-3f4fa6b26ddd/csi-node-driver-registrar/0.log
/var/log/pods/kube-system_coredns-787d4945fb-7jbpp_53643398-8d8f-4514-8aa3-5fa169f4e802/coredns/0.log
/var/log/pods/kube-system_coredns-787d4945fb-w56qw_8fd2147a-7abc-4855-863e-5f250b1cc843/coredns/0.log
/var/log/pods/kube-system_etcd-k8su-master_699fd81b5c8ec8c4dbc4338395262e53/etcd/0.log
/var/log/pods/kube-system_kube-apiserver-k8su-master_de088f05e01138ec1dbc93cd4c84e2f2/kube-apiserver/0.log
/var/log/pods/kube-system_kube-controller-manager-k8su-master_c41031e429b4a5f760fcbc35a86855b3/kube-controller-manager/14.log
/var/log/pods/kube-system_kube-controller-manager-k8su-master_c41031e429b4a5f760fcbc35a86855b3/kube-controller-manager/15.log
/var/log/pods/kube-system_kube-proxy-v8brj_8c1fa81b-af68-4bfd-bca3-18d55ee44f15/kube-proxy/0.log
/var/log/pods/kube-system_kube-scheduler-k8su-master_258e9658795a8f3c8547485c6cfc7d9c/kube-scheduler/14.log
/var/log/pods/kube-system_kube-scheduler-k8su-master_258e9658795a8f3c8547485c6cfc7d9c/kube-scheduler/15.log
/var/log/pods/tigera-operator_tigera-operator-54b47459dd-kmxhr_4c57047a-7302-4170-bcc5-5a1e2f9df382/tigera-operator/12.log
/var/log/pods/tigera-operator_tigera-operator-54b47459dd-kmxhr_4c57047a-7302-4170-bcc5-5a1e2f9df382/tigera-operator/13.log

除外条件

例えばFluent Bit自体のログを除外するために、Fluent Bitをデプロイするネームスペースを処理対象外とするなら以下のようにgrepフィルタを指定する。

    [FILTER]
        Name     grep
        Match    *
        Exclude  $kubernetes['namespace_name'] logging

stdoutを使う場合は、Fluent Bitを含む各podが出力するログをFluent Bitが収集しFluent Bitのpodのログとしても出力するため、この除外設定が無いとFluent Bitのログが大量に出力されるので注意。

環境

  • Kubernetes: v1.26.1 (kubeadmで構築)
  • Fluent Bit Helmチャート: 0.24.0
  • Fluent Bit: 2.0.9
  • rsyslog: 8.2204.0-2.fc35 (Fedora 35)