- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 들어가며
- QEMU 아키텍처
- TCG: Tiny Code Generator
- Block Layer: 스토리지 관리
- Device Emulation과 VirtIO
- 네트워크 백엔드
- KVM 통합: 하드웨어 가속 가상화
- GPU Passthrough (VFIO)
- 실전 VM 생성 예시
- 사용 사례
들어가며
QEMU(Quick Emulator)는 오픈소스 머신 에뮬레이터이자 가상화 도구입니다. 단독으로는 소프트웨어 에뮬레이션을, KVM과 결합하면 하드웨어 가속 가상화를 제공합니다. OpenStack, Proxmox, libvirt 등 주요 클라우드 플랫폼의 핵심 엔진입니다.
QEMU 아키텍처
System Emulation vs User-mode Emulation
QEMU는 두 가지 실행 모드를 제공합니다.
[System Emulation] [User-mode Emulation]
+-------------------+ +-------------------+
| Guest OS | | Guest Binary |
| (Full System) | | (Single Process) |
+-------------------+ +-------------------+
| Virtual Hardware | | Syscall 변환 계층 |
| CPU, RAM, Disk, | | (Linux-user / |
| NIC, GPU, USB | | BSD-user) |
+-------------------+ +-------------------+
| QEMU Engine | | QEMU Engine |
+-------------------+ +-------------------+
| Host OS / HW | | Host OS / HW |
+-------------------+ +-------------------+
System Emulation (qemu-system-*):
- 전체 컴퓨터 시스템을 에뮬레이션
- CPU, 메모리, 디스크, 네트워크 등 모든 하드웨어를 가상화
- 다른 아키텍처의 OS를 실행 가능 (예: x86에서 ARM Linux 실행)
User-mode Emulation (qemu-*):
- 단일 바이너리만 에뮬레이션
- 다른 아키텍처용 프로그램을 현재 시스템에서 실행
- 시스템 콜을 호스트 OS 시스템 콜로 변환
# System Emulation 예시: ARM 시스템 부팅
qemu-system-aarch64 \
-M virt -cpu cortex-a72 \
-m 2G -nographic \
-kernel Image -append "console=ttyAMA0"
# User-mode Emulation 예시: ARM 바이너리를 x86에서 실행
qemu-aarch64 ./arm-binary
TCG: Tiny Code Generator
KVM 없이 동작할 때 QEMU는 TCG(Tiny Code Generator)라는 JIT 컴파일러를 사용합니다.
TCG 동작 흐름
Guest Code (예: ARM)
|
v
[Frontend] 게스트 명령어 디코딩
|
v
TCG IR (Intermediate Representation)
|
v
[Backend] 호스트 명령어로 변환 (예: x86)
|
v
Translation Block (TB) 캐싱
|
v
Host CPU에서 실행
Translation Block(TB):
- 게스트 코드의 기본 블록(분기점까지)을 단위로 변환
- 변환된 TB는 캐시에 저장하여 재사용
- TB 체이닝으로 자주 실행되는 경로를 최적화
- TCG는 순수 소프트웨어 방식이므로 KVM 대비 10~100배 느림
[TCG Translation Block 캐시]
Guest PC 0x1000 --> TB #1 (Host code at 0x7f001000)
Guest PC 0x1040 --> TB #2 (Host code at 0x7f001200)
Guest PC 0x1080 --> TB #3 (Host code at 0x7f001400)
...
TB #1 --> TB #2 --> TB #3 (체이닝으로 직접 점프)
Block Layer: 스토리지 관리
디스크 이미지 포맷
| 포맷 | 특징 | 용도 |
|---|---|---|
| qcow2 | Copy-on-Write, 스냅샷, 압축, 암호화 | QEMU 기본 포맷, 프로덕션 |
| raw | 오버헤드 없음, 최고 I/O 성능 | 성능 우선 환경 |
| vmdk | VMware 호환 | VMware 마이그레이션 |
| vdi | VirtualBox 호환 | VirtualBox 마이그레이션 |
| vpc/vhdx | Hyper-V 호환 | Hyper-V 마이그레이션 |
# qcow2 이미지 생성 (씬 프로비저닝)
qemu-img create -f qcow2 disk.qcow2 100G
# 스냅샷 생성
qemu-img snapshot -c snap1 disk.qcow2
# 스냅샷 목록 확인
qemu-img snapshot -l disk.qcow2
# 이미지 포맷 변환
qemu-img convert -f vmdk -O qcow2 source.vmdk target.qcow2
# 이미지 정보 확인
qemu-img info disk.qcow2
외부 스토리지 백엔드
+------------------+
| Guest VM |
+------------------+
| VirtIO-blk/SCSI |
+------------------+
| QEMU Block Layer|
+--+--+--+--+--+--+
| | | | |
v v v v v
File NBD iSCSI Ceph GlusterFS
RBD
- NBD (Network Block Device): 원격 디스크 공유
- Ceph RBD: 분산 스토리지 기반 블록 디바이스
- GlusterFS: 분산 파일 시스템 기반 볼륨
- iSCSI: IP 네트워크 기반 블록 스토리지
Device Emulation과 VirtIO
에뮬레이션 vs 반가상화
[전통적 에뮬레이션] [VirtIO 반가상화]
Guest OS Guest OS
| |
v v
에뮬레이트된 e1000 NIC VirtIO-net 드라이버
| |
v v
QEMU가 모든 레지스터 공유 메모리 링 버퍼
접근을 처리 (VM Exit 다수) (최소 VM Exit)
| |
v v
Host NIC Host NIC
VirtIO 디바이스 종류:
| VirtIO 디바이스 | 기능 | 성능 향상 |
|---|---|---|
| virtio-net | 네트워크 | 10x 이상 (e1000 대비) |
| virtio-blk | 블록 스토리지 | 2~5x (IDE 에뮬레이션 대비) |
| virtio-scsi | SCSI 스토리지 | 다수의 디스크 지원에 최적 |
| virtio-gpu | 그래픽 | 3D 가속 지원 (virgl) |
| virtio-fs | 파일 공유 | 호스트-게스트 파일 시스템 공유 |
| virtio-balloon | 메모리 | 동적 메모리 조절 |
네트워크 백엔드
+--------+ +--------+ +--------+
| VM 1 | | VM 2 | | VM 3 |
| virtio | | virtio | | virtio |
+---+----+ +---+----+ +---+----+
| | |
+---+-------------+-------------+---+
| Linux Bridge |
| (virbr0) |
+----------------+-------------------+
|
Physical NIC
(eth0)
| 백엔드 | 설명 | 사용 사례 |
|---|---|---|
| SLIRP (user) | 사용자 모드 NAT, 설정 간단 | 개발/테스트 |
| TAP/TUN | 커널 레벨 가상 NIC | 프로덕션 |
| Bridge | TAP을 브리지에 연결 | VM 간 통신, 외부 접근 |
| macvtap | macvlan + TAP 결합 | 간단한 L2 연결 |
| vhost-net | 커널 내 VirtIO 처리 | 고성능 네트워킹 |
# TAP + Bridge 네트워크 설정
sudo ip link add br0 type bridge
sudo ip link set eth0 master br0
sudo ip link set br0 up
# QEMU에서 TAP 네트워크 사용
qemu-system-x86_64 \
-netdev tap,id=net0,ifname=tap0,script=no \
-device virtio-net-pci,netdev=net0
KVM 통합: 하드웨어 가속 가상화
KVM_RUN ioctl 흐름
QEMU Process (User Space)
|
| ioctl(KVM_RUN)
v
KVM Module (Kernel Space)
|
| VMLAUNCH / VMRESUME
v
Guest Mode (VMX non-root)
|
| VM Exit 발생
v
KVM Module (Kernel Space)
|
| KVM이 처리 가능하면 직접 처리
| 불가능하면 QEMU로 반환
v
QEMU Process (User Space)
|
| 디바이스 에뮬레이션 등 처리
| 다시 ioctl(KVM_RUN)
v
... (반복)
KVM이 처리하는 VM Exit:
- 대부분의 MSR 접근
- 간단한 I/O 포트 접근
- EPT 위반 (메모리 매핑)
- 외부 인터럽트
QEMU로 전달되는 VM Exit:
- 복잡한 디바이스 I/O
- MMIO(Memory-Mapped I/O) 접근
- 일부 CPUID 요청
QEMU + KVM 성능
[성능 비교 (상대값, 네이티브 = 100)]
CPU 연산 (정수/부동소수점):
Native: ████████████████████████████████████████ 100%
QEMU+KVM: ███████████████████████████████████████ 98%
QEMU(TCG): ██████████ 25%
디스크 I/O (VirtIO):
Native: ████████████████████████████████████████ 100%
QEMU+KVM: ████████████████████████████████████ 90%
QEMU(TCG): ████████████ 30%
네트워크 (vhost-net):
Native: ████████████████████████████████████████ 100%
QEMU+KVM: ██████████████████████████████████████ 95%
QEMU(TCG): ██████████ 25%
GPU Passthrough (VFIO)
GPU를 VM에 직접 연결하여 네이티브에 가까운 그래픽 성능을 제공합니다.
설정 단계
# 1. IOMMU 활성화 (GRUB에서)
# Intel: intel_iommu=on iommu=pt
# AMD: amd_iommu=on iommu=pt
# 2. IOMMU 그룹 확인
for d in /sys/kernel/iommu_groups/*/devices/*; do
n=$(basename "$d")
echo "IOMMU Group $(basename $(dirname $(dirname "$d"))): $n $(lspci -nns "$n")"
done
# 3. GPU를 vfio-pci에 바인딩
# GPU의 벤더:디바이스 ID 확인
lspci -nn | grep -i nvidia
# 예시 출력: 01:00.0 VGA ... [10de:2484]
# 예시 출력: 01:00.1 Audio ... [10de:228b]
# vfio-pci 바인딩
echo "10de 2484" > /sys/bus/pci/drivers/vfio-pci/new_id
echo "10de 228b" > /sys/bus/pci/drivers/vfio-pci/new_id
# 4. QEMU에서 GPU 패스스루 실행
qemu-system-x86_64 \
-enable-kvm \
-m 16G \
-cpu host \
-smp 8 \
-device vfio-pci,host=01:00.0,multifunction=on \
-device vfio-pci,host=01:00.1 \
-drive if=pflash,format=raw,readonly=on,file=OVMF_CODE.fd \
-drive if=pflash,format=raw,file=OVMF_VARS.fd \
-drive file=vm-disk.qcow2,format=qcow2,if=virtio
VFIO 아키텍처
+-------------------+
| Guest VM |
| (GPU 드라이버) |
+-------------------+
| VFIO-PCI |
| (패스스루 계층) |
+-------------------+
| IOMMU |
| (DMA 리매핑) |
+-------------------+
| Physical GPU |
| (NVIDIA/AMD) |
+-------------------+
- IOMMU가 DMA 요청을 리매핑하여 VM 간 메모리 격리 보장
- 같은 IOMMU 그룹의 모든 디바이스를 함께 패스스루해야 함
- OVMF(UEFI 펌웨어)로 GPU BIOS 초기화
- GPU 한 개는 하나의 VM에만 독점 할당
실전 VM 생성 예시
# 기본 VM 생성 및 실행
qemu-system-x86_64 \
-enable-kvm \
-name "ubuntu-server" \
-m 4G \
-smp cores=4 \
-cpu host \
-drive file=ubuntu.qcow2,format=qcow2,if=virtio \
-cdrom ubuntu-22.04-server.iso \
-boot d \
-device virtio-net-pci,netdev=net0 \
-netdev user,id=net0,hostfwd=tcp::2222-:22 \
-vnc :1 \
-monitor stdio
# SSH 접속 (호스트에서)
ssh -p 2222 user@localhost
# 라이브 마이그레이션 (소스에서)
# 대상 호스트에서 동일한 VM 설정으로 -incoming tcp:0:4444 옵션 추가 후
# 소스에서 실행:
# (QEMU monitor) migrate tcp:dest-host:4444
사용 사례
| 사용 사례 | 설명 |
|---|---|
| OpenStack | Nova compute에서 libvirt+QEMU/KVM을 기본 하이퍼바이저로 사용 |
| Proxmox VE | 웹 UI 기반 KVM 가상화 + LXC 컨테이너 통합 관리 |
| 개발 환경 | 크로스 아키텍처 개발 (ARM on x86 등) |
| 보안 연구 | 악성코드 분석, 취약점 연구를 위한 격리 환경 |
| CI/CD | 깨끗한 테스트 환경을 빠르게 생성/삭제 |
| 임베디드 개발 | QEMU로 다양한 보드 에뮬레이션 |
퀴즈: QEMU/KVM 이해도 점검
Q1. QEMU의 System Emulation과 User-mode Emulation의 차이점은 무엇인가요?
System Emulation은 전체 컴퓨터 시스템(CPU, 메모리, 디스크 등)을 에뮬레이션하여 완전한 OS를 실행합니다. User-mode Emulation은 단일 바이너리만 에뮬레이션하며 시스템 콜을 호스트 OS로 변환합니다.
Q2. TCG가 KVM보다 느린 이유는 무엇인가요?
TCG는 게스트 명령어를 IR(중간 표현)으로 변환한 후 호스트 명령어로 재변환하는 소프트웨어 JIT 컴파일 방식입니다. KVM은 하드웨어 가상화 확장(VT-x/AMD-V)을 활용하여 게스트 코드를 CPU에서 직접 실행하므로 훨씬 빠릅니다.
Q3. VirtIO가 에뮬레이트된 e1000 NIC보다 빠른 이유는?
에뮬레이트된 e1000은 모든 레지스터 접근마다 VM Exit가 발생합니다. VirtIO는 공유 메모리 링 버퍼를 사용하여 대량의 데이터를 최소한의 VM Exit로 전달하므로 오버헤드가 크게 줄어듭니다.
Q4. GPU Passthrough에서 IOMMU 그룹이 중요한 이유는?
같은 IOMMU 그룹의 디바이스는 DMA를 통해 서로의 메모리에 접근할 수 있습니다. 따라서 보안을 위해 같은 그룹의 모든 디바이스를 하나의 VM에 함께 할당하거나 모두 격리해야 합니다.
Q5. qcow2 포맷의 장점은 무엇인가요?
Copy-on-Write로 씬 프로비저닝을 지원하며, 스냅샷, 압축, 암호화 기능을 내장합니다. 100GB 디스크를 만들어도 실제 사용한 만큼만 호스트 스토리지를 소비합니다.