시스템 로그
시스템 로그 (System Logs)
시스템 컴포넌트 로그는 클러스터에서 발생하는 이벤트를 기록하며, 디버깅에 매우 유용할 수 있어요. 로그 상세 수준(verbosity)을 구성해 더 많거나 적은 세부 내용을 볼 수 있어요. 로그는 컴포넌트 안의 오류를 보여주는 정도로 거칠게(coarse-grained) 할 수도 있고, 이벤트의 단계별 추적(예: HTTP 접근 로그, 파드 상태 변경, 컨트롤러 동작, 스케줄러 결정)을 보여줄 정도로 세밀하게(fine-grained) 할 수도 있어요.
경고:
출처: 문서
본문
Klog
klog는 쿠버네티스 로깅 라이브러리예요. klog가 쿠버네티스 시스템 컴포넌트의 로그 메시지를 생성해요.
쿠버네티스는 컴포넌트의 로깅을 단순화하는 과정에 있어요. 다음 klog 명령줄 플래그는 쿠버네티스 v1.23부터 사용 중단(deprecated)되고 쿠버네티스 v1.26에서 제거됐어요:
--add-dir-header--alsologtostderr--log-backtrace-at--log-dir--log-file--log-file-max-size--logtostderr--one-output--skip-headers--skip-log-headers--stderrthreshold
출력은 출력 형식과 무관하게 항상 stderr로 기록돼요. 출력 리다이렉션은 쿠버네티스 컴포넌트를 호출하는 컴포넌트가 처리할 것으로 기대돼요. 이는 POSIX 셸이나 systemd 같은 도구일 수 있어요.
어떤 경우(예: distroless 컨테이너나 Windows 시스템 서비스)에는 그런 옵션을 사용할 수 없어요. 그런 경우 kube-log-runner 바이너리를 쿠버네티스 컴포넌트 주위의 래퍼로 사용해 출력을 리다이렉션할 수 있어요. 미리 빌드된 바이너리는 여러 쿠버네티스 기본 이미지에 전통적인 이름 /go-runner 로 포함되어 있고, 서버·노드 릴리스 아카이브에는 kube-log-runner 로 포함되어 있어요.
다음 표는 kube-log-runner 호출이 셸 리다이렉션과 어떻게 대응하는지 보여줘요:
| 용도 | POSIX 셸(예: bash) | kube-log-runner <options> <cmd> |
|---|---|---|
| stderr와 stdout 병합, stdout에 기록 | 2>&1 |
kube-log-runner (기본 동작) |
| 둘 다 로그 파일로 리다이렉션 | 1>>/tmp/log 2>&1 |
kube-log-runner -log-file=/tmp/log |
| 로그 파일과 stdout에 복사 | 2>&1 | tee -a /tmp/log |
kube-log-runner -log-file=/tmp/log -also-stdout |
| stdout만 로그 파일로 리다이렉션 | >/tmp/log |
kube-log-runner -log-file=/tmp/log -redirect-stderr=false |
Klog 출력
전통적인 klog 네이티브 형식의 예시:
I1025 00:15:15.525108 1 httplog.go:79] GET /api/v1/namespaces/kube-system/pods/metrics-server-v0.3.1-57c75779f-9p8wg: (1.512ms) 200 [pod_nanny/v0.0.0 (linux/amd64) kubernetes/$Format 10.56.1.19:51756]
메시지 문자열은 줄 바꿈을 포함할 수 있어요:
I1025 00:15:15.525108 1 example.go:79] This is a message
which has a line break.
구조화 로깅 (Structured Logging)
경고:
구조화 로그 메시지로의 마이그레이션은 진행 중인 과정이에요. 이 버전에서 모든 로그 메시지가 구조화된 것은 아니에요. 로그 파일을 파싱할 때는 구조화되지 않은 로그 메시지도 처리해야 해요.
로그 형식과 값 직렬화는 변경될 수 있어요.
구조화 로깅은 로그 메시지에 균일한 구조를 도입해 정보의 프로그래밍 방식 추출을 가능하게 해요. 구조화 로그는 더 적은 노력과 비용으로 저장·처리할 수 있어요. 로그 메시지를 생성하는 코드가 전통적인 비구조화 klog 출력을 사용할지 구조화 로깅을 사용할지 결정해요.
구조화 로그 메시지의 기본 형식은 텍스트이며, 전통적인 klog와 이전 버전과 호환되는 형식이에요:
<klog header> "<message>" <key1>="<value1>" <key2>="<value2>" ...
예시:
I1025 00:15:15.525108 1 controller_utils.go:116] "Pod status updated" pod="kube-system/kubedns" status="ready"
문자열은 따옴표로 묶여요. 다른 값은 %+v로 형식화되는데, 데이터에 따라 로그 메시지가 다음 줄로 계속될 수 있어요.
I1025 00:15:15.525108 1 example.go:116] "Example" data="This is text with a line break\nand \"quotation marks\"." someInt=1 someFloat=0.1 someStruct={StringField: First line,
second line.}
컨텍스트 로깅 (Contextual Logging)
컨텍스트 로깅은 구조화 로깅 위에 구축돼요. 주로 개발자가 로깅 호출을 사용하는 방식에 관한 것이에요. 그 개념에 기반한 코드는 더 유연하며 Contextual Logging KEP에 설명된 추가 사용 사례를 지원해요.
개발자가 컴포넌트에서 WithValues 나 WithName 같은 추가 함수를 사용하면, 로그 항목에는 호출자가 함수에 전달한 추가 정보가 포함돼요.
쿠버네티스 1.37의 경우 이것은 ContextualLogging 기능 게이트 뒤에 있으며 기본으로 활성화돼 있어요. 이를 위한 인프라는 컴포넌트를 수정하지 않고 1.24에 추가됐어요. component-base/logs/example 명령은 새 로깅 호출을 사용하는 방법과 컨텍스트 로깅을 지원하는 컴포넌트가 어떻게 동작하는지 보여줘요.
$ cd $GOPATH/src/k8s.io/kubernetes/staging/src/k8s.io/component-base/logs/example/cmd/
$ go run . --help
...
--feature-gates mapStringBool A set of key=value pairs that describe feature gates for alpha/experimental features. Options are:
AllAlpha=true|false (ALPHA - default=false)
AllBeta=true|false (BETA - default=false)
ContextualLogging=true|false (BETA - default=true)
$ go run . --feature-gates ContextualLogging=true
...
I0222 15:13:31.645988 197901 example.go:54] "runtime" logger="example.myname" foo="bar" duration="1m0s"
I0222 15:13:31.646007 197901 example.go:55] "another runtime" logger="example" foo="bar" duration="1h0m0s" duration="1m0s"
logger 키와 foo="bar" 는 runtime 메시지를 기록하는 함수와 duration="1m0s" 값을 수정하지 않고 그 함수의 호출자가 추가한 것이에요.
컨텍스트 로깅이 비활성화되면 WithValues 와 WithName 은 아무것도 하지 않고 로그 호출은 전역 klog 로거를 통해 진행돼요. 따라서 이 추가 정보는 로그 출력에 더 이상 없어요:
$ go run . --feature-gates ContextualLogging=false
...
I0222 15:14:40.497333 198174 example.go:54] "runtime" duration="1m0s"
I0222 15:14:40.497346 198174 example.go:55] "another runtime" duration="1h0m0s" duration="1m0s"
JSON 로그 형식
경고:
JSON 출력은 많은 표준 klog 플래그를 지원하지 않아요. 지원되지 않는 klog 플래그 목록은 명령줄 도구 참조를 참고해요.
모든 로그가 JSON 형식으로 기록된다고 보장되지는 않아요(예: 프로세스 시작 중). 로그를 파싱하려면 JSON이 아닌 로그 줄도 처리할 수 있는지 확인해요.
필드 이름과 JSON 직렬화는 변경될 수 있어요.
--logging-format=json 플래그는 로그 형식을 klog 네이티브 형식에서 JSON 형식으로 변경해요. JSON 로그 형식 예시(예쁘게 출력됨):
{
"ts": 1580306777.04728,
"v": 4,
"msg": "Pod status updated",
"pod":{
"name": "nginx-1",
"namespace": "default"
},
"status": "ready"
}
특별한 의미를 가진 키:
ts- Unix 시간으로서의 타임스탬프(필수, float)v- 상세 수준(info 및 오류 메시지 아님에만 해당, int)err- 오류 문자열(선택, string)msg- 메시지(필수, string)
현재 JSON 형식을 지원하는 컴포넌트 목록:
로그 상세 수준 (Log verbosity level)
-v 플래그는 로그 상세 수준을 제어해요. 값을 높이면 기록되는 이벤트 수가 늘어나고, 값을 낮추면 줄어들어요. 상세 설정을 높이면 덜 심각한 이벤트가 기록돼요. 상세 수준 0 설정은 중요 이벤트만 기록해요.
로그 위치 (Log location)
시스템 컴포넌트에는 두 가지 유형이 있어요: 컨테이너에서 실행되는 것과 컨테이너에서 실행되지 않는 것. 예를 들어:
- 쿠버네티스 스케줄러와 kube-proxy는 컨테이너에서 실행돼요.
- kubelet과 컨테이너 런타임은 컨테이너에서 실행되지 않아요.
systemd가 있는 머신에서 kubelet과 컨테이너 런타임은 journald에 기록해요. 그렇지 않으면 /var/log 디렉토리의 .log 파일에 기록해요. 컨테이너 안의 시스템 컴포넌트는 기본 로깅 메커니즘을 우회해 항상 /var/log 디렉토리의 .log 파일에 기록해요. 컨테이너 로그와 비슷하게 /var/log 디렉토리의 시스템 컴포넌트 로그를 회전(rotate)해야 해요. kube-up.sh 스크립트로 만든 쿠버네티스 클러스터에서는 logrotate 도구로 로그 회전이 구성돼요. logrotate 도구는 로그를 매일 또는 로그 크기가 100MB를 초과하면 회전해요.
로그 조회 (Log query)
이는 쿠버네티스의 stable 기능이며 버전 1.36부터 stable입니다. 처음에는 v1.27 릴리스에서 사용할 수 있었어요.
Log Query 기능은 Linux와 Windows 노드 모두에서 문제를 디버깅하는 데 도움을 줄 수 있어요. 쿠버네티스 v1.27에서 도입된 이 기능은 노드에서 실행되는 서비스의 로그 보기를 허용해요. 기능을 사용하려면 대상 노드에 대해 kubelet 구성 옵션 enableSystemLogHandler 와 enableSystemLogQuery 가 모두 true 로 설정되어 있는지 확인해요.
쿠버네티스 v1.36에서 이 기능은 stable로 승격됐고 NodeLogQuery 기능 게이트가 이제 true 로 잠겨 있어요. 따라서 기능 게이트는 기본으로 활성화되고, enableSystemLogHandler 만 Log Query 기능을 활성화·비활성화하는 데 필요한 유일한 옵션으로 남아 있어요.
enableSystemLogHandler 는 기본값 false 이며 적극적으로 디버깅하지 않는 한 비활성 상태로 두는 것이 권장돼요.
경고:
Linux에서는 서비스 로그가 journald 로 사용 가능하다고 가정해요. Windows에서는 서비스 로그가 애플리케이션 로그 제공자에서 사용 가능하다고 가정해요. 두 운영 체제 모두에서 /var/log/ 안의 파일을 읽어도 로그를 사용할 수 있어요.
노드 객체와 상호 작용할 권한이 있다면 모든 노드 또는 그 일부에서 이 기능을 시도해 볼 수 있어요. 다음은 노드에서 kubelet 서비스 로그를 검색하는 예시예요:
# Fetch kubelet logs from a node named node-1.example
kubectl get --raw "/api/v1/nodes/node-1.example/proxy/logs/?query=kubelet"
또한 파일이 kubelet이 로그 가져오기를 허용하는 디렉토리에 있다면 파일도 가져올 수 있어요. 예를 들어 Linux 노드의 /var/log 에서 로그를 가져올 수 있어요:
kubectl get --raw "/api/v1/nodes/<insert-node-name-here>/proxy/logs/?query=/<insert-log-file-name-here>"
kubelet은 로그를 검색하기 위해 휴리스틱을 사용해요. 이것은 주어진 시스템 서비스가 journald 같은 운영 체제의 네이티브 로거에 로그를 기록하는지 /var/log/ 의 로그 파일에 기록하는지 알지 못할 때 도움이 돼요. 휴리스틱은 먼저 네이티브 로거를 확인하고, 그걸 사용할 수 없으면 /var/log/<servicename> 또는 /var/log/<servicename>.log 또는 /var/log/<servicename>/<servicename>.log 에서 첫 로그를 검색하려 시도해요.
사용할 수 있는 옵션의 전체 목록:
| 옵션 | 설명 |
|---|---|
boot |
특정 시스템 부팅의 메시지 보여줌 |
pattern |
제공된 PERL 호환 정규식으로 로그 항목 필터링 |
query |
로그를 반환할 서비스(들) 또는 파일 지정(필수) |
sinceTime |
로그를 보여줄 RFC3339 타임스탬프(포함) |
untilTime |
로그를 보여줄 RFC3339 타임스탬프(포함) |
tailLines |
로그 끝에서 검색할 줄 수 지정; 기본은 전체 로그 가져오기 |
더 복잡한 쿼리 예시:
# Fetch kubelet logs from a node named node-1.example that have the word "error"
kubectl get --raw "/api/v1/nodes/node-1.example/proxy/logs/?query=kubelet&pattern=error"
더 알아보기 (Learn more)
- 쿠버네티스 로깅 아키텍처 읽기
- 구조화 로깅 읽기
- 컨텍스트 로깅 읽기
- klog 플래그 사용 중단 읽기
- 로그 심각도 규칙 읽기
- Log Query 읽기