コンテンツにスキップ

Kubernetes クラスターにおけるログ収集のさまざまな方法


はじめに

企業のアプリケーションシステムにとって、ログは非常に重要な役割を果たします。特に Kubernetes 環境ではログ収集がさらに複雑になるため、DataKit はログ収集に対して非常に強力なサポートを提供し、多様な環境や技術スタックに対応しています。ここでは、DataKit のログ収集の使用方法について詳しく説明します。

前提条件

Guance にログインし、【インテグレーション】→【Datakit】→【Kubernetes】の順に進み、案内に従って Kubernetes クラスターに DataKit をインストールしてください。デプロイに使用する datakit.yaml ファイルは、以降の操作で使用します。

DataKit の詳細設定

1 ログレベルの設定

DataKit のデフォルトのログレベルは Info です。ログレベルを Debug に変更する場合は、datakit.yaml に環境変数を追加します。

        - name: ENV_LOG_LEVEL
          value: debug

2 ログ出力方法の設定

DataKit はデフォルトでログを /var/log/datakit/gin.log および /var/log/datakit/log に出力します。コンテナ内にログファイルを生成したくない場合は、datakit.yaml に環境変数を追加します。

    - name: ENV_LOG
      value: stdout
    - name: ENV_GIN_LOG
      value: stdout     
DataKit が生成したログは、kubectl コマンドと POD 名を使用して確認できます。

kubectl logs datakit-2fnrz -n datakit # 

注意』:ENV_LOG_LEVEL を debug に設定すると大量のログが生成されるため、その場合は ENV_LOG を stdout に設定することは推奨しません。

ログ収集

1 stdout 収集

1.1 stdout ログの全収集

DataKit は stdout に出力されたコンテナログを収集できます。datakit.yaml を使用して DataKit をデプロイすると、デフォルトで container 収集機能が有効になります。

        - name: ENV_DEFAULT_ENABLED_INPUTS
          value: cpu,disk,diskio,mem,swap,system,hostobject,net,host_processes,container

この時、DataKit コンテナ内に /usr/local/datakit/conf.d/container/container.conf 設定ファイルが生成されます。デフォルト設定では、pubrepo.guance.com/datakit/logfwd で始まるイメージを除くすべての stdout ログを収集します。

  container_include_log = []  # 相当于image:*
  container_exclude_log = ["image:pubrepo.guance.com/datakit/logfwd*"]

1.2 カスタム stdout ログ収集

ログの発生源をより明確に区別し、タグを追加したり、ログを解析する pipeline ファイルを指定するには、カスタム方式を使用します。つまり、デプロイする yaml ファイルに annotations を追加します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: log-demo-service
  labels:
    app: log-demo-service
spec:
  replicas: 1
  selector:
    matchLabels:
      app: log-demo-service
  template:
    metadata:
      labels:
        app: log-demo-service
      annotations:
        # 以下を追加
        datakit/logs: |
          [
            {
              "source": "pod-logging-testing-demo",
              "service": "pod-logging-testing-demo",
              "pipeline": "pod-logging-demo.p",
              "multiline_match": "^\\d{4}-\\d{2}-\\d{2}"
            }
          ]

Annotations パラメータの説明

  • source: データソース
  • service: タグマーク
  • pipeline: pipeline スクリプト名
  • ignore_status:
  • multiline_match: 1行のログを一致させる正規表現。例では日付(2021-11-26 など)で始まるものを1行のログとして扱い、次の行がこの日付で始まらない場合は、その行のログは前の行の一部と見なされます。
  • remove_ansi_escape_codes: ANSI エスケープコード(標準出力のテキスト色など)を削除するかどうか

1.3 コンテナの stdout ログを収集しない

コンテナ収集機能を有効にすると、コンテナが stdout に出力するログが自動的に収集されます。収集したくないログがある場合は、以下の方法があります。

1.3.1 POD の stdout ログ収集を無効にする

アプリケーションをデプロイする yaml ファイルに annotations を追加し、disable を true に設定します。

apiVersion: apps/v1
kind: Deployment
metadata:

...

spec:
  ...
  template:
    metadata:      
      annotations:
        ## 以下を追加
        datakit/logs: |
          [
            {
              "disable": true  
            }
          ]
1.3.2 標準出力のリダイレクト

stdout ログ収集が有効になっており、コンテナのログも stdout に出力されている場合、両方を変更したくない場合は、起動コマンドを変更して標準出力をリダイレクトできます。

java ${JAVA_OPTS}   -jar ${jar} ${PARAMS}  2>&1 > /dev/null
1.3.3 container 収集機能のフィルタリング機能

stdout ログの収集をより簡単に制御したい場合は、container.conf ファイルを上書きすることを推奨します。つまり、ConfigMap を使用して container.conf を定義し、container_include_log と container_exclude_log の値を変更して、DataKit にマウントします。datakit.yaml で以下のように変更します。

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: datakit-conf
  namespace: datakit
data:
    #### container
    container.conf: |-  
      [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

        ## Containers logs to include and exclude, default collect all containers. Globs accepted.
        container_include_log = []
        container_exclude_log = ["image:pubrepo.guance.com/datakit/logfwd*", "image:pubrepo.guance.com/datakit/datakit*"]

        exclude_pause_container = true

        ## Removes ANSI escape codes from text strings
        logging_remove_ansi_escape_codes = false

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

        ## Authorization level:
        ##   bearer_token -> bearer_token_string -> TLS
        ## Use bearer token for authorization. ('bearer_token' takes priority)
        ## linux at:   /run/secrets/kubernetes.io/serviceaccount/token
        ## windows at: 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"
        volumeMounts:
        - mountPath: /usr/local/datakit/conf.d/container/container.conf
          name: datakit-conf
          subPath: container.conf
  • container_includecontainer_excludeimage で始まる必要があり、形式は "image:<glob规则>" です。glob ルールがコンテナイメージに対して適用されることを示します。
  • Glob ルール は軽量な正規表現で、* ? などの基本的なマッチングユニットをサポートします。

例えば、イメージ名に log-order を含み、log-pay を含まないものだけを収集したい場合は、以下のように設定します。

        container_include_log = ["image:*log-order*"]
        container_exclude_log = ["image:*log-pay*"]

注意』:ある POD で stdout ログ収集が有効になっている場合、logfwd や socket ログ収集を併用しないでください。ログが重複して収集されます。

2 logfwd 収集

これは Sidecar パターンを使用したログ収集方法です。同じ POD 内のコンテナがストレージを共有する仕組みを利用し、logfwd が Sidecar としてビジネスコンテナのログファイルを読み取り、DataKit に送信します。具体的な使用方法については、Pod ログ収集ベストプラクティス の方法2を参照してください。

3 socket 収集

DataKit が Socket ポート(例:9542)を開放すると、ログがこのポートにプッシュされます。Java の log4j や logback はログプッシュをサポートしています。以下では、SpringBoot に Logback を組み込んだ場合を例に、socket ログ収集を実装します。

3.1 Appender の追加

logback-spring.xml ファイルに socket Appender を追加します。

<?xml version="1.0" encoding="UTF-8"?>

<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <springProperty scope="context" name="dkSocketHost" source="datakit.socket.host" />
    <springProperty scope="context" name="dkSocketPort" source="datakit.socket.port" />
    <contextName>logback</contextName>

    <!-- ログルートディレクトリ -->
    <property name="log.path" value="./logs"/>
    <!-- ログ出力形式 -->
    <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] -  - %msg%n" />

    <!-- コンソールにログを出力 -->
    <appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
    </appender>
    ... 
    <!-- 以下は追加する Socket appender --> 
    <appender name="socket" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <!-- datakit host: logsocket_port -->
        <destination>${dkSocketHost}:${dkSocketPort}</destination>
        <!-- ログ出力エンコーディング -->
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <timestamp>
                    <timeZone>UTC+8</timeZone>
                </timestamp>
                <pattern>
                    <pattern>
                        {
                        "severity": "%level",
                        "appName": "${logName:-}",
                        "trace": "%X{dd.trace_id:-}",
                        "span": "%X{dd.span_id:-}",
                        "pid": "${PID:-}",
                        "thread": "%thread",
                        "class": "%logger{40}",
                        "msg": "%message\n%exception"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="Console"/>
        <appender-ref ref="file_info"/>
        <appender-ref ref="socket" />
    </root>
</configuration>

3.2 設定の追加

SpringBoot プロジェクトの application.yml ファイルに設定を追加します。

datakit:
  socket:
    host: 120.26.218.200  # 
    port: 9542

3.3 依存関係の追加

SpringBoot プロジェクトの pom.xml に依存関係を追加します。

<dependency>
    <groupId>net.logstash.logback</groupId>
    <artifactId>logstash-logback-encoder</artifactId>
    <version>4.9</version>
</dependency>

3.4 DataKit に logging-socket.conf ファイルを追加

DataKit の datakit.yaml ファイルに以下の内容を追加します。

        volumeMounts:  # この位置に以下の3行を追加
        - mountPath: /usr/local/datakit/conf.d/log/logging-socket.conf
          name: datakit-conf
          subPath: logging-socket.conf

---           
apiVersion: v1
kind: ConfigMap
metadata:
  name: datakit-conf
  namespace: datakit
data:       
    logging-socket.conf: |-
      [[inputs.logging]]
        # only two protocols are supported:TCP and UDP
        sockets = [
          "tcp://0.0.0.0:9542",
        #"udp://0.0.0.0:9531",                  
        ]
        ignore = [""]
        source = "demo-socket-service"
        service = ""
        pipeline = ""
        ignore_status = []
        character_encoding = ""
        # multiline_match = '''^\S'''
        remove_ansi_escape_codes = false

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

Socket ログ収集の詳細については、logback socket ログ収集ベストプラクティス を参照してください。

4 ログファイル収集

Linux ホストにインストールされた DataKit がそのホストのログを収集する方法は、logging.conf ファイルをコピーし、logging.conf ファイル内の logfiles の値をログの絶対パスに変更することです。

cd /usr/local/datakit/conf.d/log
cp logging.conf.sample  logging.conf

Kubernetes 環境では、まず POD が生成するログディレクトリ /data/app/logs/demo-system をホストマシンの /var/log/k8s/demo-system にマウントし、次に DaemonSet で DataKit をデプロイし、/var/log/k8s/demo-system ディレクトリをマウントします。これにより、DataKit はホストマシン上の /rootfs/var/log/k8s/demo-system/info.log ログファイルを収集できます。

        volumeMounts:
        - name: app-log
          mountPath: /data/app/logs/demo-system

      ...

      volumes:   
      - name: app-log
        hostPath:
          path: /var/log/k8s/demo-system

        volumeMounts:  # この位置に以下の3行を追加
        - mountPath: /usr/local/datakit/conf.d/log/logging.conf
          name: datakit-conf
          subPath: logging.conf

---           
apiVersion: v1
kind: ConfigMap
metadata:
  name: datakit-conf
  namespace: datakit
data:           
    #### logging
    logging.conf: |-
        [[inputs.logging]]
          ## required
          logfiles = [
            "/rootfs/var/log/k8s/demo-system/info.log",
          ]

          ## glob filteer
          ignore = [""]

          ## your logging source, if it's empty, use 'default'
          source = "k8s-demo-system-log"

          ## add service tag, if it's empty, use $source.
          #service = "k8s-demo-system-log"

          ## grok pipeline script path
          pipeline = ""
          ## optional status:
          ##   "emerg","alert","critical","error","warning","info","debug","OK"
          ignore_status = []

          ## optional encodings:
          ##    "utf-8", "utf-16le", "utf-16le", "gbk", "gb18030" or ""
          character_encoding = ""

          ## The pattern should be a regexp. Note the use of '''this regexp'''
          ## regexp link: https://golang.org/pkg/regexp/syntax/#hdr-Syntax
          multiline_match = '''^\d{4}-\d{2}-\d{2}'''

          [inputs.logging.tags]
          # some_tag = "some_value"
          # more_tag = "some_other_value" 
注意』:Guance を使用してログを収集する場合、ログはすでに永続化されているため、ホストマシンにログを保存する必要はありません。したがって、Kubernetes 環境ではこの収集方法は推奨しません。

Pipeline

Pipeline は主に、非構造化テキストデータを解析したり、構造化テキスト(JSON など)から部分的な情報を抽出するために使用されます。ログに関しては、主にログの生成時間やログレベルなどの情報を抽出します。特に、Socket で収集されたログは JSON 形式であるため、検索ボックスでキーワード検索できるように解析する必要があります。Pipeline の詳細については、以下の記事を参照してください。

異常検知

ログに異常が発生し、アプリケーションに大きな影響を与える場合、Guance のログ異常検知機能を使用し、アラートを設定することで、異常を適切な監視対象に迅速に通知できます。Guance のアラートは、メール、DingTalk、SMS、WeCom、Lark などの通知方法をサポートしています。以下では、メールを例にアラートを説明します。

1 通知先の作成

Guance にログインし、【管理】→【通知先管理】→【通知先を作成】の順に進み、メールグループを選択し、名前とメールアドレスを入力します。

image

2 モニターの作成

【モニター】→【モニターを作成】→【ログモニタリング】の順にクリックします。

image

ルール名を入力します。検出指標の log_fwd_demo はログ収集時に設定した source で、その後の error はログに含まれる内容、host_ip はログのタグです。イベント内容では {{host_ip}} を使用して特定のタグの値を出力できます。トリガー条件は 1 を入力し、タイトルと内容はメールで送信されます。入力後、【保存】をクリックします。

image

image

3 アラートの設定

【モニター】画面で、先ほど作成したモニターをクリックし、【アラート設定】をクリックします。

image

アラート通知先は、最初の手順で作成したメールグループを選択し、アラートサイレント時間を選択して、【確定】をクリックします。

image

4 アラートのトリガー

アプリケーションで error ログがトリガーされると、通知メールが届きます。

image

フィードバック

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