기록 84편을 계약 에이전트로 다시 썼다. 기존 71편(kss 25 · virt 46)과, 계약에만 있고 안 쓰여 있던 새 글감 13편이다. 원장 84개를 열어 단계마다 스킬 영수증과 관문 종료 코드를 적었고 verify-pipeline-run.py 가 error 0 으로 닫는다. SSOT 결함 둘을 고쳤다. - kss 의 `약 58일` 이 반입 중 `약 59일` 로 바뀌어 있었다. 원 증거 파일이 「남은 일수: 88일 … 실제 갱신까지 약 58일」로 산수를 직접 적는다. D-4a 쪽 `약 59일` 은 강제 갱신 뒤(`VALID: 89 days`)라 맞는 값이라 그대로 뒀다. - virt §198 의 `11.6GB` 는 §178 의 원 측정 `Mem: 11648`(MiB)과 어긋나는데 원 가이드의 표기 그대로라 고치지 않고 쓰이는 자리에 대조를 적었다. 기록의 수치 오류 셋을 고쳤다 — CASE 요약의 「게스트 셋에 8240MB」(5120+3120 은 둘이다), k3s 편이 같은 것을 여섯·일곱·여덟로 세던 것, no-docker 편의 「셋을 더 든다」(§281 의 표는 네 행이고 디스크 행이 빠져 있었다). 계약을 셋 고쳤다. - kss 의 sourceRepository 리비전이 cdac9b8 이었는데 그 커밋에는 docs/guides/** 28개가 아예 없다. 9465582b 로 바꾸고, 반입한 바이트가 어느 커밋과도 같지 않다는 것을 측정값과 함께 적었다 — 반입은 커밋이 아니라 그 시점의 작업 트리에서 떠 온 것이다(kss 297/306 · virt 12/14 가 작업 트리와 같고, 200 커밋을 거슬러 전수 대조했을 때 가장 가까운 커밋도 28개가 어긋났다). - virt 계약이 「2026-09-11 재배분」이라고 적는데 SSOT 는 재배분 날짜를 적지 않고 재배분 뒤 값은 이미 2026-09-10 측정에 찍혀 있다. - kss 후보 대장이 지나친 절 아홉에 처분을 적었다(warn 9 → 0). 새 글감은 0건이고 넷은 앵커가 h3 슬러그의 접두가 아니라 중간 토막이라 검사기가 못 본 것이었다. style_profile.mjs 의 결함 둘을 고쳤다 — frontmatter 가 문장으로 세어져 (실측 398자짜리 「문장」 하나) 평균 길이를 기준 안으로 밀어 올리고 있었고, engPerSent 의 분자는 목록을 포함한 글에서, 분모는 목록을 걷어낸 글에서 세고 있었다(Question 기록에서 11.94 → 3.86). verify-pipeline.py 전 항목 PASS · error 0 · unittest 334건 OK. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
6.9 KiB
kind, slug, title, topic, topicName, project, status, decisionStatus, source, sourceRevision
| kind | slug | title | topic | topicName | project | status | decisionStatus | source | sourceRevision | |||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| PROJECT_DECISION | two-guest-vms-instead-of-installing-k3s-on-the-host | 호스트에 직접 깔지 않고 게스트 VM 두 대로 간다 — 관측자가 실험 대상과 함께 죽으면 안 된다 | lab-environment-build | 실험대 환경 구성 | virtualization | 게시 전 | ADOPTED |
|
9465582b5d1630eb4ae7c4e078021486919bf6b6 |
호스트에 직접 깔지 않고 게스트 VM 두 대로 간다 — 관측자가 실험 대상과 함께 죽으면 안 된다
k3s 를 게스트 VM 두 대에 나눠 깔고 물리 호스트는 진입점과 하이퍼바이저로만 남긴다. 머신이 한 대뿐이라 같은 커널에 두 노드를 올리면 노드 상실 실험이 성립하지 않고, 호스트가 노드를 겸하면 SSH 와 libvirt 와 nginx 가 실험 대상과 같이 내려간다.
근거
- 엣지 nginx 를 호스트에서 게스트 VM 으로 옮긴다 — 성능이 아니라 더러워지는 층의 격리 같은 논리를 엣지 한 층에 다시 적용한 결정이다. 그쪽은 게스트 구조가 이미 있다고 놓고 엣지가 어디 사는지를 정했고, 이쪽은 게스트 구조를 쓸 것인지를 정했다.
- lab host 에 가상화 패키지를 깔고 virsh 가 sudo 없이 돌게 만든다 이 결정이 요구한 첫 절차다. 호스트에 k3s 대신 libvirt 와 QEMU 가 깔리는 까닭을 이 결정이 댄다.
- k3s server 와 agent 를 게스트 두 대에 깔고 lab host 에서 kubectl 로 본다
결정을 실제로 실행한 절차다. server 와 agent 가 서로 다른 게스트로 들어가고
kubectl은 호스트에서 돈다. - Prometheus 와 Grafana 를 올려 클러스터 안을 밖에서 본다 관측 스택을 server 노드에 못박는 절차가 거기 있다. 관측자를 살려 둔다는 이유가 클러스터 안에서 한 번 더 쓰인다.
- lab host 에는 Docker 를 깔지 않는다 — 이미지 저장소가 갈리고, 그 위에 네트워크 변수가 하나 더 붙는다 호스트를 깨끗이 남긴다는 같은 축의 결정을 컨테이너 런타임 쪽에 적용한 것이다.
- 실험대를 껐다 켜고 게스트 메모리를 다시 나눈다
게스트로 갔기 때문에 가능해진 운영이다.
virsh setmaxmem으로 메모리를 다시 나누는 일은 호스트에 직접 깔았으면 생기지 않는다.
결정문
k3s server 를 게스트 kc-lab-1 에, agent 를 게스트 kc-lab-2 에 깐다. 물리 호스트 test-server 에는 nginx 와 libvirt/KVM 만 두고 k3s 를 설치하지 않는다.
2026-09-03 에 구축이 끝난 배치가 그 상태다. 게스트 둘이 virbr0 뒤에서 192.168.122.11 과 192.168.122.12 를 쓰고, 호스트에는 nginx 와 libvirt/KVM 만 있다. 나중에 엣지 게스트가 한 대 더 붙어 셋이 되는데, 그것은 엣지를 게스트로 옮긴 결정이 따로 받는다.
판단 이유
물리 머신이 한 대다. 그 한 대로 무엇을 재려 하는가가 이 판단을 갈랐다. §213 은 「나중에 반드시 다시 묻게 되는 판단이므로 근거를 남긴다」로 시작해 이유 여섯을 중요도 순으로 적는다.
독립 커널이 둘 필요하다 : 같은 커널에 k3s server 와 agent 를 올리면 노드가 이름뿐이라 노드 간 방화벽·파티션·노드 상실 실험이 성립하지 않는다 파괴 실험 후 복원 : VM 은 qcow2 오버레이를 지우면 몇 초 만에 초기 상태로 돌아가고, 호스트는 재설치 말고 되돌릴 방법이 없다 관측자를 살려 둔다 : 노드를 죽이는 실험인데 그 노드가 호스트면 SSH 와 libvirt 와 nginx 가 같이 죽는다 호스트 오염 방지 : k3s 는 nftables 규칙과 CNI(Container Network Interface, 컨테이너 네트워크 규격) 인터페이스, 커널 모듈, systemd 유닛을 대량으로 심는다 운영 배포판과 일치 : 호스트는 Arch 인데 운영 k3s 가 다른 배포판이면 커널과 systemd 차이가 잡음이 된다. 게스트를 운영과 같게 맞추면 그 잡음이 사라진다 netem 격리 : 커널이 분리되어 지연 주입이 게스트 안에 갇힌다. 호스트에서 걸면 SSH 까지 느려진다
견준 쪽은 호스트에 단일 노드 k3s 를 직접 까는 것이다. §213 은 그것을 정직한 반대편으로 직접 적었다 — 계약 검증(2홉 헤더, 쿠키/origin)만 볼 거라면 호스트 직접 설치로 충분하고 그게 더 빠르다. VM 경로가 필요해지는 것은 클러스터와 장애 실험부터다.
절충안도 하나 검토하고 채택하지 않았다. 호스트를 노드 1로 쓰고 VM 을 노드 2로 두는 방법이다. 게스트 운영체제 하나(약 350MB)와 설치 수고를 아끼는 대신 관측자 분리와 호스트 오염 방지를 포기하게 된다. 7.4Gi 예산에서 그 350MB 보다 관측자 분리가 더 값지다고 판단했다.
영향
실험 범위를 넓히는 대가로 구축 시간과 게스트 운영체제 몫의 메모리를 치렀다. 호스트에 단일 노드로 깔았으면 하루 안에 끝났을 구축이 게스트 생성과 cloud-init 과 k3s 설치로 나뉘었고, 게스트마다 커널과 systemd 가 따로 돌아 그만큼의 메모리를 쓴다.
얻은 것은 되돌릴 수 있는 실험대다. 노드를 죽여도 virsh start 로 되살아나고, 게스트를 통째로 지워도 base.qcow2 위에 오버레이를 다시 얹으면 몇 초 만에 초기 상태가 된다. 호스트의 인증서와 DNS 와 진입 설정은 그동안 한 번도 건드려지지 않는다.
같은 구분이 클러스터 안에서 한 번 더 나온다. k3s server 와 agent 는 죽였을 때가 다르다.
kc-lab-1(server) 를 죽이면 : kubectl 이 안 되고 DNS 와 인그레스도 사라진다
kc-lab-2(agent) 를 죽이면 : 그 노드의 워크로드만 사라지고 클러스터 제어는 살아 있다
그래서 노드 상실 실험은 agent 를 죽이는 것이고, server 를 죽이는 것은 노드 상실이 아니라 컨트롤 플레인 상실이다. §313 은 이 사실을 모르고 「keycloak 하나만 있는 노드를 죽이자」고 계획했다가 실제 배치를 조회한 뒤 정정했다고 적는다. 노드가 둘뿐이라 관측과 실험을 완전히 갈라놓을 수는 없으므로 §330 이 규칙으로 못박았다 — 관측 스택은 server 쪽에 두고 죽이지 않으며, 장애 주입은 agent 쪽에만 건다. nodeSelector 로 배치를 고정해야 그 규칙이 재현된다.
확인하지 않은 것이 하나 있다. 호스트 직접 설치와 게스트 두 대를 같은 실험으로 견준 측정은 이 저장소에 없다. 여섯 이유는 무엇이 성립하고 무엇이 성립하지 않는가에 대한 판단이고, 어느 쪽이 얼마나 느린지는 재지 않았다.