콘텐츠로 이동

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 logs 명령어에 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 로그 수집

로그 출처를 더 잘 구분하고, tag를 추가하며, 로그 파이프라인 파일을 지정하려면 사용자 정의 방식이 필요합니다. 즉, 배포 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: tag 표시
  • pipeline: 파이프라인 스크립트 이름
  • ignore_status:
  • multiline_match: 정규 표현식으로 한 줄의 로그를 매칭합니다. 예시에서는 날짜(예: 2021-11-26)로 시작하는 것을 한 줄의 로그로 간주하며, 다음 줄이 이 날짜로 시작하지 않으면 해당 로그 줄은 이전 로그의 일부로 간주합니다.
  • remove_ansi_escape_codes: ANSI 이스케이프 코드(예: 표준 출력의 텍스트 색상 등)를 삭제할지 여부

1.3 컨테이너의 stdout 로그를 수집하지 않음

컨테이너 수집기를 활성화하면 컨테이너가 stdout으로 출력하는 로그가 자동으로 수집됩니다. 수집을 원하지 않는 로그가 있는 경우 다음과 같은 방법이 있습니다.

1.3.1 POD의 stdout 로그 수집 비활성화

애플리케이션 배포 yaml 파일에 annotations을 추가하고 disabletrue로 설정합니다.

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_logcontainer_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

        ## 포함 및 제외할 컨테이너 로그, 기본적으로 모든 컨테이너를 수집합니다. Glob 패턴을 허용합니다.
        container_include_log = []
        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"
        volumeMounts:
        - mountPath: /usr/local/datakit/conf.d/container/container.conf
          name: datakit-conf
          subPath: container.conf
  • container_includecontainer_exclude는 반드시 image로 시작해야 하며, 형식은 "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 로그 수집 모범 사례의 두 번째 방안을 참조하세요.

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:  # 이 위치에 아래 세 줄을 추가
        - 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]]
        # TCP와 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:  # 이 위치에 아래 세 줄을 추가
        - 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]]
          ## 필수
          logfiles = [
            "/rootfs/var/log/k8s/demo-system/info.log",
          ]

          ## glob 필터
          ignore = [""]

          ## 로그 소스, 비어 있으면 'default' 사용
          source = "k8s-demo-system-log"

          ## service 태그 추가, 비어 있으면 $source 사용
          #service = "k8s-demo-system-log"

          ## grok 파이프라인 스크립트 경로
          pipeline = ""
          ## 선택적 상태:
          ##   "emerg","alert","critical","error","warning","info","debug","OK"
          ignore_status = []

          ## 선택적 인코딩:
          ##    "utf-8", "utf-16le", "utf-16le", "gbk", "gb18030" 또는 ""
          character_encoding = ""

          ## 패턴은 정규 표현식이어야 합니다. '''this regexp''' 사용에 유의하세요.
          ## 정규 표현식 링크: 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에 로그인하여 【관리】->【알림 대상 관리】-> 【알림 대상 생성】으로 이동한 후, 메일 그룹을 선택하고 이름과 이메일 주소를 입력합니다.

이미지

2 모니터 생성

【모니터】->【모니터 생성】-> 【로그 모니터링】을 클릭합니다.

이미지

규칙 이름을 입력하고, 검색 지표 log_fwd_demo는 로그 수집 시 설정한 source이며, 뒤의 error는 로그에 포함된 내용이고, host_ip는 로그의 태그입니다. 이벤트 내용에서는 {{host_ip}}를 사용하여 특정 태그의 값을 출력할 수 있습니다. 트리거 조건에 1을 입력하고, 제목과 내용은 이메일로 전송됩니다. 입력 후 【저장】을 클릭합니다.

이미지

이미지

3 알림 구성

【모니터】화면에서 방금 생성한 모니터를 클릭하고 【알림 구성】을 클릭합니다.

이미지

알림 알림 대상으로 첫 번째 단계에서 생성한 메일 그룹을 선택하고, 알림 음소거 시간을 선택한 후 【확인】을 클릭합니다.

이미지

4 알림 트리거

애플리케이션에서 error 로그가 트리거되면 알림 이메일이 수신됩니다.

이미지

문서 평가

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