refactor: 문서 개선 중

This commit is contained in:
donghyeon-ka
2026-09-21 14:30:55 +09:00
parent c93cdea150
commit 805a18f486
1497 changed files with 525837 additions and 59152 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,23 +1,23 @@
{
"version": "1.1",
"id": "b5-b6-storage-and-keys",
"title": "볼륨 없는 영속화와 유예 없는 회전",
"question": "설정만으로 영속화와 무중단 키 교체가 되는가",
"title": "볼륨 없는 영속화와 replica별 키 회전",
"question": "설정을 켰다는 사실만으로 영속화와 일관된 키 회전을 기대할 수 있는가",
"type": "architecture",
"direction": "TB",
"direction": "LR",
"audience": [
"저장소와 키 회전을 운영하는 엔지니어"
],
"summary": "볼륨이 없으면 appendonly 설정은 장식이고, JWKS 캐시는 모르는 kid 를 만나면 곧바로 다시 가져온다.",
"alt": "Redis 의 데이터 디렉터리가 컨테이너 파일시스템일 때 영속화 설정이 무의미해지는 구성과, 새 kid 를 만난 검증기가 JWKS 를 재조회하는 구성.",
"long_description": "redis-cli config set appendonly yes 를 켜도 아무것도 달라지지 않았다. /data 가 컨테이너 파일시스템이라 컨테이너와 함께 죽기 때문이다. appendonlydir 이 만들어졌다가 그대로 버려진다. 볼륨 없는 영속화 설정은 장식이다. realm 키를 회전했을 때는 JWKS 캐시의 유예 구간을 기대했는데 없었다. NimbusJwtDecoder 는 모르는 kid 를 만나면 JWKS 를 다시 가져온다.",
"summary": "Redis AOF 는 볼륨이 없으면 컨테이너와 함께 사라진다. 키 회전 뒤에는 replica별 JWKS cache 상태가 달라 같은 옛 토큰이 401과 200을 번갈아 받았다.",
"alt": "운영 변경에서 Redis AOF는 볼륨 없는 데이터 디렉터리로 이어져 소멸하고, realm 키 회전은 replica별 JWKS cache 차이로 401과 200이 갈리는 두 경로.",
"long_description": "B-5에서는 appendonly yes 설정이 적용돼도 /data가 컨테이너 파일시스템이라 재시작 때 사라졌다. B-6에서는 옛 키를 지운 뒤 같은 토큰을 반복 요청하자 401과 200이 교대로 나왔다. echo replica 둘의 JWKS cache가 독립적이라 한쪽은 새 목록을 받아 옛 키를 잃었고 다른 쪽은 아직 들고 있었기 때문이다.",
"source_context": {
"document": "docs/keycloak-session-store/final/document.md",
"document_sha256": "1d44cba1905544d92f1d26ae36a8deb64a3db3914d6b488fd30d6ae7f8cfbabe",
"document_sha256": "28aef96a2bbb94fbb10ade26a71238fee62a5a4d9fa6e7749ae98cfd0a65e560",
"anchor": {
"kind": "heading",
"value": "B-5 · B-6 — 저장소 상실과 키 회전",
"line": 415
"line": 859
}
},
"composition": {
@@ -31,71 +31,91 @@
"groups": [],
"nodes": [
{
"id": "config",
"label": "appendonly yes",
"id": "change",
"label": "운영 변경",
"kind": "process",
"role": "source",
"emphasis": "warning",
"description": "설정은 적용된다.",
"emphasis": "normal",
"description": "저장 설정과 realm 키 회전을 각각 수행한다.",
"details": [
"redis-cli config set"
"B-5 · B-6"
],
"evidence": [
{
"start_line": 406,
"end_line": 412
"start_line": 861,
"end_line": 872
}
],
"assumption": false
},
{
"id": "datadir",
"label": "/data",
"label": "Redis /data",
"kind": "datastore",
"role": "control",
"emphasis": "warning",
"description": "컨테이너 파일시스템이다.",
"description": "AOF가 기록되는 컨테이너 파일시스템이다.",
"details": [
"appendonlydir"
"appendonly yes · 볼륨 없음"
],
"evidence": [
{
"start_line": 406,
"end_line": 412
"start_line": 861,
"end_line": 863
}
],
"assumption": false
},
{
"id": "container",
"label": "컨테이너",
"id": "lost",
"label": "Redis 재시작",
"kind": "component",
"role": "target",
"emphasis": "warning",
"description": "죽으면 /data 도 같이 사라진다.",
"description": "볼륨이 없어 데이터가 함께 사라진다.",
"details": [
"볼륨 없음"
"영속화 실패"
],
"evidence": [
{
"start_line": 406,
"end_line": 412
"start_line": 861,
"end_line": 863
}
],
"assumption": false
},
{
"id": "volume",
"label": "PersistentVolume",
"kind": "datastore",
"role": "target",
"emphasis": "primary",
"description": "여기 있어야 설정이 뜻을 갖는다.",
"details": [],
"id": "replicas",
"label": "echo replica 2개",
"kind": "service",
"role": "control",
"emphasis": "warning",
"description": "JWKS cache를 인스턴스마다 따로 가진다.",
"details": [
"replica별 cache"
],
"evidence": [
{
"start_line": 406,
"end_line": 412
"start_line": 868,
"end_line": 872
}
],
"assumption": false
},
{
"id": "mixed",
"label": "교차 응답",
"kind": "component",
"role": "target",
"emphasis": "primary",
"description": "같은 옛 토큰의 검증 결과가 replica에 따라 갈린다.",
"details": [
"401 · 200 · 반복"
],
"evidence": [
{
"start_line": 868,
"end_line": 877
}
],
"assumption": false
@@ -104,42 +124,56 @@
"edges": [
{
"id": "c-d",
"from": "config",
"from": "change",
"to": "datadir",
"label": "AOF 기록",
"label": "AOF 설정",
"kind": "write",
"evidence": [
{
"start_line": 406,
"end_line": 412
"start_line": 861,
"end_line": 863
}
],
"assumption": false
},
{
"id": "d-c",
"id": "d-l",
"from": "datadir",
"to": "container",
"label": "컨테이너와 함께 소멸",
"to": "lost",
"label": "볼륨 없음",
"kind": "blocked",
"evidence": [
{
"start_line": 406,
"end_line": 412
"start_line": 861,
"end_line": 863
}
],
"assumption": false
},
{
"id": "d-v",
"from": "datadir",
"to": "volume",
"label": "볼륨 마운트",
"kind": "write",
"id": "c-r",
"from": "change",
"to": "replicas",
"label": "키 회전",
"kind": "request",
"evidence": [
{
"start_line": 406,
"end_line": 412
"start_line": 865,
"end_line": 872
}
],
"assumption": false
},
{
"id": "r-m",
"from": "replicas",
"to": "mixed",
"label": "cache 상태",
"kind": "request",
"evidence": [
{
"start_line": 868,
"end_line": 877
}
],
"assumption": false
@@ -147,6 +181,6 @@
],
"legend": [],
"metadata": {
"rationale": "설정과 매체를 분리해 그렸다. 설정만 보면 두 경우 모두 되어 있는 것으로 읽힌다."
"rationale": "B-5와 B-6를 같은 실패로 합치지 않고, 설정이 실제 매체와 인스턴스별 cache에 닿을 때 각각 어떤 결과가 나는지 두 갈래로 연결했다."
}
}
}