コンテンツにスキップ

Kubernetes における StdOut ログのホワイトリスト運用のベストプラクティス


環境準備

Kubernetes 環境(以下 K8s)がすでに存在することを前提とします。本実践は、セルフホストの Kubernetes v1.23.1、Guance Datakit バージョン 1.2.13、Nginx 1.17 に基づいています。

Datakit はすでにデプロイ済みであり、Datakit の設定ファイル container.conf は ConfigMap 経由で管理されています。

注意: Alibaba Cloud Container Service for Kubernetes その他のクラウドプロバイダーの Kubernetes でも、設定の考え方は同様です。

前提条件

K8s 環境における Nginx のログ出力は、ファイル出力ではなく StdOut 方式です。Guance Datakit は DaemonSet としてデプロイされると、デフォルトで K8s 内部の全 StdOut ログ出力を収集します。これには、CoreDNS(ログ出力を有効化する必要あり)などのクラスター内部コンポーネントの StdOut 出力も含まれます。本ドキュメントで扱うログはすべて StdOut 方式で出力されるものです。

補足:StdOut は、開発者がコードを記述する際にログのコンソール出力方式として選択するものです。例:

<appender name="console" class="ch.qos.logback.core.ConsoleAppender">

ホワイトリストの要件

Datakit のデプロイ完了後、指定した業務 Pod のログや K8s クラスターコンポーネントのログをオンデマンドで収集し、後から追加される未指定の業務 Pod のログは収集しません。また、同一 Pod 内の複数コンテナのログについては、そのうちの 1 つまたは複数のみを収集します。

本ドキュメントでは、Guance のコレクターである Datakit の異なるログフィルタリング方法を用いてこれを実現します。具体的には、ログに Annotation を付与する方法(Pod 内部の他のコンテナが出力するログのフィルタリングを含む)と、container.conf 内の container_include_log = [] を組み合わせて使用します。

より詳細なログ処理の原理については、<Datakit ログ処理概要> を参照してください。

実装方法

方法 1: container_include_log = [] を使用する

クラスターコンポーネントの coredns と nginx のログのみを収集します。container_include_log には、正規表現構文を用いてイメージ名を指定します。

詳細は <コンテナイメージに基づくメトリクスとログ収集の設定> を参照してください。

      [inputs.container]
        docker_endpoint = "unix:///var/run/docker.sock"
        containerd_address = "/var/run/containerd/containerd.sock"

        enable_container_metric = true
        enable_k8s_metric = true
        enable_pod_metric = true

        ## 収集対象/除外対象のコンテナログ。デフォルトでは全コンテナを収集。グロブパターン対応。
        container_include_log = ["image:*coredns*","image:*nginx*"]
        container_exclude_log = ["image:pubrepo.guance.com/datakit/logfwd*", "image:pubrepo.guance.com/datakit/datakit*"]

        exclude_pause_container = true

        ## テキスト文字列から ANSI エスケープコードを除去
        logging_remove_ansi_escape_codes = false

        kubernetes_url = "https://kubernetes.default:443"

        ## 認証レベル:
        ##   bearer_token -> bearer_token_string -> TLS
        ## 認証には bearer token を使用('bearer_token' が優先)
        ## linux:   /run/secrets/kubernetes.io/serviceaccount/token
        ## windows: C:\var\run\secrets\kubernetes.io\serviceaccount\token
        bearer_token = "/run/secrets/kubernetes.io/serviceaccount/token"
        # bearer_token_string = "<your-token-string>"

        [inputs.container.tags]
          # some_tag = "some_value"
          # more_tag = "some_other_value"

実装効果

指定したイメージ名の Pod ログのみをオンデマンドで収集します。下図のとおりです。

image

方法 2: container_include_log = [] と Annotation の組み合わせ

クラスターコンポーネントの coredns と nginx のログのみを収集すると同時に、Annotation によって nginx にマークを付けます。もちろん、container_include_log でホワイトリストに登録されていないイメージ(例:busybox)でも、Annotation 方式でマークすれば収集可能です。これは、Annotation 方式の優先度が高いためです。

より詳細なログ処理の原理については、<Datakit ログ処理概要> を参照してください。

Nginx の Annotation マーク

      labels:
         app: nginx-pod
      annotations:
        datakit/logs: |
          [
            {
              "disable": false,
              "source": "nginx-source",
              "service": "nginx-source",
              "pipeline": "",
              "multiline_match": ""
            }
          ]
    spec:
[inputs.container]
  docker_endpoint = "unix:///var/run/docker.sock"
  containerd_address = "/var/run/containerd/containerd.sock"

  ## 収集対象/除外対象のコンテナメトリクス。デフォルトでは収集しません。グロブパターン対応。
  container_include_metric = []
  container_exclude_metric = ["image:*"]

  ## 収集対象/除外対象のコンテナログ。デフォルトでは全コンテナを収集。グロブパターン対応。
  container_include_log = ["image:*coredns*","image:*nginx*"]
  container_exclude_log = []

  exclude_pause_container = true

  ## テキスト文字列から ANSI エスケープコードを除去
  logging_remove_ansi_escape_codes = false
  ## ログの最大長。デフォルトは 32766 バイト。
  max_logging_length = 32766

  kubernetes_url = "https://kubernetes.default:443"

  ## 認証レベル:
  ##   bearer_token -> bearer_token_string -> TLS
  ## 認証には bearer token を使用('bearer_token' が優先)
  ## linux:   /run/secrets/kubernetes.io/serviceaccount/token
  ## windows: C:\var\run\secrets\kubernetes.io\serviceaccount\token
  bearer_token = "/run/secrets/kubernetes.io/serviceaccount/token"
  # bearer_token_string = "<your-token-string>"

  [inputs.container.tags]
    # some_tag = "some_value"
    # more_tag = "some_other_value"

実装効果

image

方法 3: Pod 内の特定コンテナログをフィルタリングする

クラスターコンポーネントの coredns と nginx のログのみを収集します。同時に、nginx の Annotation マーク内の "only_images" フィールドを使用して、収集対象とするコンテナのイメージを指定します。つまり、Pod 内部にもホワイトリスト戦略を適用します。

Pod 内ホワイトリスト有効化前

下図のとおり、nginx と busybox の両方のログが収集されます。

image

Pod 内ホワイトリスト有効化

      labels:
         app: nginx-pod
      annotations:
        datakit/logs: |
          [
            {
              "disable": false,
              "source": "nginx-source",
              "service": "nginx-source",
              "pipeline": "",
              "only_images": ["image:*nginx*"],
              "multiline_match": ""
            }
          ]
    spec:

実装効果

Pod 内の Nginx ログのみが保持されます。

image

まとめ

実際には、ホワイトリスト戦略の使用は推奨しません。ホワイトリストは多くの問題を引き起こす可能性があり、デバッグも容易ではありません。また、予期しない効果が生じることもあります(例えば、開発者がログを出力したのに見えない場合、それは特定のタグが付与されていないことが原因かもしれません)。ログの発生源をフィルタリングする場合、ブラックリストが無効になっても、最悪のケースではデータが収集されてしまいます。ブラックリストによるフィルタリングは、例えば Datakit コレクターの container.conf 内で以下のように設定します。

container_exclude_log = ["image:pubrepo.guance.com/datakit/logfwd*"]

方法 1 は、Annotation を使用せず、コレクター container.conf に組み込まれたフィルタリング方式を用いる、より低レイヤーな実装です。しかし、この方法は方法 2 に劣ります。なぜなら、マーク方式ではログの発生源により適切なタグを付与できるため、将来の問題分析やフィルタリングが容易になり、また柔軟性も高まるからです。マークは業務 Pod 上に付与されるため、同一の業務イメージに対してきめ細かいログフィルタリング管理が可能です。
方法 3 は、特定の業務シナリオに応じて、不要な Sidecar などのログをフィルタリングし、ノイズを低減する効果があります。

フィードバック

このページは役に立ちましたか?