기록 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>
9.6 KiB
id, kind, slug, title, topic, topicName, project, status, studio, sourceRevision, source
| id | kind | slug | title | topic | topicName | project | status | studio | sourceRevision | source | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 68a848c7-eaff-4421-ad25-de21673ca40c | REFERENCE | bisect-the-packet-path-with-capture-points | packet 이 어디서 끊겼는지는 계층마다 capture 해서 가른다 | network-virtualization | 네트워크 가상화 | virtualization | 초안 | https://hyeonworks.com/studio/documents/68a848c7-eaff-4421-ad25-de21673ca40c/edit | no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다 |
|
packet 이 어디서 끊겼는지는 계층마다 capture 해서 가른다
가상 머신이 밖과 통신하지 못하면 게스트부터 뒤지지 말고 패킷이 지나야 할 네 지점에 캡처를 걸어 어디까지 보였는지로 구간을 좁힌다. 호스트의 물리 NIC(Network Interface Card) 와 브리지, 가상 머신에 붙은 TAP, 게스트 안의 인터페이스가 그 지점이다. 보이지 않은 첫 지점의 앞 구간이 의심 구간이 된다.
관계
- Guest 의 packet 이 Host Physical NIC 에 닿기까지 — virtio-net · virtqueue · vhost-net · TAP · Bridge 이 절차가 관측 지점으로 쓰는 계층을 세운 글이다. 어느 계층이 무엇을 하는지는 그쪽에 있다.
- Keycloak 실험 결과를 애플리케이션 원인으로 읽기 전에 network 계층을 따로 검증한다 그 기준은 문제가 네트워크인지 아닌지를 가르고, 이 절차는 네트워크 안에서 어느 구간인지를 가른다.
- 이 호스트의 가상 머신 네트워크는 Bridge 인가 NAT 인가 Routing 인가 캡처 지점 이름을 확정하는 첫 규칙이 그대로 이 물음의 확인 절차다.
- VM1 과 VM2 의 TAP/vnet interface 는 무엇이고 어디에 붙어 있는가 TAP 이름을 모르면 이 절차의 세 번째 지점에 캡처를 걸 수 없다.
- Host Nginx 에서 Keycloak 까지 packet 은 실제로 어디를 지나는가 그 경로를 처음 확인할 때 쓰는 절차다.
목적
이 기준은 두 가지를 막는다.
가상 머신이 통신하지 못할 때 게스트 안쪽과 애플리케이션부터 뒤지느라 호스트의 브리지와 TAP 연결을 늦게 보는 일이 하나다. 그 사이의 계층은 애플리케이션 로그에 아무것도 남기지 않는다.
오프로드 때문에 실제 wire 와 다르게 보이는 정상 패킷을 결함으로 판정하는 일이 다른 하나다.
이 순서는 물음 셋이 함께 쓴다. 이 호스트의 가상 머신 네트워크가 무엇으로 구성돼 있는지, TAP 인터페이스가 무엇인지, 호스트 Nginx 에서 Keycloak 까지 패킷이 어디를 지나는지 셋이 모두 이 순서 위에서 돈다. 그래서 세 곳에 같은 절차를 되풀이하지 않고 한 편에 두었다.
규칙
1. 캡처할 지점의 이름을 먼저 확정한다
관측 지점은 넷이다. 호스트의 물리 NIC, 호스트의 브리지, 가상 머신에 붙은 tap 또는 vnet, 그리고 게스트 안의 인터페이스.
이름을 모른 채 시작하면 없는 인터페이스에 캡처를 걸어 놓고 패킷이 안 보인다고 판정하게 된다.
인터페이스 목록은 ip link 로 본다. 브리지에 무엇이 붙어 있는지는 bridge link 와 bridge fdb show 가 알려 준다. tap 목록은 ip tuntap show 로 본다. 어느 가상 머신이 어느 tap 에 붙어 있는지는 virsh domiflist 에 도메인 이름을 붙여 확인한다. libvirt 가 만든 가상 네트워크가 무엇인지는 virsh net-list --all 과 virsh net-dumpxml 로 확인한다. 라우팅이 개입하는 구성이면 ip route 와 ip rule 도 함께 본다.
2. 네 지점에 같은 요청을 흘리면서 캡처를 건다
호스트에서는 물리 NIC 와 브리지, tap 또는 vnet 에 각각 tcpdump -ni 로 캡처를 건다. 게스트에서는 게스트 인터페이스에 같은 방식으로 건다.
3. 보이지 않은 첫 지점의 앞 구간을 의심 구간으로 삼는다
판독은 어느 지점까지 보였는가로만 한다.
물리 NIC 에 보이고 브리지에도 보이는데 tap 에 안 보이면, 게스트 내부보다 먼저 호스트의 브리지와 tap 연결을 의심한다.
tap 에는 보이는데 게스트 NIC 에 안 보이면 virtio 와 vhost, 게스트 NIC 계층을 의심한다.
게스트 NIC 에는 보이는데 소켓까지 오지 않으면 게스트의 라우팅과 방화벽, listen 상태를 의심한다.
4. 증상마다 다음에 볼 명령을 미리 정해 둔다
의심 구간이 나오면 그 구간의 증상에 맞는 확인으로 넘어간다.
가상 머신이 외부와 통신하지 못하거나 호스트와 통신하지 못하거나 특정 가상 머신만 통신하지 못하면 tap 과 브리지 연결을 본다. ip link, bridge link, bridge fdb show, virsh domiflist 가 그 확인이다.
같은 서브넷은 통신되는데 다른 서브넷이 안 되거나 게이트웨이까지는 가는데 외부 통신이 실패하면 라우팅을 본다. ip route 와 ip rule 이다.
가상 머신에서 인터넷으로 나가지 못하거나 외부에서 가상 머신에 접근하지 못하거나 특정 포트만 실패하면 nftables 와 iptables, NAT(Network Address Translation) 규칙, IP(Internet Protocol) forwarding 설정을 확인 대상으로 둔다.
이 실험대가 가장 오래 막힌 지점도 여기였다. 밖에서 온 요청만 엣지 게스트에 닿지 않았고, 거절한 것은 libvirt 가 자기 테이블의 guest_input 체인 끝에 둔 reject 규칙이었다(§180).
증상 셋을 각각 다른 기준으로 나누지 않은 것은 셋이 모두 어느 지점에서 끊겼는가 하나로 모이기 때문이다. 따로 적으면 같은 규칙의 부분 증상이 셋으로 늘어난다.
5. 패킷 크기와 체크섬이 예상과 다르다는 이유만으로 결함이라고 읽지 않는다
오프로드가 켜져 있으면 캡처에서 보이는 패킷 크기나 체크섬이 실제 wire 에서 보이는 것과 다르게 보일 수 있다. 원인 후보는 GSO(Generic Segmentation Offload), GRO(Generic Receive Offload), TSO(TCP Segmentation Offload), checksum offload 다.
크기와 체크섬이 예상과 다르면 오프로드 설정을 먼저 확인하고, 그 값만으로 판정하지 않는다.
6. 호스트의 L3 쪽에서 안 보이는 것을 곧바로 실패로 읽지 않는다
브리지가 L2 전달만 하는 경우 프레임이 호스트의 일반적인 L3 TCP/IP 스택을 반드시 거치지는 않는다. 한 가상 머신의 tap 에서 브리지를 지나 다른 가상 머신의 tap 으로 가는 경로가 그렇다.
호스트가 라우팅이나 NAT, host-local termination, 방화벽 역할을 할 때 L3 와 Netfilter 경로가 개입한다. 그래서 구성에 따라 호스트의 L3 관측에서 안 보이는 것이 정상이다.
7. 네 지점이 모두 보이는데 느리기만 한 경우는 이 절차가 답하지 않는다
이 절차가 가르는 것은 패킷이 어디서 끊겼는가다. 끊기지 않고 느리기만 하면 다른 기준으로 넘긴다.
적용 조건
KVM(Kernel-based Virtual Machine)/QEMU/libvirt 로 만든 가상 머신이 외부와 통신하지 못할 때.
특정 구간에서만 통신이 실패할 때.
실제 패킷 경로를 처음 확인할 때.
예외
오프로드가 켜진 구성에서는 패킷 크기와 체크섬이 그대로 증거가 되지 않는데, 다섯 번째 규칙이 그 경우다.
브리지가 L2 전달만 하는 구성에서는 호스트의 L3 관측에 안 보이는 것이 정상인데, 여섯 번째 규칙이 그 경우다.
네 지점이 모두 보이는데 느린 경우는 이 기준이 다루지 않는다. 「Keycloak 실험 결과를 애플리케이션 원인으로 읽기 전에 network 계층을 따로 검증한다」 쪽으로 넘긴다.
이 저장소에는 아직 이 절차를 실제로 돌린 출력이 없다. 여기 적은 판독은 원문 문서가 서술한 것이고 이 호스트의 캡처로 확인한 것이 아니다.
§180 의 사건에서도 구간을 좁힌 것은 네 지점 캡처가 아니었다. 호스트에서 친 curl 은 404 를 받는데 밖에서 친 curl 만 connection refused 를 받았다는 차이가 단서였고, 범인은 그 reject 규칙의 카운터가 4 패킷 240 바이트로 밖에서 친 횟수와 맞아떨어져서 확정했다.
예시
- 물리 NIC 에 보이고 브리지에도 보이는데 tap 에 안 보임 : 호스트의 브리지와 tap 연결을 먼저 확인한다
- tap 에 보이는데 게스트 NIC 에 안 보임 : virtio 와 vhost, 게스트 NIC 계층을 확인한다
- 게스트 NIC 에 보이는데 소켓까지 안 옴 : 게스트의 라우팅과 방화벽, listen 상태를 확인한다
- 특정 가상 머신만 통신 불가 : ip link 와 bridge link, virsh domiflist 로 그 가상 머신의 tap 이 브리지에 붙어 있는지 본다
- 같은 서브넷은 되고 다른 서브넷만 실패 : ip route 와 ip rule 을 본다
- 캡처에 보이는 패킷이 예상보다 크고 체크섬이 어긋남 : 오프로드 설정을 먼저 확인한다
- 네 지점이 모두 보이는데 응답만 느림 : 이 절차를 여기서 멈춘다