feat: 가상화 문서들 추가

This commit is contained in:
DongHyeonka
2026-09-10 08:54:05 +09:00
parent e9f6a93327
commit 43e1aadef0
695 changed files with 153404 additions and 12754 deletions
@@ -0,0 +1,137 @@
---
id: 68a848c7-eaff-4421-ad25-de21673ca40c
kind: REFERENCE
slug: bisect-the-packet-path-with-capture-points
title: packet 이 어디서 끊겼는지는 계층마다 capture 해서 가른다
topic: network-virtualization
topicName: 네트워크 가상화
project: virtualization
status: 초안
studio: "https://hyeonworks.com/studio/documents/68a848c7-eaff-4421-ad25-de21673ca40c/edit"
sourceRevision: no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다
source:
- final/document.md#119-실제-packet-path-추적
- final/document.md#118-실제-linux에서-확인할-명령어
- final/document.md#117-이-구조에서-발생할-수-있는-문제-117-1
- final/document.md#117-이-구조에서-발생할-수-있는-문제-117-2
- final/document.md#117-이-구조에서-발생할-수-있는-문제-117-3
- final/document.md#117-이-구조에서-발생할-수-있는-문제-117-6
- final/document.md#113-offload-최적화
- final/document.md#114-linux-bridge가-항상-host-tcp-ip-stack을-거치는-것은-아니다
- final/document.md#99-tap의-역할
---
# packet 이 어디서 끊겼는지는 계층마다 capture 해서 가른다
가상 머신이 밖과 통신하지 못할 때 게스트 안에서만 원인을 찾으면 호스트의 브리지와 TAP 연결은 마지막에야 보게 된다. 그 사이의 계층은 애플리케이션 로그에 아무것도 남기지 않는다.
그래서 패킷이 지나야 할 지점마다 캡처를 걸고 어디까지 보였는지로 구간을 좁힌다. 호스트의 물리 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 설정을 확인 대상으로 둔다.
증상 셋을 각각 다른 기준으로 나누지 않은 것은 셋이 모두 어느 지점에서 끊겼는가로 환원되기 때문이다. 따로 적으면 같은 규칙의 부분 증상이 셋으로 늘어난다.
### 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 계층을 따로 검증한다 쪽으로 넘긴다.
이 저장소에는 아직 이 절차를 실제로 돌린 출력이 없다. 여기 적은 판독은 원문 문서가 서술한 것이고 이 호스트의 캡처로 확인한 것이 아니다.
## 예시
- 물리 NIC 에 보이고 브리지에도 보이는데 tap 에 안 보임 : 호스트의 브리지와 tap 연결을 먼저 확인한다
- tap 에 보이는데 게스트 NIC 에 안 보임 : virtio 와 vhost, 게스트 NIC 계층을 확인한다
- 게스트 NIC 에 보이는데 소켓까지 안 옴 : 게스트의 라우팅과 방화벽, listen 상태를 확인한다
- 특정 가상 머신만 통신 불가 : ip link 와 bridge link, virsh domiflist 로 그 가상 머신의 tap 이 브리지에 붙어 있는지 본다
- 같은 서브넷은 되고 다른 서브넷만 실패 : ip route 와 ip rule 을 본다
- 캡처에 보이는 패킷이 예상보다 크고 체크섬이 어긋남 : 오프로드 설정을 먼저 확인한다
- 네 지점이 모두 보이는데 응답만 느림 : 이 절차를 여기서 멈춘다
@@ -0,0 +1,108 @@
---
id: ca36f0db-9028-4761-91a8-afb7eb30f2b9
kind: REFERENCE
slug: verify-the-network-path-before-blaming-the-application
title: Keycloak 실험 결과를 애플리케이션 원인으로 읽기 전에 network 계층을 따로 검증한다
topic: network-virtualization
topicName: 네트워크 가상화
project: virtualization
status: 초안
studio: "https://hyeonworks.com/studio/documents/ca36f0db-9028-4761-91a8-afb7eb30f2b9/edit"
sourceRevision: no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다
source:
- final/document.md#120-keycloak-refresh-token-실험과의-관계
- final/document.md#117-이-구조에서-발생할-수-있는-문제-117-7
- final/document.md#124-핵심-claim
- final/document.md#89-문서-목적
- final/document.md#116-현재-keycloak-k3s-테스트-환경과-연결
- final/document.md#102-packet이-keycloak까지-올라오는-과정
---
# Keycloak 실험 결과를 애플리케이션 원인으로 읽기 전에 network 계층을 따로 검증한다
Refresh Token 경쟁 자체는 virtio-net 문제가 아니다. 다만 그 실험은 클라이언트에서 Nginx 와 가상 머신, K3s, Keycloak 을 거쳐 PostgreSQL 또는 Redis 까지 가는 경로를 여러 노드가 함께 쓴다. 그 경로 위의 네트워크 가상화 문제는 애플리케이션 동시성 문제와 비슷한 증상으로 나타난다.
노드 하나만 느리거나 특정 가상 머신에서만 요청이 실패하는 것을 Refresh Token 경쟁이나 데이터베이스 락으로 결론내지 않으려면, 실험 결과를 원인에 귀속하기 전에 네트워크 경로를 따로 검증한다.
## 관계
- **Guest 의 packet 이 Host Physical NIC 에 닿기까지 — virtio-net · virtqueue · vhost-net · TAP · Bridge**
이 기준이 「따로 검증한다」고 말하는 계층을 세운 글이다.
- **packet 이 어디서 끊겼는지는 계층마다 capture 해서 가른다**
이 기준이 문제가 네트워크인지 아닌지를 가른다면, 그 절차는 네트워크 안에서 어느 구간인지를 가른다.
- **Host Nginx 에서 Keycloak 까지 packet 은 실제로 어디를 지나는가**
검증 순서의 첫 항목이다. 경로를 모르면 무엇을 관측할지도 정해지지 않는다.
- **부하 중 network 가상화가 지연을 바꿀 만큼 호스트 CPU 를 쓰는가**
검증 순서의 마지막 항목이고, 네트워크 처리와 CPU 경쟁을 가르는 관측이다.
- **Keycloak 동시 refresh 실험 중 CPU 가상화 계층이 결과를 흔들 만큼 포화되는가**
같은 실험을 CPU 쪽에서 본 물음이다. 두 계층이 같은 지연으로 보이므로 함께 기록한다.
## 목적
이 기준은 실험 결과를 잘못된 원인에 붙이는 일을 막는다.
Keycloak 멀티 노드 실험에서 관측되는 지연과 실패에는 네트워크 가상화 쪽 원인이 섞일 수 있다. 노드 하나만 지연되는 경우, 가상 머신 하나에서만 패킷이 유실되는 경우, 호스트 브리지 구성이 잘못된 경우, NAT(Network Address Translation) 나 conntrack 문제, 호스트 CPU 경쟁 때문에 vhost 처리가 밀리는 경우가 여기 들어간다.
이 원인들을 확인하지 않은 채 결과를 Refresh Token 경쟁이나 데이터베이스 락으로 적으면, 고칠 곳이 아닌 곳을 고치게 된다.
이 분리는 실험 결과를 보고 나서 세운 규칙이 아니다. 원문 문서는 이 실험 기반으로 검증하려는 항목을 일곱 개 적어 두었고, 그 마지막이 「네트워크 계층 문제와 애플리케이션/저장소 문제의 분리」였다.
## 규칙
### 1. 실험이 지나는 경로를 먼저 적고 시작한다
요청은 클라이언트에서 Nginx 로 가고, 거기서 가상 머신 두 대 중 하나로, 그 안의 K3s 를 지나 Keycloak 으로, 다시 PostgreSQL 또는 Redis 로 간다. 이 경로를 노드들이 공유한다.
경로를 적지 않으면 어느 관측이 어느 구간을 덮는지 정해지지 않는다.
### 2. 노드 하나에서만 나는 증상을 애플리케이션 동시성으로 먼저 읽지 않는다
노드 하나만 지연되거나 가상 머신 하나에서만 실패하는 증상은 그 노드로 가는 경로 쪽에서도 나올 수 있다. 호스트 브리지 구성 오류, NAT 와 conntrack 문제, 그 가상 머신 쪽 패킷 유실이 같은 모양으로 관측된다.
증상이 노드별로 갈리면 그 노드까지 가는 경로를 먼저 확인한다.
### 3. 애플리케이션 로그만으로 네트워크 계층을 배제하지 않는다
Keycloak 은 virtqueue 와 vhost-net, TAP, Bridge, 물리 NIC(Network Interface Card) 를 직접 알지 못하고, 게스트가 주는 소켓 위에서만 동작한다. 아래 계층이 어긋나도 애플리케이션 로그에는 느렸다는 것과 실패했다는 것만 남는다.
그래서 애플리케이션 쪽 관측을 아무리 늘려도 이 계층이 원인인지 아닌지는 갈리지 않는다.
### 4. 네트워크 처리가 쓰는 호스트 CPU 를 실험과 같은 시간축에 기록한다
vhost-net 과 QEMU 스레드, softirq 도 호스트 CPU 를 쓴다. 그래서 네트워크 문제처럼 보이는 지연이 CPU 스케줄링 문제일 수도 있다. 앞의 세 규칙이 애플리케이션 증상을 네트워크 쪽으로 되돌린다면 이 규칙은 네트워크 증상을 CPU 쪽으로 되돌린다. 방향이 반대라서 둘을 한 기준에 둔다.
부하 실험을 돌릴 때 QEMU 와 vhost 의 CPU 사용량, 호스트와 게스트의 CPU, 네트워크 지연을 같은 시간축에 남긴다. 나중에 따로 재면 그때의 부하를 다시 만들어야 한다.
### 5. 세 가지 검증을 마친 뒤에 원인을 적는다
경로가 무엇인지, 그 경로가 끊기지 않았는지, 네트워크 처리가 호스트 CPU 를 얼마나 쓰는지 셋을 확인한다.
첫째는 호스트 Nginx 에서 Keycloak 까지의 실제 패킷 경로를 추적해서, 둘째는 계층마다 캡처해서, 셋째는 부하 중 CPU 사용량을 재서 답한다.
## 적용 조건
여러 노드가 같은 네트워크 경로를 공유하는 실험의 결과를 원인에 귀속할 때.
노드별로만 나타나는 지연을 볼 때.
특정 가상 머신에서만 나는 실패를 볼 때.
부하 구간에서만 커지는 지연을 애플리케이션 동시성이나 저장소 lock 으로 결론내려 할 때.
## 예외
이 기준은 애플리케이션 쪽 관측을 늘려서는 적용되지 않는다. Keycloak 이 게스트 소켓 위에서만 동작하므로 애플리케이션 로그로는 이 계층이 원인인지 가릴 수 없다.
네트워크 계층이 깨끗하다고 해서 이 기준이 애플리케이션 결함을 배제해 주지는 않는다. 여기서 나오는 것은 네트워크가 원인이 아니라는 것까지다.
가상 머신 위 K3s 안쪽은 이 기준의 범위 밖이다. CNI(Container Network Interface) 와 Service, Pod 네트워크는 별도 계층으로 두고 따로 분석한다.
원문 문서가 이 테스트 환경에 얹어 그린 경로는 확인된 것이 아니라 기준 구조를 그대로 옮겨 놓은 그림이다. 이 저장소에는 이 기준으로 원인을 실제로 가른 실험이 아직 없다.
## 예시
- Keycloak 노드 하나만 응답이 느림 : 그 노드가 있는 가상 머신까지의 경로부터 확인한다
- 가상 머신 하나에서만 요청이 실패 : 호스트 브리지 구성과 그 가상 머신의 tap 연결을 본다
- 부하를 올릴수록 지연이 커짐 : QEMU 와 vhost 의 CPU 사용량을 같은 시간축에서 함께 본다
- 동시 갱신 실험에서 두 번째 요청이 거부됨 : 네트워크 검증 셋을 마친 뒤에 Refresh Token 경쟁으로 적는다
- 네트워크 검증이 전부 깨끗함 : 네트워크가 원인이 아니라는 것까지만 적고 애플리케이션 쪽을 계속 본다