콘텐츠로 이동

Pod 로그 수집 모범 사례


서문

컨테이너화된 방식으로 마이크로서비스를 배포할 때 마이크로서비스는 컨테이너에서 실행됩니다. Pod은 하나 또는 긴밀하게 결합된 여러 컨테이너로 구성되며, Kubernetes에서 가장 작은 스케줄링 단위입니다.

Pod 내 로그 수집을 위해 본 문서에서는 DataKit을 통해 로그를 수집하는 세 가지 방안을 설명합니다.

방안 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: 추가 태그입니다. 비어 있으면 기본적으로 $source를 사용합니다.
  • pipeline: Pipeline 사용 시 스크립트 경로를 정의합니다.
  • character_encoding: 인코딩을 선택합니다.
  • multiline_match: 멀티라인 매칭입니다.
  • remove_ansi_escape_codes: ANSI 이스케이프 코드(예: 표준 출력의 텍스트 색상 등)를 삭제할지 여부입니다. 값은 true 또는 false입니다.
  • tags: key-value 형식으로 태그를 정의하며, 필수 항목이 아닙니다.

환경 변수 설명

  • 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: 태그
  • pipeline: Pipeline 스크립트 경로
  • ignore_status:
  • multiline_match: 정규 표현식으로 한 줄의 로그를 매칭합니다. 예시에서는 날짜(예: 2021-11-26)로 시작하는 줄을 한 줄의 로그로 간주하며, 다음 줄이 이 날짜로 시작하지 않으면 해당 줄은 이전 로그의 일부로 간주됩니다.
  • 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을 배포합니다:

kubectl 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의 로그 파일을 수집할 수 있습니다.

문서 평가

이 페이지가 도움이 되었나요?