Skip to content
Published on

[가상화] 02. QEMU와 KVM: 오픈소스 가상화의 핵심

Authors

들어가며

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: 스토리지 관리

디스크 이미지 포맷

포맷특징용도
qcow2Copy-on-Write, 스냅샷, 압축, 암호화QEMU 기본 포맷, 프로덕션
raw오버헤드 없음, 최고 I/O 성능성능 우선 환경
vmdkVMware 호환VMware 마이그레이션
vdiVirtualBox 호환VirtualBox 마이그레이션
vpc/vhdxHyper-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-scsiSCSI 스토리지다수의 디스크 지원에 최적
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프로덕션
BridgeTAP을 브리지에 연결VM 간 통신, 외부 접근
macvtapmacvlan + 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

사용 사례

사용 사례설명
OpenStackNova 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 디스크를 만들어도 실제 사용한 만큼만 호스트 스토리지를 소비합니다.