로깅 아키텍처

로깅 아키텍처 (Logging Architecture)

Kubernetes 클러스터에서 로그를 어떻게 다루고 저장하는지 설명할게요. 클러스터 수준 로깅의 개념부터 노드에서의 로그 처리, 그리고 대표적인 로깅 아키텍처까지 옆에서 차근차근 알려드릴게요.

출처: Kubernetes 공식 문서 — Logging Architecture

클러스터 수준 로깅 (Cluster-level logging)

클러스터에서 로그는 노드, 파드, 컨테이너와는 독립적인 별도의 저장소와 수명 주기를 가져야 해요. 이 개념을 클러스터 수준 로깅이라고 합니다.

클러스터 수준 로깅 아키텍처는 로그를 저장하고 분석하고 조회하기 위한 별도의 백엔드가 필요해요. Kubernetes는 로그 데이터에 대한 네이티브 저장 솔루션을 제공하지 않아요. 대신 Kubernetes와 통합되는 수많은 로깅 솔루션이 존재합니다.

파드와 컨테이너 로그 (Pod and container logs)

Kubernetes는 실행 중인 파드의 각 컨테이너에서 로그를 수집해요. 기본 예제는 표준 출력 스트림(stdout)으로 텍스트를 1초에 한 번 쓰는 컨테이너를 가진 Pod 매니페스트를 사용합니다.

kubectl logs --previous 명령으로 컨테이너의 이전 인스턴스에서 생성된 로그를 가져올 수 있어요. 파드에 여러 컨테이너가 있다면, -c 플래그로 컨테이너 이름을 지정해서 접근할 수 있습니다.

kubectl logs counter -c count

컨테이너 로그 스트림 (Container log streams)

알파 기능으로, kubelet은 컨테이너가 생성하는 두 표준 스트림(표준 출력 stdout과 표준 오류 stderr)을 분리해서 로그를 나눌 수 있어요. 이 동작을 사용하려면 PodLogsQuerySplitStreams 기능 게이트를 활성화해야 해요.

이 기능 게이트가 활성화되면 Kubernetes 1.36에서 파드 API를 통해 이러한 로그 스트림에 직접 접근할 수 있어요. stream 쿼리 문자열에 스트림 이름(Stdout 또는 Stderr)을 지정해서 특정 스트림을 가져올 수 있습니다.

노드가 컨테이너 로그를 처리하는 방법 (How nodes handle container logs)

컨테이너 런타임은 컨테이너화된 애플리케이션의 stdoutstderr 스트림으로 생성된 모든 출력을 처리하고 리다이렉트해요. 다양한 컨테이너 런타임이 서로 다른 방식으로 구현하지만, kubelet과의 통합은 CRI 로깅 형식으로 표준화되어 있어요.

기본적으로 컨테이너가 다시 시작되면 kubelet은 로그와 함께 종료된 컨테이너 하나를 유지해요. 파드가 노드에서 축출(evict)되면 모든 관련 컨테이너도 로그와 함께 축출됩니다.

kubelet은 Kubernetes API의 특수 기능을 통해 클라이언트에게 로그를 제공해요. 이에 접근하는 일반적인 방법은 kubectl logs를 실행하는 것입니다.

로그 회전 (Log rotation)

기능 상태: Kubernetes v1.21 [stable]

kubelet은 컨테이너 로그 회전과 로깅 디렉터리 구조 관리를 담당해요. kubelet은 이 정보를 CRI를 통해 컨테이너 런타임에 전달하고, 런타임은 주어진 위치에 컨테이너 로그를 기록합니다.

kubelet 구성 파일에서 두 가지 kubelet 구성 설정인 containerLogMaxSize(기본값 10Mi)와 containerLogMaxFiles(기본값 5)를 구성할 수 있어요. 이 설정은 각 로그 파일의 최대 크기와 각 컨테이너에 허용되는 최대 파일 수를 각각 설정해줍니다.

또한 containerLogMaxWorkerscontainerLogMonitorInterval 설정을 통해 동시 로그 회전 수와 로그 모니터링/회전 간격을 조정할 수 있어요.

시스템 컴포넌트 로그 (System component logs)

  • kubelet과 컨테이너 런타임은 컨테이너 안에서 실행되지 않아요. kubelet은 (파드로 묶인) 컨테이너들을 실행합니다.
  • Kubernetes 스케줄러, 컨트롤러 매니저, API 서버는 파드(보통 정적 파드) 안에서 실행됩니다.
  • etcd 컴포넌트는 컨트롤 플레인에서 실행되며, 대부분 정적 파드로도 실행됩니다.
  • kube-proxy를 사용한다면 보통 DaemonSet으로 실행합니다.

로그 위치 (Log locations)

기본적으로 kubelet은 컨테이너 런타임이 /var/log/pods 아래 디렉터리에 로그를 쓰도록 지시해요. kubelet 자체의 로그는 Windows 기준으로 C:\var\logs 디렉터리 안의 파일에 기록됩니다(참고: C:\var\log가 아님).

파드에서 실행되는 클러스터 컴포넌트는 기본 로깅 메커니즘을 우회해서 /var/log 디렉터리 안의 파일에 기록해요. Kubernetes의 스토리지 메커니즘을 사용해 영구 스토리지를 컴포넌트가 실행되는 컨테이너에 매핑할 수 있어요.

kubelet 구성 파일의 podLogsDir 파라미터를 설정하면 파드 로그 디렉터리를 기본값인 /var/log/pods에서 다른 경로로 변경할 수 있어요.

⚠️ 주의: etcd와 그 로그에 대한 자세한 내용은 etcd 문서를 참고하세요.

참고: 부모 노드에서 공유하는 볼륨에 로그를 기록하도록 스케줄러 같은 클러스터 컴포넌트를 구성했다면, 그 로그가 회전되는지 확인해야 해요. Kubernetes는 이 로그 회전을 관리하지 않습니다.

클러스터 수준 로깅 아키텍처 (Cluster-level logging architectures)

Kubernetes는 클러스터 수준 로깅을 위한 네이티브 솔루션을 제공하지 않지만, 고려할 수 있는 몇 가지 일반적인 접근 방식이 있어요.

  • 모든 노드에서 실행되는 노드 수준 로깅 에이전트를 사용
  • 애플리케이션 파드에 로깅 전용 사이드카 컨테이너를 포함
  • 애플리케이션 내부에서 백엔드로 직접 로그를 전송

노드 로깅 에이전트 사용 (Using a node logging agent)

각 노드에 노드 수준 로깅 에이전트를 포함해 클러스터 수준 로깅을 구현할 수 있어요. 로깅 에이전트는 로그를 노출하거나 백엔드로 전송하는 전용 도구예요. 에이전트는 모든 노드에서 실행되어야 하므로 DaemonSet으로 실행하는 것을 권장합니다. 노드 수준 로깅은 노드당 에이전트 하나만 만들고, 노드에서 실행 중인 애플리케이션의 변경을 요구하지 않아요.

로깅 에이전트가 있는 사이드카 컨테이너 (Sidecar container with the logging agent)

사이드카 컨테이너를 다음 두 가지 방법 중 하나로 사용할 수 있어요.

  • 사이드카 컨테이너가 애플리케이션 로그를 자신의 stdout으로 스트리밍
  • 사이드카 컨테이너가 애플리케이션 컨테이너에서 로그를 수집하도록 구성된 로깅 에이전트 실행

스트리밍 사이드카 컨테이너 (Streaming sidecar container)

사이드카 컨테이너가 각자의 stdoutstderr 스트림에 쓰도록 하면, 이미 각 노드에서 실행 중인 kubelet과 로깅 에이전트를 활용할 수 있어요. stdoutstderr가 kubelet에 의해 처리되므로 kubectl logs 같은 내장 도구를 사용할 수 있습니다.

서로 다른 형식의 로그 항목을 같은 로그 스트림에 쓰는 것은 권장하지 않아요. 대신 사이드카 컨테이너 두 개를 만들 수 있습니다. 노드 수준 에이전트가 설치되어 있다면 추가 구성 없이 자동으로 로그 스트림을 수집합니다.

사이드카 컨테이너는 애플리케이션이 스스로 회전할 수 없는 로그 파일을 회전하는 데도 사용할 수 있어요. 예를 들어 주기적으로 logrotate를 실행하는 작은 컨테이너가 있죠. 다만 stdoutstderr을 직접 사용하는 편이 더 간단합니다.

로깅 에이전트를 가진 사이드카 컨테이너 (Sidecar container with a logging agent)

노드 수준 로깅 에이전트가 충분히 유연하지 않다면, 애플리케이션과 함께 실행되도록 특별히 구성한 별도의 로깅 에이전트를 가진 사이드카 컨테이너를 만들 수 있어요.

참고: 사이드카 컨테이너에서 로깅 에이전트를 사용하면 상당한 리소스가 소모될 수 있어요. 또한 이런 로그는 kubelet이 제어하지 않기 때문에 kubectl logs로 접근할 수 없습니다.

fluentd를 구성한 ConfigMap과 사이드카 컨테이너가 fluentd를 실행하는 파드 매니페스트 예시를 참고할 수 있어요. fluentd 대신 애플리케이션 컨테이너 내부의 어떤 소스에서든 읽는 모든 로깅 에이전트로 교체할 수 있습니다.

애플리케이션에서 직접 로그 노출 (Exposing logs directly from the application)

모든 애플리케이션에서 직접 로그를 노출하거나 전송하는 클러스터 로깅은 Kubernetes의 범위를 벗어나요.

더 알아보기 (Learn more)