{ "schemaVersion": 4, "project": "virtualization", "ssot": "final/document.md", "ssotSha256": "9146d6428ebdf2ab49f0fbd160e9526db93f48ca357bc8d281e753a999771f50", "sourceRevision": "no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다", "generatedAt": "2026-09-17", "sourceRepository": [ { "name": "반입한 개념 문서 (제1~4부)", "path": "/home/donghyeon/workspace/chat-gpt-container/document-haness/docs/virtualization/final/document.md", "revision": null, "verified": "이 프로젝트에는 분석한 저장소가 없다. 출발점은 사용자가 밖에서 쓴 문서 한 편이고, 체크아웃이 아니라 반입한 파일이 근거를 고정한다. 그래서 path 는 그 문서의 현재 자리인 final/document.md 다. 반입할 때의 원본(절 23개 · sha256 2b7b386de841f3e7b408066b39efaf183804b3d158d78d88e7fa0b7e00e08d69)은 source/kvm-cpu-virtualization-ssot.md 에 두었다가, 사용자가 §24~§28 을 더해 final/document.md 가 그 상위 집합이 된 뒤 지웠다 — heading marker 를 뺀 본문을 대조해 지워진 문장이 없음을 확인했다. 코드를 읽고 쓴 글이 아니라 고정할 커밋이 없어 revision 은 null 로 둔다. 지어내지 않는다." }, { "name": "실험대 저장소 (제5~6부)", "path": "/home/donghyeon/workspace/keycloak-pattern", "revision": "9465582b5d1630eb4ae7c4e078021486919bf6b6", "verified": "제5부와 제6부의 근거인 기반 7단계 가이드(source/docs/guides/00-lab-host ~ 06-observability)와 설정 원본(source/deploy/lab/edge/)이 이 저장소에서 반입됐다. 반입할 때 적어 둔 source/.source-revision 이 이 커밋이고, git cat-file 로 저장소에 실재함을 확인했다. 커밋 제목은 「chore: 실행 환경 구성 문서 추가 및 수정」이고 날짜는 2026-09-10 이다 (2026-09-12 확인). 제1~4부는 이 저장소에서 오지 않았다 — 그쪽 출처는 위 항목이다. **다만 반입한 바이트가 이 커밋과 같지는 않다** (2026-09-17 대조) — 반입 14개 가운데 이 커밋과 같은 것은 3개이고 11개가 다르다. 같은 14개를 저장소의 **작업 트리**와 견주면 12개가 같다. 즉 반입은 커밋이 아니라 **그 시점의 작업 트리**(미커밋 수정이 있던 상태)에서 떠 온 것이다. 남은 2개(docs/session-lab-concepts.md · docs/guides/04-tls/README.md)는 반입 뒤 저장소가 더 고친 파일이고 지금도 git status 가 M 으로 낸다. **맞는 커밋을 찾아봤고 없다** — HEAD 에서 200 커밋을 거슬러 전수 대조했을 때 가장 가까운 것도 9개가 어긋났다. 이 커밋은 「반입 시점의 HEAD」라는 뜻이지 「반입한 바이트가 이것이다」가 아니다" } ], "candidateScope": { "document": "final/document.md", "sections": [ "2. 전체 구조", "3. 각 구성요소의 역할", "4. vCPU와 vCPU Thread", "5. Host Linux Scheduler와 실제 CPU", "6. KVM_RUN과 Guest 실행", "7. VM Entry와 VM Exit", "8. 무엇이 실제로 VM Exit을 발생시키는가", "9. VM Exit 이후 처리", "10. Guest가 idle이면 물리 CPU는 어떻게 되는가", "11. VM의 4 vCPU는 정확히 무엇을 의미하는가", "12. CPU contention과 overcommit", "13. Steal Time", "14. 실제 Linux에서 확인할 수 있는 것", "15. CPU 가상화 관점에서 장애를 보는 방법", "16. 현재 Keycloak/K3s 실험과의 관계", "17. 동시성 테스트와 부하 테스트를 분리해야 한다", "18. Bare-metal K3s와 VM 기반 K3s의 차이", "19. 이 SSOT에서 파생될 CONCEPT", "20. 이 CONCEPT에서 파생되는 OPEN QUESTION", "21. OPEN QUESTION에서 CASE가 만들어지는 흐름", "22. 현재 단계의 핵심 Claim", "23. 다음 단계", "24. CPU 가상화 계층에서 발생할 수 있는 문제", "25. CPU 문제를 계층별로 구분하는 진단표", "26. 현재 Keycloak 실험에서 CPU 문제를 오판하지 않기 위한 기준", "27. 문제 영역에서 파생되는 추가 OPEN QUESTION", "28. CONCEPT -> OPEN QUESTION -> CASE 적용 기준", "29. 이 문서에서 먼저 고정할 전체 구조", "30. 일반 Linux의 Virtual Memory부터 시작한다", "31. Page와 Physical Frame", "32. Virtual Address = Page + Offset", "33. Guest Page Table", "34. MMU: 실제 주소 변환을 수행하는 CPU 하드웨어", "35. TLB: 주소 변환 결과의 CPU Cache", "36. Bare Metal과 VM의 차이", "37. EPT(Extended Page Tables)", "38. 왜 EPT가 필요한가", "39. Shadow Page Table과 EPT의 의미", "40. QEMU는 Guest RAM을 어떻게 준비하는가", "41. KVM_SET_USER_MEMORY_REGION", "42. Configured Memory와 실제 Physical RAM 사용량은 같지 않을 수 있다", "43. Guest Page Table 자체도 메모리에 있다", "44. 정상 Memory Access는 매번 VM Exit하지 않는다", "45. Guest Page Fault", "46. Page Fault의 대표적인 원인", "47. EPT Violation", "48. Guest Page Fault와 EPT Violation 비교", "49. Host Page Fault도 별도로 존재한다", "50. Huge Page가 필요한 이유", "51. Huge Page와 TLB Coverage", "52. VM에서 Huge Page를 볼 때 주의할 점", "53. THP: Transparent Huge Pages", "54. THP의 Trade-off", "55. HugeTLB", "56. THP와 HugeTLB 비교", "57. Memory Overcommit", "58. CPU Overcommit과 Memory Overcommit의 차이", "59. Host Memory Pressure와 Reclaim", "60. Host Swap이 VM에 미치는 영향", "61. Guest Swap과 Host Swap", "62. Memory Pressure와 Storage Contention의 연결", "63. Swap Used만 보고 장애를 판단하면 안 된다", "64. Ballooning이 필요한 이유", "65. virtio-balloon 구조", "66. Balloon Inflate", "67. Balloon Page 반환의 의미", "68. Balloon Deflate", "69. Ballooning을 과도하게 하면 Guest가 압박을 받는다", "70. Ballooning과 Memory Hotplug", "71. OOM", "72. Guest OOM과 Host OOM", "73. NUMA", "74. Local Memory와 Remote Memory", "75. vCPU와 NUMA의 연결", "76. vCPU Pinning만으로는 NUMA 최적화가 끝나지 않는다", "77. Guest NUMA", "78. NUMA는 실제 장비 topology부터 확인한다", "79. 전체 Memory Virtualization 실행 경로", "80. 전체 Memory Virtualization 관리 경로", "81. CPU / Network / Storage / Memory 연결", "82. 핵심 Claim Registry", "83. 실제 환경에서 확인할 OPEN QUESTION", "84. 권장 실험 순서", "85. 실험 시 반드시 같이 기록할 것", "86. 문제를 진단할 때의 분류", "87. 최종 기준 그림", "88. 결론", "89. 문서 목적", "90. virsh / libvirt / virtio 구분", "91. virtio-net은 정확히 어디에 있는가", "92. Frontend와 Backend", "93. Guest OS는 왜 QEMU가 아니라 virtio-net을 사용하는가", "94. 전체 네트워크 계층", "95. Physical NIC의 역할", "96. Linux Bridge의 역할", "97. Routing의 역할", "98. NAT의 역할", "99. TAP의 역할", "100. virtqueue의 역할", "101. Guest TCP/IP Stack의 역할", "102. Packet이 Keycloak까지 올라오는 과정", "103. QEMU virtio Device Model의 역할", "104. 왜 `TAP → vhost-net → QEMU → virtqueue`라고 일반화하면 안 되는가", "105. Control Path와 Data Path", "106. QEMU가 Userspace인데 packet이 QEMU를 안 거칠 수 있는 이유", "107. vhost-net 최적화", "108. vhost-net은 QEMU를 제거하지 않는다", "109. Fast Path와 Slow/Control Path", "110. Data Copy 최적화", "111. Interrupt / Notification 최적화", "112. Multi-Queue 최적화", "113. Offload 최적화", "114. Linux Bridge가 항상 Host TCP/IP Stack을 거치는 것은 아니다", "115. Host Physical NIC로 나갈 때 virtio를 다시 거치지 않는다", "116. 현재 Keycloak/K3s 테스트 환경과 연결", "117. 이 구조에서 발생할 수 있는 문제", "118. 실제 Linux에서 확인할 명령어", "119. 실제 packet path 추적", "120. Keycloak Refresh Token 실험과의 관계", "121. 이 SSOT에서 파생될 CONCEPT", "122. OPEN QUESTION", "123. OPEN QUESTION → CASE", "124. 핵심 Claim", "125. 최종 기준 구조", "126. 다음 실습 순서", "127. 문서 목적", "128. 전체 구조", "129. Guest Application: `read()` / `write()`에서 시작", "130. VFS: 공통 파일 인터페이스 계층", "131. Filesystem(ext4/XFS): 파일 세계를 block 공간에 배치", "132. inode", "133. Page Cache: `write()`가 바로 SSD write는 아니다", "134. Guest Block I/O Layer", "135. `/dev/vda`: Guest가 보는 가상 Block Device", "136. `/dev/vda`와 Filesystem 관계", "137. virtio-blk: Guest의 가상 Block Device Driver", "138. virtio-blk와 virtqueue", "139. virtqueue의 실제 의미", "140. VM Boundary를 넘으면 QEMU가 등장", "141. QEMU가 물리 SSD를 직접 제어하는 것은 아니다", "142. qcow2: Host에서는 파일, Guest에서는 디스크", "143. qcow2 Virtual Size와 실제 Host 사용량", "144. RAW Image", "145. Host Block Device를 직접 backend로 사용 가능", "146. 실제 연결 확인", "147. VM에서는 Page Cache가 두 번 나타날 수 있다", "148. `write()` 완료와 영속화는 다르다", "149. Direct I/O", "150. `fsync()`가 필요한 이유", "151. FLUSH", "152. 가장 위험한 상황: 거짓 완료", "153. QEMU Cache Mode", "154. `cache=none`", "155. `cache=writeback`", "156. `writeback = 위험`이라고 단정하면 안 되는 이유", "157. Device-side Cache", "158. Host Block Layer", "159. 여러 VM이 하나의 NVMe를 공유하면", "160. blk-mq: Multi-Queue Block Layer", "161. I/O Scheduler", "162. `none`", "163. 실제 I/O Scheduler 확인", "164. NVMe Driver와 Physical Device", "165. NVMe와 SSD 구분", "166. Storage I/O Completion", "167. Storage Contention", "168. CPU가 정상이어도 Storage 때문에 느릴 수 있다", "169. Storage 관측 명령어", "170. PostgreSQL 예시: WAL과 Durability", "171. 성능과 Durability의 Trade-off", "172. Storage Virtualization Canonical Flow", "173. Network Virtualization과 비교", "174. 핵심 Claim", "175. 실제 테스트 서버에서 확인할 Open Questions", "176. 권장 실습 흐름", "177. 최종 요약", "178. 이 부의 출처와 범위", "179. 엣지를 물리 호스트에서 VM 으로 옮기면 무엇이 새로 필요해지나", "180. nftables 는 앞 체인의 `accept` 로 뒤 체인의 `reject` 를 막지 못한다", "181. qcow2 가 담는 것과 담지 않는 것", "182. 이 구축에서 드러난 문서 결함의 공통 원인", "183. 이 부에서 파생될 OPEN QUESTION", "184. 이 부의 출처와 범위", "185. 가이드 묶음이 스스로 정한 규약", "186. 단계 00 — lab host 가상화 준비", "187. 단계 01 — 게스트 세 대", "188. 단계 02 — k3s server 와 agent", "189. 단계 03 — 엣지 nginx 라우팅과 호스트 DNAT", "190. 단계 04 — Let's Encrypt 와 인증서 갱신", "191. 단계 05 — Keycloak 2노드와 PostgreSQL", "192. 단계 06 — Prometheus 와 Grafana", "193. 이 구축이 제1~4부의 어느 구조에 닿나", "194. 이 부에서 파생될 OPEN QUESTION", "195. 이 부의 출처와 범위", "196. 이 문서가 무엇인가", "197. 측정 환경", "198. 자원 — 할당과 실사용은 다르다", "199. 디스크 — 오버레이는 얼마나 쓰나", "200. 부팅 — cloud-init 은 얼마나 걸리나", "201. 네트워크 — DHCP 예약의 실제 동작", "202. 철거 — 실제 출력 전문", "203. 실측으로 드러난 함정 셋", "204. 재구축할 때 무엇이 남아 있나", "206. 이 부의 출처와 범위", "207. `lab-edge-dnat.nft` — DNAT 파일이 자기 안에 적어 둔 네 가지", "208. `lab-edge-dnat.service` — `ExecStartPost` 앞의 `-` 가 무엇을 봐주나", "209. `nginx-keycloak-lab.conf` — 스티키 스위치와 신뢰 경계", "210. `reload-nginx.sh` — `deploy/` 와 `post/` 를 가르는 한 줄", "211. 이 부의 출처와 범위", "212. \"이건 Arch라서 하는 건가?\"에 대한 답", "213. 왜 호스트에 직접 깔지 않고 VM 2대인가", "214. 전체 구조 한눈에 보기", "215. VM 한 대의 디스크 구성", "216. 설정 파일이 게스트에 도달하는 경로", "217. 부팅할 때 일어나는 일", "218. 실험대 전체 배치 (2026-09-03 구축 완료, 실측값)", "219. 1층. 가상화", "220. VT-x / AMD-V (하드웨어 가상화 확장)", "221. KVM", "222. QEMU", "223. libvirt / virsh / libvirtd", "224. 연결 URI — `qemu:///system` vs `qemu:///session`", "225. 보조 그룹과 재로그인", "226. 멱등성과 `&&` 단축 평가", "227. systemd 소켓 활성화 (`libvirtd.socket`)", "228. qcow2와 backing store (오버레이)", "229. 왜 OS를 설치하지 않아도 VM이 뜨는가", "230. 디스크 이미지를 \"복사한다\"는 것의 실제 원리", "231. qcow2 파일 내부는 어떻게 생겼나 — 매핑표가 전부다", "232. `qemu-img` 와 `qemu-system-x86_64` 는 다른 도구다", "233. 오버레이는 Docker 레이어와 같은 아이디어다", "234. 그래서 마이그레이션과 스냅샷이 된다", "235. multipass, virt-install, virsh — 무엇이 다른가", "236. 클라우드 이미지와 cloud-init", "237. 확정된 함정: `--cloud-init` + Debian `genericcloud` 조합은 동작하지 않는다", "238. 시드 ISO 를 굽는 세 명령이 각각 하는 일", "239. 시드 디렉터리 구조와 파일명 규칙", "240. 진단 도구: `virsh screenshot`", "241. base 이미지가 무엇인지 확인하는 법", "242. UEFI / OVMF (`edk2-ovmf`)", "243. `--os-variant` / osinfo", "244. 2층. 가상 네트워크", "245. libvirt `default` 네트워크와 `virbr0`", "246. dnsmasq (libvirt 내장 DHCP/DNS)", "247. DHCP 예약 (`ip-dhcp-host`)과 MAC `52:54:00`", "248. `--live --config`", "249. NAT vs 브리지 vs macvtap", "250. WiFi에서 브리지가 안 되는 이유", "251. SSH 키는 \"머신\"이 아니라 \"홉\" 단위다", "252. `~/.ssh/config`의 first-match-wins 규칙", "253. `/etc/hosts`와 이름 해석 순서", "254. 엣지를 물리 호스트에서 VM 으로 옮기면 무엇이 새로 필요해지나", "255. nftables 는 앞 체인의 `accept` 로 뒤 체인의 `reject` 를 막지 못한다", "256. 3층. 호스트 진입", "257. 리버스 프록시와 `upstream`", "258. 왜 TLS를 끊어서 내용을 보는가", "259. `X-Forwarded-*`와 신뢰 경계", "260. 스티키 세션", "261. 진입점 자체가 죽으면 — 로드밸런서의 재귀 문제", "262. `nginx -t`", "263. 4층. TLS", "264. ACME", "265. 도메인 검증: HTTP-01 vs DNS-01", "266. DNS-01 은 언제 쓰는가 — 네 가지 경우", "267. `fullchain.pem` / `privkey.pem` / `cert.pem` / `chain.pem`", "268. 공개 DNS에 사설 IP를 넣는 것", "269. 5층. k3s", "270. k3s server / agent / node-token", "271. `--node-ip` / `--tls-san`", "272. kubeconfig의 `127.0.0.1` 문제", "273. agent 노드에는 kubeconfig가 없다 — `localhost:8080` 오류", "274. Traefik (k3s 기본 ingress)", "275. 호스트 nginx와 Traefik은 무엇이 다른가 — 둘 다 필요한 이유", "276. servicelb (klipper-lb)", "277. flannel VXLAN", "278. NetworkPolicy와 k3s의 내장 컨트롤러", "279. 매니페스트 읽는 법 — `deploy/lab/k8s/echo.yaml`을 예로", "280. 무엇을 어디에 설치하는가", "281. Docker를 lab host에 설치하면 안 되는 이유", "282. 그러면 이미지는 어떻게 넣는가", "283. 6층. Arch 특이사항", "284. nginx 설정 구조 — `sites-available`은 nginx 기능이 아니다", "285. 롤링 릴리스와 부분 업그레이드 금지", "286. 패키지명 대응표", "287. 없어서 오히려 편한 것", "288. 게스트 배포판: Debian이란 무엇이고 Ubuntu와 무엇이 다른가", "289. 7층. git", "290. `.gitignore` 패턴 앵커링", "291. 이미 추적 중인 파일은 무시되지 않는다", "292. 8층. 패키지 저장소와 설치 원리", "293. 저장소(repository)란 무엇인가", "294. 설치는 다섯 단계로 진행된다", "295. apt (Debian / Ubuntu)", "296. pacman (Arch)", "297. 왜 HTTP로 받아도 안전한가 — 서명 신뢰 사슬", "298. 세 배포판 대조표", "299. 이 실험대에서 어디에 나타나는가", "300. 9층. `deploy/` — 무엇이 살아 있고 무엇이 참조인가", "301. 전체 지도", "302. 왜 적용하지 않는 것을 남겨두는가", "303. `reverse-proxy/` — 1홉 계약의 원본", "304. `tls/` — 같은 일을 하는 두 구현", "305. `tunnel/` — 채택하지 않은 이유를 남긴 자산", "306. `.example` 접미사 관례", "307. 10층. 쿠버네티스 리소스 — 이 실험대에서 실제로 쓴 것들", "308. 워크로드 세 종류 — 무엇을 언제 쓰는가", "309. 저장소 — PVC · PV · StorageClass", "310. Secret — 감춰지지 않는다", "311. RBAC — ServiceAccount · ClusterRole · Binding", "312. 배치 제어 — nodeSelector · 라벨 · taint", "313. k3s server와 agent — 죽였을 때가 다르다", "314. 11층. Keycloak 클러스터링 내부 — Infinispan과 JGroups", "315. 두 층으로 되어 있다", "316. 디스커버리와 트랜스포트는 다른 경로다", "317. 코디네이터", "318. 클러스터 뷰", "319. 주요 JGroups 프로토콜 — 지표 이름에 그대로 나온다", "320. 세션은 어디에 있는가 — 두 곳이되 역할이 다르다", "321. 세션 쓰기 트랜잭션의 세 가지 설계 결정", "322. 12층. 관측성 — Prometheus의 구조", "323. 세 부분으로 되어 있다", "324. exporter 패턴", "325. 서비스 디스커버리 — 타깃을 적어두지 않는다", "326. relabel — 걸러내고 이름을 붙인다", "327. 메트릭 타입", "328. `up` — 가장 중요한 합성 지표", "329. TSDB와 보존 기간", "330. 관측 시스템의 장애 도메인", "331. 13층. 가상화 운영 — 실행 중 바꾸는 것들", "332. VM 메모리 재배분 — 게스트를 다시 만들지 않는다", "333. 안전한 종료 순서", "334. 복구 순서 — 종료의 역순", "335. qcow2 파일을 다른 물리 서버로 옮기면 무엇이 따라가나" ], "excluded": [ "1. 이 문서의 범위", "205. 관련 문서", "336. 아직 기록하지 않은 개념", "337. 이번에 채운 것 (2026-09-11)", "338. 이번에 채운 것 (2026-09-04)" ], "excludedAnchorPattern": "#(1-이-문서의-범위|205-관련-문서|336-아직-기록하지-않은-개념|337-이번에-채운-것-2026-09-11|338-이번에-채운-것-2026-09-04)$", "note": "접어 넣은 분석이 아니라 처음부터 한 편으로 쓴 개념 문서라 제2부·제3부가 없다. 대신 이 문서 자신이 네 부다 — 제1부 CPU 가상화(§1~§28) · 제2부 메모리 가상화(§29~§88) · 제3부 네트워크 가상화(§89~§126) · 제4부 스토리지 가상화(§127~§177). 네 부 모두가 후보를 찾는 범위이고 sections 는 그 절 제목을 부 순서대로 적는다. 지금 sections 에 있는 것은 제1부 §2~§28 과 제2부 §29~§88 이고, 제3부와 제4부는 그 부를 분해할 때 같은 형식으로 뒤에 덧붙인다. §1 은 이 문서가 무엇을 다루고 무엇을 안 다루는지를 선언한 자리라 후보가 나오는 곳이 아니다 — 글감이 그 선언을 근거로 인용할 수는 있어서 concept 노드의 source 에는 들어 있고, excludedAnchorPattern 은 §1 만 가리키는 앵커로 올라온 글감을 막는다. 앵커 형식은 `final/document.md#