Skip to content

Commit 06b943d

Browse files
committed
로그 저장소 운영 전제 검증 보강
1 parent 5eaeb90 commit 06b943d

4 files changed

Lines changed: 68 additions & 5 deletions

File tree

docs/content/developer/infra/observability-improvement-plan/_index.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,17 @@ Kubernetes Pod 로그 수집은 Grafana Alloy와 Loki로 처리합니다. 클라
7272
- 수집 namespace: `code-place-dev`, `code-place-prod`, `monitoring`.
7373
- Grafana datasource: 기존 kube-prometheus-stack Grafana에 `Loki` datasource를 추가합니다.
7474

75-
이 구성은 클라우드 없는 단기 retention 기준선입니다. prod 로그량이 커지거나 로그 저장소 장애 도메인을 더 분리해야 하면, Loki는 내부에서 별도 운영하는 S3 호환 object storage, 예를 들어 독립 MinIO cluster, 로 이전합니다. Grafana Loki chart의 내장 MinIO subchart는 신규 운영 의존성으로 사용하지 않습니다.
75+
이 구성은 클라우드 없는 단기 retention 기준선입니다. Longhorn PVC는 hostPath/emptyDir보다 낫습니다. Kubernetes에서 lifecycle을 관리할 수 있고, PVC 사용률과 Longhorn volume health를 운영자가 볼 수 있기 때문입니다. 다만 durable log archive는 아니므로 장애 분석용 단기 저장소로만 취급합니다.
76+
77+
현재 유지해야 하는 로그 저장소 불변 조건은 다음과 같습니다.
78+
79+
- Loki deployment mode는 `Monolithic`입니다.
80+
- Loki storage type은 `filesystem`입니다.
81+
- Loki PVC storageClass는 `longhorn`, size는 `50Gi`입니다.
82+
- Loki retention은 dev 72h, prod 168h입니다.
83+
- Grafana Loki chart의 내장 MinIO subchart는 사용하지 않습니다.
84+
85+
prod 로그량이 커지면 먼저 noisy log를 줄이거나 retention을 줄입니다. 그래도 부족하면 Longhorn replica 상태와 node 여유 disk를 확인한 뒤 PVC를 증설합니다. 로그 저장소 장애 도메인을 더 분리해야 하면, Loki는 내부에서 별도 운영하는 S3 호환 object storage, 예를 들어 독립 MinIO cluster, 로 이전합니다.
7686

7787
### Tracing
7888

@@ -169,8 +179,9 @@ P1은 `group_wait=30s`, `repeat_interval=1h`로 전달합니다.
169179
6. Prometheus target에서 `backend` ServiceMonitor가 healthy인지 확인합니다.
170180
7. Grafana의 `CodePlace Overview` dashboard에서 request rate, 5xx, latency, submission status, waiting queue, judge heartbeat, Pod readiness/restart, CPU/memory, PVC, PostgreSQL/Redis readiness panel을 확인합니다.
171181
8. Grafana의 `CodePlace Logs` dashboard에서 Loki ready, Alloy node coverage, Loki PVC usage, 최근 backend error, judge/celery log panel을 확인합니다.
172-
9. Grafana Explore에서 `Loki` datasource를 선택하고 `{namespace="code-place-dev"}` 쿼리가 로그를 반환하는지 확인합니다.
173-
10. test alert 또는 임시 rule로 P0 webhook 수신 시간이 1분 이내인지 확인합니다.
182+
9. Grafana의 `CodePlace Logs` dashboard에서 `request_id` 변수에 실제 응답 header 또는 JSON log의 request ID를 넣고 해당 요청 로그가 좁혀지는지 확인합니다.
183+
10. Grafana Explore에서 `Loki` datasource를 선택하고 `{namespace="code-place-dev"}` 쿼리가 로그를 반환하는지 확인합니다.
184+
11. test alert 또는 임시 rule로 P0 webhook 수신 시간이 1분 이내인지 확인합니다.
174185

175186
운영 적용 전제는 다음과 같습니다.
176187

@@ -204,6 +215,7 @@ P1은 `group_wait=30s`, `repeat_interval=1h`로 전달합니다.
204215
- PrometheusRule shape check: P0/P1 interval, alert priority/severity, summary/description, duplicate alert namespace label.
205216
- AlertmanagerConfig shape check: groupBy, P0/P1 Discord receivers, webhook Secret reference.
206217
- kube-prometheus-stack values shape check: Prometheus selector policy, AlertmanagerConfig selector, Loki datasource, dashboard sidecar label.
218+
- Loki storage shape check: Monolithic mode, filesystem storage, Longhorn PVC, 50Gi size, dev/prod retention, MinIO disabled.
207219
- scrape resource shape check: ServiceMonitor/PodMonitor selector label, scrape path/port/interval.
208220
- Monitoring kustomization shape check: email fallback example이 기본 적용에 섞이지 않는지 확인.
209221
- Live cluster smoke check: `bash kubernetes/monitoring/smoke-check.sh`

kubernetes/monitoring/grafana-dashboard-logs.yaml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ data:
3131
"text": "code-place-dev",
3232
"value": "code-place-dev"
3333
}
34+
},
35+
{
36+
"name": "request_id",
37+
"type": "textbox",
38+
"query": ".*",
39+
"current": {
40+
"text": ".*",
41+
"value": ".*"
42+
}
3443
}
3544
]
3645
},
@@ -168,7 +177,7 @@ data:
168177
"dedupStrategy": "none"
169178
},
170179
"targets": [
171-
{"expr": "{namespace=~\"$namespace\"} |= \"request_id\""}
180+
{"expr": "{namespace=~\"$namespace\"} | json | request_id=~\"$request_id\""}
172181
]
173182
}
174183
]

kubernetes/monitoring/logs/README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ This directory contains Helm values for the Kubernetes logs stack.
77
- Retention: `code-place-dev` 3 days, `code-place-prod` 7 days.
88
- Monitoring: Loki and Alloy ServiceMonitors are enabled for kube-prometheus-stack.
99

10+
This is the selected baseline while cloud object storage is unavailable. Longhorn PVC is better than local hostPath or emptyDir because it gives Kubernetes-managed persistence and operationally visible volume health without introducing a new storage service. It is still not a durable log archive and should be treated as short-retention troubleshooting storage.
11+
1012
## Install or Upgrade
1113

1214
Install or upgrade kube-prometheus-stack first so the Prometheus Operator CRDs are present and the Grafana `Loki` datasource is provisioned. Then install Loki and Alloy.
@@ -73,4 +75,14 @@ Grafana should also show:
7375

7476
## Notes
7577

76-
This is not a horizontally scalable Loki design. It is the selected cloud-free baseline for short retention. If production log volume grows or logs must survive a node/PVC failure domain, move prod to an internally operated S3-compatible object store such as a separately managed MinIO cluster.
78+
This is not a horizontally scalable Loki design. It is the selected cloud-free baseline for short retention.
79+
80+
Keep these invariants unless the storage design changes intentionally:
81+
82+
- Loki stays in `Monolithic` deployment mode.
83+
- Loki uses filesystem storage on a Longhorn PVC.
84+
- The PVC size is explicit at `50Gi`, and `LokiPVCAlmostFull` alerts at 85%.
85+
- Retention stays short: dev 72h, prod 168h.
86+
- The Loki chart's MinIO subchart stays disabled. If object storage becomes available, use a separately operated S3-compatible service and migrate Loki storage deliberately.
87+
88+
If production log volume grows, first reduce noisy application logs or shorten retention. Increase the Longhorn PVC only after confirming available node storage and Longhorn replica health. If logs must survive a node/PVC failure domain, move prod to an internally operated S3-compatible object store such as a separately managed MinIO cluster.

kubernetes/monitoring/validate.sh

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,36 @@ if dashboard_sidecar.get("label") != "grafana_dashboard":
145145
raise SystemExit("Grafana dashboard sidecar must select grafana_dashboard label")
146146
print("KUBE-PROMETHEUS-STACK VALUES SHAPE OK")
147147
148+
loki_values = yaml.safe_load((root / "logs" / "loki-values.yaml").read_text())
149+
loki_config = loki_values.get("loki", {})
150+
if loki_values.get("deploymentMode") != "Monolithic":
151+
raise SystemExit("Loki must stay in Monolithic mode for the on-prem baseline")
152+
if loki_config.get("storage", {}).get("type") != "filesystem":
153+
raise SystemExit("Loki must use filesystem storage while cloud object storage is unavailable")
154+
if loki_config.get("commonConfig", {}).get("replication_factor") != 1:
155+
raise SystemExit("Loki single-binary filesystem storage must keep replication_factor=1")
156+
persistence = loki_values.get("singleBinary", {}).get("persistence", {})
157+
if not persistence.get("enabled"):
158+
raise SystemExit("Loki singleBinary persistence must be enabled")
159+
if persistence.get("storageClass") != "longhorn":
160+
raise SystemExit("Loki persistence must use Longhorn storageClass")
161+
if persistence.get("size") != "50Gi":
162+
raise SystemExit("Loki PVC size must stay explicit at 50Gi")
163+
limits = loki_config.get("limits_config", {})
164+
if limits.get("retention_period") != "168h":
165+
raise SystemExit("Loki default retention must be 168h")
166+
retention_by_selector = {
167+
stream.get("selector"): stream.get("period")
168+
for stream in limits.get("retention_stream", [])
169+
}
170+
if retention_by_selector.get('{namespace="code-place-dev"}') != "72h":
171+
raise SystemExit("Loki dev retention must be 72h")
172+
if retention_by_selector.get('{namespace="code-place-prod"}') != "168h":
173+
raise SystemExit("Loki prod retention must be 168h")
174+
if loki_values.get("minio", {}).get("enabled") is not False:
175+
raise SystemExit("Loki chart MinIO subchart must stay disabled")
176+
print("LOKI ON-PREM STORAGE SHAPE OK")
177+
148178
backend_sm = yaml.safe_load((root / "backend-service-monitor.yaml").read_text())
149179
if backend_sm.get("metadata", {}).get("labels", {}).get("release") != "kube-prometheus-stack":
150180
raise SystemExit("backend ServiceMonitor must keep release=kube-prometheus-stack label")

0 commit comments

Comments
 (0)