diff --git a/docs/session-lab-operations.md b/docs/session-lab-operations.md index 8b0c7ff..6c976ae 100644 --- a/docs/session-lab-operations.md +++ b/docs/session-lab-operations.md @@ -108,46 +108,121 @@ kubectl -n header-lab top pods **2026-09-03 기준, Keycloak 배포 전** -``` -lab host 총 7628MB · 사용 7227MB · 여유 400MB (+ swap 8GB) - ├ qemu #1 RSS 3765MB kc-lab-1 - └ qemu #2 RSS 2670MB kc-lab-2 +### 호스트 여유와 게스트 여유는 다르다 -kc-lab-1 CPU 4% 메모리 1774Mi / 3.4GB (51%) -kc-lab-2 CPU 1% 메모리 1032Mi / 2.4GB (41%) -echo 파드 각 150Mi -``` - -**호스트 여유가 400MB뿐이다.** 다만 QEMU RSS는 이미 게스트 할당 상한에 -근접했으므로 **앞으로 크게 늘지 않는다.** 압박은 호스트가 아니라 -**게스트 안에서** 생긴다. - -**다음 배포의 예상 소요** - -| 워크로드 | 예상 | -|---|---| -| Keycloak × 2 | 각 ~800Mi | -| PostgreSQL | ~300Mi | -| Redis | ~100Mi | -| 합계 | 약 2000Mi, 게스트당 ~1000Mi | +가장 오해하기 쉬운 지점이다. 호스트만 보면 절망적으로 보인다. ``` -kc-lab-1 1774 + 1000 ≈ 2774Mi / 3.4GB (80%) -kc-lab-2 1032 + 1000 ≈ 2032Mi / 2.4GB (84%) +lab host 총 7628MB · 사용 7189MB · 여유 439MB + ├ qemu #1 RSS 3765MB kc-lab-1 (할당 3584MB) → 상한 도달 + └ qemu #2 RSS 2633MB kc-lab-2 (할당 2560MB) → 상한 도달 ``` -**빠듯하지만 가능하다.** 여유가 필요하면 헤더 실험이 끝난 `header-lab` -네임스페이스를 지운다 — 파드 2개 × 150Mi가 회수된다. +그런데 게스트 안을 보면 여유가 있다. + +``` +kc-lab-1 총 3423MB · used 1464 · buff/cache 2020 · available 1959MB +kc-lab-2 총 2480MB · used 580 · buff/cache 1714 · available 1899MB + ───────────────── + 게스트 여유 합계 약 3.8GB +``` + +**왜 이런가** — QEMU의 RSS는 게스트가 **터치한 페이지**만큼이다. 게스트가 +메모리를 페이지 캐시로 다 채우면 QEMU RSS도 할당 상한까지 올라간다. +지금이 그 상태다. + +**그래서 앞으로 워크로드를 올려도 호스트 압박은 늘지 않는다.** 게스트 안의 +페이지 캐시가 밀려날 뿐이다. **QEMU RSS는 이미 천장이다.** + +``` +확인 방법: + ps -eo rss,args --sort=-rss | grep '[q]emu-system' # 호스트에서 본 VM + ssh kc-lab-1 free -m # 게스트 안 실제 + kubectl top nodes # working set +``` + +세 값이 다른 것을 보는 것이 이 실험대의 메모리 감각이다. + +### 배포 예산 + +| 워크로드 | 예상 | 배치 | +|---|---|---| +| Keycloak × 2 | 각 700Mi | 노드당 1개 | +| PostgreSQL | 300Mi | kc-lab-1 | +| Redis | 100Mi | kc-lab-2 | +| BFF × 2 | 각 400Mi | 노드당 1개 | +| **합계** | **약 2600Mi** | | + +**게스트 여유 3.8GB 중 2.6GB → 가능하다.** 다만 여기에 +Prometheus/Grafana(로드맵 10번 관측성)를 얹을 여유는 없다. + +### 대응 — 비용이 없는 것부터 + +**1. 끝난 실험은 지운다** ```bash -kubectl delete ns header-lab # 실험 종료 후 +kubectl delete ns header-lab # 파드 2개 × 150Mi 회수 +``` + +증거는 `docs/evidence/`에 남아 있으므로 워크로드를 유지할 이유가 없다. + +**2. Keycloak 힙을 명시적으로 제한한다** + +Keycloak은 기본값이 넉넉해 그냥 두면 1GB를 넘긴다. + +```yaml +env: + - name: JAVA_OPTS_KC_HEAP + value: "-Xms256m -Xmx512m" +resources: + limits: + memory: 768Mi ``` **모든 워크로드에 `resources.limits`를 반드시 건다.** 안 걸면 한 파드가 -게스트 메모리를 다 먹고 다른 파드까지 OOMKilled된다. 3.4GB / 2.4GB짜리 -게스트에서는 현실적인 위험이다. +게스트 메모리를 다 먹고 다른 파드까지 OOMKilled된다. ---- +**3. 실험을 순차로 돌린다 — 동시에 다 띄우지 않는다** + +``` +A층(Keycloak + PostgreSQL) → 결과 기록 → 정리 + ↓ +B층(BFF + Redis) → 결과 기록 → 정리 + ↓ +관측성(Prometheus) → 필요할 때만 +``` + +절약책이 아니라 **정상적인 실험 운영 방식**이다. 동시에 띄우면 변수가 +섞여서 원인 분리가 어려워진다. + +### swap은 쓰지 않는다 + +호스트에는 8GB swap이 있지만 **게스트에는 0MB이며, 그것이 맞다.** + +| 이유 | | +|---|---| +| k3s/kubelet | 기본적으로 swap 을 거부한다 | +| 성능 | 호스트 swap 으로 QEMU 페이지가 밀리면 급락한다 | +| **측정 오염** | 이 실험대는 **타이밍**(refresh 경쟁, Infinispan 복제 지연)을 잰다. swap 이 끼면 측정이 통째로 무의미해진다 | + +### 근본 해결 — 메모리 증설 + +남은 실험이 10개이고 관측성까지 하려면 증설이 가장 확실하다. + +```bash +sudo pacman -S dmidecode +sudo dmidecode -t memory | grep -E "Maximum Capacity|Number Of Devices|Size:|Locator:|Type:|Speed:" +``` + +| 슬롯 상태 | 조치 | +|---|---| +| 2슬롯 중 1개만 사용 | 동일 규격 8GB 추가 → 16GB | +| 온보드 8GB + 슬롯 1개 | 16GB 추가 → 24GB | +| 2슬롯 모두 사용 | 8GB × 2 를 16GB × 2 로 교체 | + +i5-1135G7(Tiger Lake)은 DDR4-3200 SO-DIMM을 쓰며 최대 용량은 보드마다 +다르므로 `Maximum Capacity` 값을 확인한다. **비용 대비 효과가 가장 크다** — +증설하면 Prometheus·Grafana·BFF 2 replica를 동시에 띄우고도 남는다. ## 3. 자주 쓰는 명령