| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
| 29 | 30 |
- 키보드멈춤
- 새우항 세팅
- 기도
- 몬모릴로나이트
- 워킹루어
- 마우스멈춤
- 묵상
- 이머전트
- CruxCPM
- CruxSIEM
- 말씀
- Wazuh
- 가재항 세팅
- 지그헤드
- 테라포리움
- SHACL
- QT
- 물생활
- 질산염 관리
- ModernStandby
- 소일어항
- LLM 지식베이스
- 양이온교환
- 엘라스틱서치
- SKOS
- 바이오안보바
- 무환수 가재항
- 시가테크놀로지스
- 어항수경재배
- 신앙
- Today
- Total
포너포닉스
OpenShift(OCP) 환경 Filebeat DaemonSet 로그 수집 경로 완벽 분석: Container, Audit, auditd, journald 수집 및 Logstash 파싱 아키텍처 본문
OpenShift(OCP) 환경 Filebeat DaemonSet 로그 수집 경로 완벽 분석: Container, Audit, auditd, journald 수집 및 Logstash 파싱 아키텍처
PONERponix 2026. 11. 12. 00:521. 개요: Filebeat DaemonSet 수집 경로에 대한 흔한 오해
엔터프라이즈 환경 및 금융권의 Red Hat OpenShift Container Platform(OCP) 환경에서 대용량 로그 통합 아키텍처를 설계할 때, 로그 에이전트로 Filebeat DaemonSet을 자주 채택합니다. 이때 현업 엔지니어들이 흔히 마주치는 설계 질문 중 하나가 있습니다.
"Filebeat DaemonSet의 paths 설정에 /var/log/pods/default_*/*/*.log, /var/log/pods/kube*_*/*/*.log, /var/log/pods/openshift*_*/*/*.log 를 지정하면 Pod 컨테이너 로그뿐만 아니라 Audit 로그, Linux auditd, systemd journald 로그까지 모두 수집할 수 있는가?"
결론부터 명확히 짚고 넘어가면, "그렇지 않다"입니다.
/var/log/pods/ 경로는 오직 Kubernetes Pod 내부 컨테이너의 표준 출력(stdout) 및 표준 오류(stderr) 로그만 적재되는 위치입니다. 위 세 가지 경로는 수집 대상 로그의 '종류'를 나눈 것이 아니라, Pod가 속한 Kubernetes Namespace 범위를 화이트리스트 형태로 한정한 것에 불과합니다.
따라서 OCP 클러스터의 전사적인 감사(Audit) 추적 및 노드 인프라 모니터링을 완벽하게 달성하려면 로그 유형별 물리적 저장 경로와 적절한 Filebeat Input 타입을 정확히 분리하여 설계해야 합니다.
2. /var/log/pods 디렉터리 구조 및 CRI 로그 포맷 분석
2.1 디렉터리 구조 및 네임스페이스 매핑
OCP Worker 및 Control Plane(Master) 노드의 로컬 디스크 상에서 /var/log/pods 디렉터리는 다음과 같은 정형화된 계층 구조를 갖습니다.
/var/log/pods/
└── <namespace>_<pod-name>_<pod-uid>/
└── <container-name>/
├── 0.log
├── 1.log
└── ...
| 경로 세그먼트 | 의미 및 설명 |
|---|---|
/var/log/pods/ |
해당 노드에 스케줄링되어 실행 중인 모든 Pod의 컨테이너 로그 루트 디렉터리 |
<namespace> |
Pod가 배포된 Kubernetes 네임스페이스 (예: default, kube-system, openshift-apiserver) |
<pod-name> |
Kubernetes Pod 리소스 이름 |
<pod-uid> |
K8s 클러스터 내에서 Pod를 식별하는 고유 UUID |
<container-name> |
Pod 스펙 내 정의된 컨테이너 이름 (Multi-container Pod인 경우 컨테이너별 디렉터리 분리) |
0.log, 1.log |
컨테이너 로그 파일. 인덱스 번호는 컨테이너 재시작(Restart) 횟수와 직결됨 |
2.2 CRI 로그 레코드 포맷 (CRI-O / containerd)
OCP의 기본 컨테이너 런타임인 CRI-O는 로그를 표준 CRI 포맷으로 기록합니다.
2026-11-11T10:20:30.123456789Z stdout F Application started on port 8080
2026-11-11T10:20:31.987654321Z stderr F [ERROR] Failed to establish database connection
- Timestamp: RFC3339 나노초 정밀도 타임스탬프
- Stream:
stdout또는stderr - Tag: 로그 레코드의 완결성 플래그 (
F: Full line - 개행으로 끝난 완전한 라인,P: Partial line - 버퍼 크기 초과로 다음 줄로 이어지는 분할 라인) - Log Message: 실제 애플리케이션 출력 문자열
2.3 제시된 세 가지 수집 경로의 실질적 한계
/var/log/pods/default_*/*/*.log: 오직default네임스페이스의 컨테이너만 수집합니다. 운영 환경의 비즈니스 앱(예:banking-core,cpm-agent,frontend등)이 별도 커스텀 네임스페이스에 배포된 경우 전량 누락됩니다./var/log/pods/kube*_*/*/*.log:kube-system,kube-public등 쿠버네티스 코어 네임스페이스에 Pod 형태로 기동된 컴포넌트 로그만 수집합니다./var/log/pods/openshift*_*/*/*.log:openshift-apiserver,openshift-ingress,openshift-monitoring등 OCP 플랫폼 및 오퍼레이터 Pod 로그를 수집합니다. OCP의 모든 로그가 아니라 OCP 네임스페이스 Pod의 컨테이너 로그에 국한됩니다.
3. 4대 핵심 로그 유형별 물리적 저장 위치 및 메커니즘 비교
OCP 클러스터의 전수 감시 체계를 수립하기 위해 반드시 구분해야 하는 4대 로그의 비교표입니다.
| 로그 유형 | 물리적 저장 위치 (RHCOS 노드) | 로그 성격 및 용도 | Filebeat 수집 방식 |
|---|---|---|---|
| Container Log | /var/log/pods/.../*.log |
Pod 컨테이너 stdout/stderr | filestream (container 파서) |
| K8s API Audit | /var/log/kube-apiserver/audit.log |
Kubernetes API 호출, 사용자 인증·인가, RBAC 감사 | filestream (JSON 파싱) |
| OCP API Audit | /var/log/openshift-apiserver/audit.log |
OpenShift 전용 API 확장 및 OAuth 로그인 감사 | filestream (JSON 파싱) |
| Linux auditd | /var/log/audit/audit.log |
호스트 OS(RHCOS) 커널 보안 이벤트, 시스템 콜, SELinux 거부 | filestream (auditd 파서) |
| systemd journald | systemd Journal 바이너리 로그 (/run/log/journal) |
kubelet.service, crio.service 등 노드 레벨 시스템 데몬 로그 |
journald 전용 input |
OCP Node (RHCOS) 파일시스템 구조
│
├── /var/log/
│ ├── pods/ ← [1] 컨테이너 로그 원본
│ │ ├── default_.../
│ │ ├── kube-system_.../
│ │ └── openshift-monitoring_.../
│ │
│ ├── containers/ ← pods 디렉터리를 가리키는 심볼릭 링크
│ │
│ ├── kube-apiserver/
│ │ └── audit.log ← [2] Kubernetes API Audit 로그
│ │
│ ├── openshift-apiserver/
│ │ └── audit.log ← [3] OpenShift API Audit 로그
│ │
│ └── audit/
│ └── audit.log ← [4] Linux OS auditd 로그
│
└── systemd Journal (바이너리 저장소) ← [5] journald input 대상
├── kubelet.service
├── crio.service
└── NetworkManager.service
4. 프로덕션 환경 Filebeat DaemonSet 권장 구성
컨테이너, K8s/OCP Audit, OS auditd, 노드 데몬 journald 로그를 단일 Filebeat 에이전트로 통합 수집하기 위한 filebeat.inputs 권장 YAML 템플릿입니다.
filebeat.inputs:
# =========================================================================
# 1. Container Logs (Pod stdout/stderr)
# =========================================================================
- type: filestream
id: ocp-container-logs
paths:
- /var/log/pods/*/*/*.log
prospector.scanner.symlinks: false
parsers:
- container:
stream: all
format: auto
processors:
- add_kubernetes_metadata:
host: "${NODE_NAME}"
matchers:
- logs_path:
logs_path: "/var/log/pods/"
# =========================================================================
# 2. Kubernetes & OpenShift API Audit Logs (Control Plane 노드)
# =========================================================================
- type: filestream
id: ocp-api-audit
paths:
- /var/log/kube-apiserver/audit.log
- /var/log/openshift-apiserver/audit.log
- /var/log/oauth-apiserver/audit.log
parsers:
- ndjson:
target: "audit"
overwrite_keys: true
# =========================================================================
# 3. Linux auditd Logs (Host OS 커널 보안 이벤트)
# =========================================================================
- type: filestream
id: ocp-linux-audit
paths:
- /var/log/audit/audit.log
parsers:
- auditd: ~
# =========================================================================
# 4. Systemd Journal Logs (Kubelet, CRI-O 서비스)
# =========================================================================
- type: journald
id: ocp-systemd-journald
seek: cursor
cursor_file:
path: /var/lib/filebeat/journald.cursor
units:
- kubelet.service
- crio.service
- NetworkManager.service
5. OCP 운영 시 핵심 체크리스트 & Best Practices
5.1 네임스페이스 하드코딩 지양 및 add_kubernetes_metadata 활용
paths에 네임스페이스 패턴(default_*, kube*_* 등)을 하드코딩하면 신규 서비스 배포 시 수집 누락이 발생합니다. 프로덕션 환경에서는 /var/log/pods/*/*/*.log로 광역 수집하되, Filebeat의 add_kubernetes_metadata 프로세서를 통해 레이블과 네임스페이스를 인덱싱 메타데이터로 부여한 뒤 Elasticsearch/OpenSearch 레벨에서 필터링하거나 라우팅하는 것이 훨씬 유연합니다.
5.2 심볼릭 링크 중복 수집 함정
/var/log/containers/에 존재하는 파일들은 사실 /var/log/pods/... 디렉터리의 실제 로그 파일을 가리키는 심볼릭 링크(Symbolic Link)입니다. 두 디렉터리를 동시에 paths에 등록하면 모든 컨테이너 로그가 2벌씩 중복 수집되어 스토리지 낭비와 인덱싱 부하를 초래합니다. /var/log/pods/ 하나만 지정하는 것을 권장합니다.
5.3 Control Plane 노드 스케줄링 및 권한 (SCC)
Audit 로그(/var/log/kube-apiserver/audit.log)는 Master/Control Plane 노드에만 존재합니다. 따라서 DaemonSet 스펙에 다음 Toleration을 반드시 명시해야 Control Plane 노드에도 Filebeat가 정상 배치됩니다.
tolerations:
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
또한 RHCOS 호스트의 /var/log 및 /run/log/journal을 hostPath로 마운트하여 읽기 위해서는 Filebeat ServiceAccount에 적절한 SCC(SecurityContextConstraints, privileged 또는 hostmount-anyuid) 권한이 부여되어야 합니다.
5.4 노드 현장 검증 실무 명령어
실제 OCP 노드에 접속하여 디렉터리 구조와 로그 생성 여부를 확인할 때 사용하는 유용한 명령어입니다.
# 1. 특정 노드의 디버그 파드 기동 및 호스트 루트 전환
oc debug node/<node-name>
chroot /host
# 2. pods 디렉터리 내 네임스페이스 분포 확인
find /var/log/pods -mindepth 1 -maxdepth 1 -type d | head -n 20
# 3. K8s / OCP Audit 로그 파일 존재 여부 확인
ls -lh /var/log/kube-apiserver/audit.log
ls -lh /var/log/openshift-apiserver/audit.log
# 4. journald 로그 동작 확인
journalctl -u crio.service -n 50 --no-pager
6. 수집 이후의 핵심: Journald 원천 로그의 Logstash 파싱 및 OpenSearch 스키마 매핑
Filebeat가 로그를 수집하여 전달하더라도, 실제 OpenSearch에 적재되는 최종 데이터가 온전한 Key-Value 구조를 갖추려면 반드시 거쳐야 하는 후속 파이프라인 단계가 있습니다. "컨테이너 및 감사 로그는 처음부터 완성된 JSON으로 출력되지 않는다"는 점을 이해하는 것이 핵심입니다.
6.1 원천 로그(Journald)의 실제 구조와 이중 계층 문제
Systemd Journal이 컨테이너 표준 출력(stdout/stderr)을 가로채어 기록할 때, 로그는 메타데이터와 본문(MESSAGE)의 혼합 구조로 저장됩니다.
- 저널 메타데이터:
CONTAINER_NAME(예:k8s_kube-apiserver_kube-apiserver-master-0_openshift-kube-apiserver_...),CONTAINER_ID_FULL,__REALTIME_TIMESTAMP,PRIORITY등 - MESSAGE 필드: 실제 로그 본문. 일반 텍스트이거나, OCP API Server 감사(Audit) 로그의 경우 JSON 객체가 통째로 이스케이프된 거대한 단일 문자열(String)로 들어있습니다.
만약 이를 Logstash 파싱 없이 OpenSearch로 그대로 던지면, MESSAGE 필드가 하나의 통짜 텍스트로 색인되어 내부의 verb, user.username, requestURI 등의 핵심 감사 키에 대한 정확한 일치 검색이나 집계가 완전히 불가능해집니다.
6.2 Logstash 파이프라인 설계 (Grok + JSON 디코딩 + Flattening)
Logstash에서는 grok 필터로 컨테이너 메타데이터를 정규화하고, json 필터로 내부 감사 메시지를 해체한 뒤 상위 필드로 끌어올립니다.
filter {
# 1. OCP 컨테이너 저널 로그 공통 처리: CONTAINER_NAME에서 네임스페이스, 파드, 컨테이너명 추출
if [CONTAINER_NAME] {
grok {
match => {
"CONTAINER_NAME" => "k8s_%{DATA:container_name}_%{DATA:pod_name}_%{DATA:namespace}_%{DATA:uid}_%{INT:attempt}"
}
tag_on_failure => ["_ocp_container_name_parse_failure"]
}
}
# 2. 대상 분기: OCP API Server 감사(Audit) 로그 인지 확인 (kube-apiserver 등)
if [container_name] == "kube-apiserver" or [TAG] =~ /audit/ {
# MESSAGE 필드 내부에 갇힌 JSON 문자열을 실제 객체로 디코딩
json {
source => "message"
target => "audit_event"
skip_on_invalid_json => true
}
# 3. 감사 로그의 주요 키들을 최상위로 끌어올려 스키마(Schema) 부여
if [audit_event] {
mutate {
add_field => {
"ocp_audit_level" => "%{[audit_event][level]}" # None, Metadata, Request, RequestResponse
"ocp_audit_verb" => "%{[audit_event][verb]}" # get, list, create, update, delete 등
"ocp_audit_uri" => "%{[audit_event][requestURI]}" # API 호출 URI
"ocp_audit_username" => "%{[audit_event][user][username]}" # 감사 요청 주체
"ocp_audit_stage" => "%{[audit_event][stage]}" # RequestReceived, ResponseComplete 등
}
# 불필요하게 거대한 중복 원본 필드 정리로 인덱싱 용량 절감
remove_field => ["[audit_event][objectRef]", "[audit_event][responseStatus]"]
}
}
} else {
# 4. 일반 컨테이너 로그 처리 (애플리케이션 자체 JSON 구조 언마샬링)
json {
source => "message"
target => "app_json"
skip_on_invalid_json => true
}
}
# 5. 저널 나노초 타임스탬프 동기화
if [__REALTIME_TIMESTAMP] {
ruby {
code => "
ts = event.get('__REALTIME_TIMESTAMP')
if ts
event.set('@timestamp', LogStash::Timestamp.at(ts.to_f / 1_000_000))
end
"
}
}
}
6.3 파싱 실패 시 페일러(Dead Letter Queue) 격리 라우팅 전략
로그 형식이 예기치 않게 변경되거나 손상되었을 때 파이프라인 전체가 중단되거나 OpenSearch 매핑 익셉션으로 로그가 통째로 드랍되는 사고를 막기 위해, Failure 태그 기반 라우팅을 적용합니다.
tag_on_failure => ["_ocp_grok_parse_failure"]: Grok 패턴 매칭 실패 시 태그를 부착해 원본 데이터를 보존한 채 다음 파이프로 전달합니다.- 조건부 출력 라우팅(
if "_ocp_grok_parse_failure" in [tags]): 실패한 원시 로그를 별도의 격리 인덱스(ocp-parse-failures-*)로 격리하여 주 인덱스의 매핑 오염을 방지하고 추후 재생(Replay)할 수 있도록 설계합니다.
6.4 OpenSearch Index Template (OCP 컨테이너 및 감사 로그 매핑 정의)
Logstash가 정제해 넘긴 키들이 OpenSearch에서 어떤 데이터 타입(Type)으로 고정될지 사전 정의하는 인덱스 템플릿입니다.
PUT _index_template/ocp-container-audit-template
{
"index_patterns": ["ocp-container-logs-*"],
"template": {
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1,
"refresh_interval": "5s"
},
"mappings": {
"properties": {
"@timestamp": { "type": "date" },
"namespace": { "type": "keyword" },
"pod_name": { "type": "keyword" },
"container_name": { "type": "keyword" },
"CONTAINER_ID_FULL": { "type": "keyword" },
"ocp_audit_level": { "type": "keyword" },
"ocp_audit_verb": { "type": "keyword" },
"ocp_audit_uri": {
"type": "text",
"fields": {
"keyword": { "type": "keyword", "ignore_above": 256 }
}
},
"ocp_audit_username": { "type": "keyword" },
"ocp_audit_stage": { "type": "keyword" },
"message": { "type": "text" }
}
}
}
}
기록일: 2026년 11월 12일
작성자: 예브게니 (OpenShift & Cloud Infra Engineering)
'IT' 카테고리의 다른 글
| [옵저버빌리티] OpenTelemetry(OTel) Collector 완벽 가이드: Metricbeat 286KB 최적화부터 Wazuh·APM·RUM·Heartbeat 대체 비교까지 (0) | 2026.11.12 |
|---|---|
| Windows 11 RDP 접속 중 화면은 갱신되는데 키보드·마우스 입력만 멈출 때: 원인 분석과 전원 관리(Modern Standby) 완벽 해결법 (0) | 2026.11.12 |
| 엘라스틱서치 8.5.2_우분투 2204 기본 설치 및 구성 (0) | 2026.08.31 |
| 알고리즘은 예측되어야 한다 (0) | 2026.08.31 |
| 온톨로지 개념 잡기: APP 서비스의 데이터를 똑똑하게 연결하는 방법 (0) | 2026.08.31 |
