기록 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>
13 KiB
id, kind, slug, title, topic, topicName, project, status, questionStatus, studio, sourceRevision, source
| id | kind | slug | title | topic | topicName | project | status | questionStatus | studio | sourceRevision | source | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 38716d7f-1aa1-48d8-ab4c-3fc505332128 | QUESTION | vm-network-mode-bridge-nat-or-routed | 이 호스트의 가상 머신 네트워크는 Bridge 인가 NAT 인가 Routing 인가 | network-virtualization | 네트워크 가상화 | virtualization | 초안 | OPEN | https://hyeonworks.com/studio/documents/38716d7f-1aa1-48d8-ab4c-3fc505332128/edit | no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다 |
|
이 호스트의 가상 머신 네트워크는 Bridge 인가 NAT 인가 Routing 인가
이 실험대는 NAT(Network Address Translation, 네트워크 주소 변환) 를 쓴다. 이더넷 없이 WiFi 만 있어 브리지를 못 쓴다고 §178 이 관측으로 적었다. §249 가 세 모드를 견준 표에서 브리지와 macvtap 은 둘 다 「WiFi라 불가」이고 채택 표시는 NAT 한 줄에만 붙어 있다. 감수한 것도 같은 표에 적혀 있다 — VM 주소가 사설이라 LAN 에서 VM 으로 바로 들어가지 못하고 포워딩이 필요하다. 엣지를 게스트로 옮긴 뒤 호스트 커널 DNAT(Destination NAT, 목적지 주소 변환) 와 libvirt 체인의 구멍이 새로 필요해진 것이 그 포워딩이다. 다만 §122 OQ-1 이 요구한 다섯 명령의 출력이 없어 virbr0 에 무엇이 붙어 있고 라우팅이 어떻게 걸려 있는지는 아직 적지 못한다.
관계
- Guest 의 packet 이 Host Physical NIC 에 닿기까지 — virtio-net · virtqueue · vhost-net · TAP · Bridge 그 경로 그림에서 TAP 과 Physical NIC 사이에 놓인 계층이 이 물음이 확정하려는 부분이다.
- packet 이 어디서 끊겼는지는 계층마다 capture 해서 가른다 구성이 무엇이냐에 따라 캡처를 걸 계층의 이름이 달라진다.
- VM1 과 VM2 의 TAP/vnet interface 는 무엇이고 어디에 붙어 있는가 ip link 와 bridge link 를 두 물음이 같이 쓰므로 한 번 찍어 둘을 함께 읽는다.
- Host Nginx 에서 Keycloak 까지 packet 은 실제로 어디를 지나는가 이 물음이 닫혀야 그 추적에서 tcpdump 를 걸 대상이 정해진다.
사실
- §96 은 Linux Bridge 를 호스트 커널 안의 L2 소프트웨어 스위치로 적었다. 이더넷 프레임의 Destination MAC 을 보고 어느 포트로 보낼지 정하고, MAC learning 을 하며, 여러 가상 포트와 물리 포트를 잇는다.
- §97 은 Routing 을 L3 에서 IP 를 보고 내리는 결정으로 놓았다. Bridge 가 같은 이더넷 네트워크를 잇는 것과 달리 Routing 은 서로 다른 IP 네트워크를 잇고, 목적지 IP 를 보고 어느 인터페이스나 next-hop 으로 보낼지 정한다.
- §98 은 NAT 을 패킷의 IP 와 포트 정보를 바꾸는 것으로 놓고, 가상 머신이 사설 서브넷을 쓰면 호스트가 NAT 게이트웨이처럼 동작할 수 있다는 예를 들었다. VM : 192.168.122.10 Host NAT 를 지난 뒤 : 203.0.113.10
- §96 과 §97 은 절 끝에 확인 명령을 달았다. §96 은 bridge link · bridge fdb show · ip link show type bridge 를, §97 은 ip route 를 들었다. 셋을 구분하라고 적은 §98 에는 확인 명령이 없다.
- §114 는 Bridge 가 단순 L2 forwarding 만 하는 구성이면 프레임이 호스트의 일반적인 L3 TCP/IP 스택을 지나지 않고 다른 TAP 으로 나갈 수 있다고 적었다. 호스트가 Routing · NAT · Host-local termination · Firewall 을 맡으면 그때는 L3/Netfilter 경로가 끼어든다.
- 그래서 §114 는 Physical NIC → Host TCP/IP Stack → Bridge 를 고정된 패킷 경로로 보면 안 되고, 실제 경로는 bridge/routing/NAT 구성에 따라 달라진다고 못 박았다.
- §94 는 이 문서가 기준으로 삼은 구조를 virtio-net + vhost-net + TAP + Linux Bridge 로 적었다. 실제 환경은 Bridge · NAT · Routed Network · macvtap · SR-IOV · VFIO passthrough · Open vSwitch · Kubernetes CNI 에 따라 달라질 수 있다고 덧붙였다.
- 확인할 명령은 §122 OQ-1 이 다섯 줄로 적어 두었다. 정의된 가상 네트워크 열거 : virsh net-list --all 그 가상 네트워크의 정의 읽기 : virsh net-dumpxml 에 이름을 넣는다 호스트 인터페이스 목록 : ip link 어느 인터페이스가 어느 브리지의 포트인지 : bridge link 라우팅 테이블 : ip route
- §118 이 같은 계층에 든 명령 가운데 virsh net-info 와 ip rule 은 OQ-1 의 다섯 줄에 없다.
- §178 은 이 실험대의 대상 환경을 관측으로 적었다. test-server 는 Arch Linux 이고 이더넷 없이 WiFi 만 있어 브리지를 못 쓴다. 그래서 libvirt NAT(virbr0) 과 호스트 진입 구조를 택했고, 게스트는 Debian 12 genericcloud 3대로 엣지 1대와 k3s 2노드다.
- §250 은 WiFi 에서 브리지가 안 되는 이유를 적었다. 802.11 데이터 프레임은 기본적으로 주소 필드가 3개다(3-address 모드). AP(Access Point, 무선 접속 장치)는 연결(association)된 단말(station)의 MAC 만 알고 있어서, 그 단말이 자기 것이 아닌 출발지 MAC 을 단 프레임을 보내면 버린다. 브리지된 가상 머신은 자기 MAC 을 출발지로 쓰므로 정확히 그런 프레임을 보낸다.
- §250 이 든 우회 수단은 둘이다. 4-address 모드(WDS) : AP 와 클라이언트 드라이버가 모두 지원해야 하는데 실제로는 거의 지원되지 않는다 USB 이더넷 어댑터를 꽂는 것 : 현실적인 우회
- §250 은 test-server 에 이더넷이 없고 wlo1 만 있어서 「VM 에 LAN IP 를 직접 주자」는 계획이 물리적으로 성립하지 않는다고 적었다. 이 제약 하나가 토폴로지 전체를 NAT + 호스트 nginx 로 확정시켰다고 밝혔다. 이더넷 인터페이스가 있는지는 ip -brief link 로 보고 무선 인터페이스 정보는 iw dev 로 본다고 확인 명령을 달았다.
- §249 는 세 모드를 한 표로 놓고 이 실험대가 무엇을 골랐는지 적었다. NAT(virbr0) : VM 주소는 192.168.122.x 사설, LAN 에서 VM 접근 불가, 채택 브리지(br0) : LAN 에서 직접 IP, WiFi 라 불가 macvtap : LAN 에서 직접 IP(호스트↔VM 은 제외), WiFi 라 불가
- §245 는 libvirt 의 default 네트워크를 소프트웨어 브리지 virbr0 과 거기 붙은 NAT 규칙으로 적었다. 기본 대역은 192.168.122.0/24 이고 호스트가 .1 을 가지며, VM 들은 이 브리지에 연결되어 서로 직접 통신하고 외부로 나갈 때만 호스트 IP 로 마스커레이딩된다. NAT 가 막는 것은 외부에서 VM 으로 들어오는 방향이다.
- §201 은 이 호스트에서 ip -br addr show virbr0 을 돌린 출력을 남겼다. VM 세 대가 돌 때는 virbr0 이 UP 이고 192.168.122.1/24 을 갖고, 전부 철거한 뒤에는 주소는 그대로인 채 DOWN 이다.
- §180 과 §255 는 밖에서 게스트로 들어오는 방향이 FORWARD 경로라 libvirt 의 guest_input 체인을 지난다고 적었다. 그 체인이 oif "virbr0" reject 로 끝나 게스트 대역으로 새로 들어오는 연결을 거절했고, 밖에서 친 curl 은 connection refused 를 받았다. 호스트 안에서 같은 게스트 주소로 친 curl 은 OUTPUT 경로라 forward 를 타지 않아 404 로 응답했다. 그 reject 줄을 범인으로 확정한 것은 카운터다. 밖에서 curl 을 네 번 쳤을 때 그 줄에 packets 4 bytes 240 이 찍혀 있었다.
- 이 호스트에서 §122 OQ-1 의 다섯 명령을 돌린 출력은 SSOT 에 없다.
가정
- 호스트에 붙어 virsh 와 ip 계열 명령을 실행할 수 있다고 본다.
- §201 과 §247 이 virsh net-update default 로 DHCP 예약을 넣었으므로 이 호스트의 가상 머신이 libvirt 의 default 네트워크를 쓴다고 본다. 그 네트워크 말고 다른 정의가 더 있는지는 열거해 봐야 갈린다.
- 확인하는 동안 네트워크 구성이 바뀌지 않는다고 전제한다.
- 셋 가운데 하나로 갈린다고 보고 물음을 세웠다. 다만 §114 가 Bridge 구성에도 Routing 과 NAT 과 Firewall 이 함께 걸릴 수 있다고 적었으므로, 하나로 갈리지 않으면 걸린 것을 모두 적는다.
미지수
- §178 과 §249 가 NAT 이라고 적은 것이 libvirt 네트워크 정의의 forward mode 로도 그렇게 적혀 있는지. virsh net-dumpxml default 를 통째로 찍은 출력이 SSOT 에 없고, §247 이 인용한 것은 그 정의의 dhcp 절뿐이다.
- default 말고 정의된 가상 네트워크가 더 있는지. virsh net-list --all 의 출력이 없다.
- virbr0 에 어느 인터페이스가 포트로 붙어 있는지, 그리고 이 호스트의 라우팅 테이블이 무엇인지. bridge link 와 ip route 의 출력이 없다.
- 게스트끼리 오가는 프레임과 게스트가 밖으로 나가는 프레임이 호스트의 L3/Netfilter 경로를 지나는지. 밖에서 게스트로 들어오는 방향만 §180 이 FORWARD 로 관측했다.
제약
- 구성이 셋 중 무엇인지를 확정하는 데서 끊는다. 그 구성이 지연에 얼마나 영향을 주는지는 부하 중 호스트 CPU 사용을 보는 물음이 받는다.
- SSOT 에 남은 출력은 §201 의 virbr0 주소와 상태뿐이다. 나머지 네 명령은 다른 장비에서 읽은 값으로 대신하지 않는다.
- 돌릴 명령은 §122 OQ-1 이 정해 두었다. 실행한 명령과 출력을 함께 남겨야 다음 사람이 같은 값을 다시 읽는다.
선택지
1. libvirt 쪽부터 읽는다
virsh net-list --all 로 정의된 가상 네트워크를 열거하고, 나온 이름마다 virsh net-dumpxml 로 forward mode 와 bridge 이름을 읽는다. forward mode 하나로 Bridge 인지 NAT 인지 Routed 인지가 갈리므로 확인이 짧다.
libvirt 로 정의하지 않고 호스트 브리지에 직접 붙인 구성이면 목록이 비어 나오고, 그때는 호스트 인터페이스 쪽을 다시 읽어야 한다.
2. 호스트 인터페이스 쪽부터 읽는다
ip link 로 실재하는 인터페이스를 세우고, bridge link 로 어느 인터페이스가 어느 브리지의 포트인지를 잡고, ip route 로 L3 결정을 본다. libvirt 로 정의했든 안 했든 호스트에 실재하는 것을 읽으므로 구성 방식과 무관하게 답이 나온다.
forward mode 라는 이름으로 적힌 의도는 나오지 않으므로, NAT 이 걸려 있는지는 routing 과 방화벽 규칙을 따로 봐야 한다. §117.3 이 NAT/Firewall 오류에 든 것은 nftables · iptables · NAT rules · IP forwarding 이라는 확인 대상 이름이고 돌릴 명령이 아니다. 방화벽 쪽 명령은 §255 가 대신 적어 두었다 — libvirt 체인 하나를 열어 보는 sudo nft -a list chain ip libvirt_network guest_input 이다. 그 명령이 통하는 것은 이 호스트가 nftables 백엔드이기 때문이고, §180 은 libvirt 의 firewall_backend 가 iptables 일 때도 같은지는 재지 않았다고 적었다.
3. tcpdump 로 경로부터 잡는다 — 제외
§119 는 Host NIC · Bridge · TAP · Guest NIC 에서 tcpdump 로 패킷을 추적하는 순서를 적어 두었다. 다만 그 추적은 캡처를 걸 인터페이스 이름을 이미 알고 있을 때 성립한다. 브리지 이름은 §245 와 §201 이 virbr0 으로 적었지만 TAP 이름은 아직 없으므로 게스트 쪽 대상을 채울 수 없다. §126 의 실습 순서에서도 Bridge/NAT/Route 확인이 셋째이고 Host Nginx → VM packet path tcpdump 는 여덟째다. 이 방법은 이 물음이 닫힌 뒤 실제 패킷 경로를 묻는 물음이 받는다.
다음 검증
- virsh net-list --all 로 정의된 가상 네트워크를 열거한다.
- 나온 이름마다 virsh net-dumpxml 에 그 이름을 넣어 forward mode 와 bridge 이름을 읽는다.
- ip link 로 호스트의 인터페이스 목록을 적는다.
- bridge link 로 어느 인터페이스가 어느 브리지에 붙어 있는지 적는다.
- ip route 로 라우팅 테이블을 적는다.
- 다섯 출력을 실행한 명령과 함께 증거로 남긴다.
닫는 조건 : 세 구성 가운데 무엇인지가 출력으로 확정되면 닫는다. Bridge 로 나오면 §96 과 §114 의 L2 forwarding 서술이 이 호스트에 적용된다고 적는다. NAT 으로 나오면 §98 의 주소 변환이 경로에 들어가고, Routing 으로 나오면 §97 의 L3 결정이 들어간다. 어느 쪽이든 그 결과로 실제 패킷 경로를 묻는 물음의 캡처 지점이 정해진다. §94 가 기준으로 삼은 구조와 다르게 나오면 제3부의 서술 가운데 이 호스트에 적용되지 않는 절을 함께 적는다.