Pod 로그 수집 모범 사례¶
서문¶
컨테이너화된 방식으로 마이크로서비스를 배포할 때 마이크로서비스는 컨테이너에서 실행됩니다. Pod은 하나 또는 긴밀하게 결합된 여러 컨테이너로 구성되며, Kubernetes에서 가장 작은 스케줄링 단위입니다.
Pod 내 로그 수집을 위해 본 문서에서는 DataKit을 통해 로그를 수집하는 세 가지 방안을 설명합니다.
방안 1¶
DataKit에서 Logfwd 수집기를 활성화하고, Logfwd는 Sidecar 패턴으로 비즈니스 컨테이너 로그를 수집합니다.
1 Logfwd 수집기 활성화¶
Kubernetes에 DataKit이 통합되지 않은 경우, Guance에 로그인하여 「통합」 - 「Datakit」 - 「Kubernetes」에서 datakit.yaml 파일을 사용하여 DataKit을 통합하세요.
아래와 같이 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 재시작¶
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 포트입니다.
5 로그 확인¶
Guance에 로그인하여 「로그」에서 데이터 소스로 log_fwd_demo를 검색합니다.
방안 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 레지스트리에 업로드합니다:
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을 배포합니다:
마이크로서비스에 접속합니다:
Guance에 로그인하여 「로그」 모듈에서 log-demo-service를 입력하면 로그가 성공적으로 조회됩니다.
방안 3¶
Pod에 Volume을 마운트하고, 볼륨 유형으로 hostPath를 사용하여 로그 파일을 호스트에 마운트합니다. 그런 다음 DaemonSet으로 DataKit을 배포하고 동일하게 hostPath 유형의 Volume을 마운트하면 DataKit이 Pod의 로그 파일을 수집할 수 있습니다.




