Both pods go NotReady, the Service endpoint list empties and the front door returns 503, so adding Keycloak replicas buys nothing against database loss. The node holding the session in cache fails too, because a refresh writes LAST_SESSION_REFRESH. Recovery was automatic in about fifteen seconds with no restart, which is what readiness rather than liveness buys. The observability finding matters as much: up stayed at 1 through a total outage, so alerting on it would have caught nothing. kube-state-metrics is missing and pod readiness is therefore not recorded as a metric. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A-2 — PostgreSQL 정지 증거
2026-09-04 11:56–11:58 KST · Keycloak 26.7.0
해설: docs/experiment-a2-database-loss.md
| 파일 | 무엇을 보여주는가 |
|---|---|
01-baseline.txt |
정지 전 — 양쪽 Ready, cluster_size=2 |
02-setup-sessions.txt |
양쪽 노드에 세션 하나씩. 캐시는 각자 노드에만 |
03-four-paths.txt |
네 경로 전부 500. 캐시를 가진 노드도 실패 — refresh 는 쓰기다 |
04-health-and-service.txt |
전면 장애 증거 — Ready 파드 0개, ready 주소=[], 외부 503, database connections: DOWN. JWKS·.well-known 은 200 |
05-recovery.txt |
up=1 인 채로 503. DB 복귀 15초 후 재시작 0회로 자동 회복, 세션 5건 생존 |
a2-up-stayed-1-during-outage.png |
Grafana — up{job="keycloak"} 이 전면 장애 내내 1에 평평 |
핵심 세 줄
- DB 는 단일 장애점이다. Keycloak 을 몇 대로 늘려도 같이 죽는다 — Ready 파드 0개, 외부 503.
- 캐시는 읽기를 대신할 뿐 쓰기를 못 한다. refresh 는
UPDATE LAST_SESSION_REFRESH를 하므로 캐시가 있어도 실패한다. up은 이 장애를 못 잡는다. 알림은 readiness 와 외부 응답 코드에 걸어야 한다.