コンテンツにスキップ

Pod ログ収集のベストプラクティス


はじめに

コンテナ化されたマイクロサービスのデプロイでは、マイクロサービスはコンテナ内で実行されます。Pod は1つまたは密接に結合された一連のコンテナで構成され、Kubernetes における最小のスケジューリング単位です。

本稿では、Pod 内のログについて、DataKit を使用したログ収集の3つの方法を紹介します。

方法1

DataKit で Logfwd コレクターを有効にし、Logfwd を Sidecar モードで使用して業務コンテナのログを収集します。

1 Logfwd コレクターを有効にする

Kubernetes に DataKit が統合されていない場合は、Guance にログインし、「インテグレーション」→「Datakit」→「Kubernetes」の順に選択し、datakit.yaml ファイルを使用して DataKit を統合してください。

image

次に、datakit.yaml ファイルを編集し、logfwdserver.conf ファイルを DataKit の /usr/local/datakit/conf.d/log/ ディレクトリにマウントします。

datakit.yaml に以下の設定を追加します:

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: datakit-conf
  namespace: datakit
data:
  #### logfwdserver
  logfwdserver.conf: |-
    [inputs.logfwdserver]
      ## logfwd 受信側のリスニングアドレスとポート
      address = "0.0.0.0:9531"

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

DaemonSet リソースに以下を追加します:

- mountPath: /usr/local/datakit/conf.d/log/logfwdserver.conf
  name: datakit-conf
  subPath: logfwdserver.conf

2 Pipeline をマウントする

datakit.yaml ファイルを編集し、pod-logging-demo.p ファイルを DataKit の /usr/local/datakit/pipeline/ ディレクトリにマウントします。

ConfigMap リソースに以下を追加します:

    pod-logging-demo.p: |-
        # ログ形式
        #2021-12-01 10:41:06.015 [http-nio-8090-exec-2] INFO  c.s.d.c.HealthController - [getPing,19] -  - ping インターフェースを呼び出し
        grok(_, "%{TIMESTAMP_ISO8601:time} %{NOTSPACE:thread_name} %{LOGLEVEL:status}%{SPACE}%{NOTSPACE:class_name} - \\[%{NOTSPACE:method_name},%{NUMBER:line}\\] -  - %{GREEDYDATA:msg}")


        default_time(time,"Asia/Shanghai")

DaemonSet リソースに以下を追加します:

- mountPath: /usr/local/datakit/pipeline/pod-logging-demo.p
  name: datakit-conf
  subPath: pod-logging-demo.p

注意: Pipeline を使用したログパース(切り出し)が不要な場合、この手順は省略できます。

3 DataKit を再起動する

kubectl delete -f datakit.yaml
kubectl apply -f datakit.yaml

4 Logfwd Sidecar によるログ収集

Logfwd イメージと業務イメージを同一 Pod にデプロイします。以下では log-demo-service:v1 を業務イメージとし、/data/app/logs/log.log ログファイルを生成します。logfwd が共有ストレージ方式でログファイルを読み取り、DataKit に転送します。pod-logging-demo.p を使用してログをパースし、日付でマルチラインマッチングを行います。

関連設定ファイルの例
apiVersion: apps/v1
kind: Deployment
metadata:
  name: log-fwd-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: log-fwd-pod
  template:
    metadata:
      labels:
        app: log-fwd-pod
      annotations:
    spec:
      nodeName: k8s-node2
      containers:
        - name: log-fwd-container
          image: 172.16.0.238/df-demo/log-demo-service:v2
          ports:
            - containerPort: 8090
              protocol: TCP
          volumeMounts:
            - mountPath: /data/app/logs
              name: varlog
        - name: logfwd
          image: pubrepo.guance.com/datakit/logfwd:1.2.12
          env:
            - name: LOGFWD_DATAKIT_HOST
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: status.hostIP
            - name: LOGFWD_DATAKIT_PORT
              value: "9531"
            - name: LOGFWD_ANNOTATION_DATAKIT_LOGS
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: metadata.annotations['datakit/logs']
            - name: LOGFWD_POD_NAME
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: metadata.name
            - name: LOGFWD_POD_NAMESPACE
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: metadata.namespace
          volumeMounts:
            - mountPath: /var/log
              name: varlog
            - mountPath: /opt/logfwd/config
              name: logfwd-config
              subPath: config
      restartPolicy: Always
      volumes:
        - name: varlog
          emptyDir: {}
        - configMap:
            name: logfwd-conf
          name: logfwd-config
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: logfwd-conf
data:
  config: |
    [
        {            
            "loggings": [
                {
                    "logfiles": ["/var/log/log.log"],
                    "source": "log_fwd_demo",                    
                    "pipeline": "pod-logging-demo.p",
                    "multiline_match": "^\\d{4}-\\d{2}-\\d{2}",
                    "tags": {
                        "flag": "tag1"
                    }
                }
            ]
        }
    ]

logfwd-conf パラメーターの説明

  • logfiles: ログファイルのリスト。
  • ignore: ファイルパスのフィルタリングに使用します。glob ルールに従い、いずれかのフィルター条件に一致した場合、そのファイルは収集されません。
  • source: データソース。
  • service: 追加するタグ service。空の場合は、デフォルトで $source が使用されます。
  • pipeline: Pipeline を使用する場合、スクリプトのパスを指定します。
  • character_encoding: エンコーディングを選択します。
  • multiline_match: マルチラインマッチング。
  • remove_ansi_escape_codes: ANSI エスケープコード(標準出力のテキスト色など)を削除するかどうか。値は true または false
  • tags: キーと値の形式でタグを定義します。必須項目ではありません。

環境変数の説明

  • LOGFWD_DATAKIT_HOST: DataKit のアドレス。
  • LOGFWD_DATAKIT_PORT: Logfwd のポート番号。
kubectl apply -f log-fwd-deployment.yaml

5 ログを確認する

Guance にログインし、「ログ」を選択して、データソース log_fwd_demo を検索します。

image

image

方法2

DataKit はデフォルトで Pod の標準出力(Stdout)に出力されたログを収集します。ログ形式を特殊処理するために、通常は Pod をデプロイする Deployment コントローラーの YAML ファイルに Annotations を追加します。

以下は、Spring Boot マイクロサービスのプロジェクトを例にしたログ収集のサンプルです。JAR ファイルは log-springboot-demo-1.0-SNAPSHOT.jar で、ログは Logback を使用します。具体的な手順は以下の通りです:

1 logback-spring.xml を作成する

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

<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <contextName>logback</contextName>

    <!-- ログのルートディレクトリ - - 
    <property name="log.root.dir" 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>

    <root level="INFO">
        <appender-ref ref="Console"/>
    </root>
</configuration>

2 イメージを作成する

Dockerfile は以下の通りです:

FROM openjdk:8u292

RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone
ENV jar log-springboot-demo-1.0-SNAPSHOT.jar

ENV workdir /data/app/
RUN mkdir -p ${workdir}
WORKDIR ${workdir}
ENTRYPOINT ["sh", "-ec", "exec java ${JAVA_OPTS} -jar ${jar} "]

イメージを作成し、Harbor レジストリにプッシュします:

 docker build -t <your-harbor>/log-demo-service:v1  .
 docker push <your-harbor>/log-demo-service:v1

3 pod-log-service.yaml ファイルを作成する

pod-log-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: log-demo-service
  labels:
    app: log-demo-service
spec:
  selector:
    app: log-demo-service
  ports:
    - protocol: TCP
      port: 8090
      nodePort: 30053
      targetPort: 8090
  type: NodePort
---
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}"
            }
          ]

    spec:
      containers:
        - env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
          name: log-service
          image: <your-harbor>/log-demo-service:v1
          ports:
            - containerPort: 8090
              protocol: TCP

      restartPolicy: Always
      volumes:
        - name: ddagent
          emptyDir: {}

Annotations パラメーターの説明

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

4 Pipeline を設定する

datakit-default.yaml ファイルの ConfigMap リソースに pod-logging-demo.p セクションを追加します。

apiVersion: v1
kind: ConfigMap
metadata:
  name: datakit-conf
  namespace: datakit
data:
  pod-logging-demo.p: |-
    # ログ形式
    #2021-12-01 10:41:06.015 [http-nio-8090-exec-2] INFO  c.s.d.c.HealthController - [getPing,19] -  - ping インターフェースを呼び出し
    grok(_, "%{TIMESTAMP_ISO8601:time} %{NOTSPACE:thread_name} %{LOGLEVEL:status}%{SPACE}%{NOTSPACE:class_name} - \\[%{NOTSPACE:method_name},%{NUMBER:line}\\] -  - %{GREEDYDATA:msg}")

    default_time(time)

Pod-logging-demo.p を DataKit にマウントします。

- mountPath: /usr/local/datakit/pipeline/pod-logging-demo.p
  name: datakit-conf
  subPath: pod-logging-demo.p

5 ログを確認する

以下のコマンドを実行して Pod をデプロイします:

kuectl apply -f pod-log-service.yaml

マイクロサービスにアクセスします:

curl localhost:30053/ping

Guance にログインし、「ログ」モジュールで log-demo-service と入力すると、ログが正常に表示されます。

image

image

方法3

Pod に Volume をマウントします。ボリュームタイプは hostPath を使用し、ログファイルをホストマシンにマウントします。その後、DaemonSet を使用して DataKit をデプロイし、同様に hostPath タイプの Volume をマウントすることで、DataKit が Pod 内のログファイルを収集できるようにします。

フィードバック

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