libvirt / KVM 관리

libvirt는 KVM, QEMU, LXC, Xen 등 다양한 하이퍼바이저를 통합 관리하는 오픈소스 가상화 API 라이브러리다. virsh, XML 도메인 설정, UEFI firmware auto-selection, Secure Boot/TPM, 네트워크/스토리지 관리, 스냅샷, 라이브 마이그레이션, Python API, virtiofsd까지 커널 개발자를 위한 종합 가이드.

libvirt 개요 및 아키텍처

libvirt는 하이퍼바이저 독립적인 가상화 관리 인터페이스를 제공하는 미들웨어 계층이다. 클라이언트-서버 구조로 동작하며, libvirtd 데몬이 하이퍼바이저와 통신한다.

드라이버 모델

libvirt는 각 하이퍼바이저마다 드라이버 플러그인을 제공한다.

드라이버하이퍼바이저연결 URI
QEMU/KVMQEMU with KVMqemu:///system
LXCLinux Containerslxc:///
XenXen 하이퍼바이저xen:///
OpenVZOpenVZopenvz:///system
원격TCP/TLS/SSH 터널qemu+ssh://host/system

주요 도구 비교

도구인터페이스용도
virshCLI도메인/네트워크/스토리지 관리 (자동화에 적합)
virt-managerGUI데스크탑 GUI 관리
virt-installCLIVM 생성 전문 도구
virt-viewerGUIVM 콘솔 표시 (VNC/Spice)
Python libvirtAPI프로그래밍 자동화
클라이언트 계층 virsh CLI virt-manager GUI Python API libvirt.open() virt-install VM 생성 원격 클라이언트 SSH / TLS libvirtd 데몬 XML 파싱 & 도메인 상태 관리 UNIX 소켓: /var/run/libvirt/libvirt.sock 드라이버 디스패치 & RPC ACL 권한 / 감사 로깅 드라이버 계층 QEMU 드라이버 qemu:///system LXC 드라이버 lxc:/// 네트워크 드라이버 bridge / NAT / SR-IOV 스토리지 드라이버 dir / logical / netfs / rbd 하이퍼바이저 QEMU/KVM 프로세스 Linux Containers (LXC) Xen 도메인 -enable-kvm -machine q35 ... cgroups v2 + 네임스페이스 xl / xm 커맨드

libvirtd vs 모듈식 데몬 (libvirt 6.0+)

libvirt 6.0부터 단일 libvirtd 대신 기능별로 분리된 모듈식 데몬 아키텍처를 지원한다. 각 하이퍼바이저/스토리지/네트워크 기능이 독립 데몬으로 분리되어 보안성과 안정성이 향상된다.

데몬역할소켓 경로
virtproxyd클라이언트 프록시 (하위 호환)/run/libvirt/virtproxyd-sock
virtqemudQEMU/KVM 도메인 관리/run/libvirt/virtqemud-sock
virtstoraged스토리지 풀/볼륨 관리/run/libvirt/virtstoraged-sock
virtnetworkd가상 네트워크 관리/run/libvirt/virtnetworkd-sock
virtnodedevd호스트 노드 디바이스/run/libvirt/virtnodedevd-sock
virtsecretd시크릿(암호) 관리/run/libvirt/virtsecretd-sock
virtnwfilterd네트워크 필터 관리/run/libvirt/virtnwfilterd-sock
virtinterfaced호스트 네트워크 인터페이스/run/libvirt/virtinterfaced-sock
virsh / 클라이언트 virtproxyd RPC 라우팅 / 하위 호환 프록시 virtqemud QEMU/KVM 도메인 virtstoraged 스토리지 풀/볼륨 virtnetworkd 가상 네트워크 virtsecretd 외 시크릿/필터/인터페이스 QEMU/KVM 프로세스

RPC 통신 메커니즘

libvirt 클라이언트와 데몬 간 통신은 XDR(eXternal Data Representation) 직렬화 기반 RPC 프로토콜을 사용한다.

전송 방식URI 예시특징
UNIX 도메인 소켓qemu:///system로컬 전용, 가장 빠름, root/libvirt 그룹 접근
SSH 터널qemu+ssh://host/system원격 접근, SSH 키 인증, 방화벽 불필요
TLS (x509)qemu+tls://host/system원격 접근, 인증서 기반, 포트 16514
TCP (비보안)qemu+tcp://host/system테스트용, 포트 16509, 운영 환경 비권장

libvirt 핵심 객체 모델

객체 타입C 타입Python 타입설명
연결virConnectPtrvirConnect하이퍼바이저 연결 핸들
도메인virDomainPtrvirDomainVM 인스턴스 (실행/정지 모두)
네트워크virNetworkPtrvirNetwork가상 네트워크
스토리지 풀virStoragePoolPtrvirStoragePool스토리지 컨테이너
스토리지 볼륨virStorageVolPtrvirStorageVol개별 디스크 이미지
인터페이스virInterfacePtrvirInterface호스트 네트워크 인터페이스
시크릿virSecretPtrvirSecret암호화 키/비밀값
도메인 상태 머신 Undefined Defined Running Paused Shutdown Shutoff Crashed define start suspend resume shutdown 완료 start crash destroy

설치 및 초기 설정

패키지 설치

# Ubuntu / Debian
sudo apt install -y libvirt-daemon-system libvirt-clients \
    virtinst virt-manager qemu-kvm

# Fedora / RHEL / CentOS
sudo dnf install -y libvirt libvirt-client virt-install \
    virt-manager qemu-kvm

# Arch Linux
sudo pacman -S libvirt virt-install virt-manager qemu

권한 설정

# 현재 사용자를 libvirt, kvm 그룹에 추가
sudo usermod -aG libvirt,kvm $USER

# 로그아웃 후 재로그인 또는 즉시 적용
newgrp libvirt

# libvirtd 서비스 시작 및 자동 시작 설정
sudo systemctl enable --now libvirtd

# 연결 테스트
virsh -c qemu:///system list --all

네트워크 초기화 (virbr0)

# 기본 NAT 네트워크 (default) 시작
virsh net-start default
virsh net-autostart default

# 네트워크 목록 확인
virsh net-list --all

# virbr0 브리지 확인
ip link show virbr0
ip addr show virbr0

libvirtd.conf 주요 설정 옵션

/etc/libvirt/libvirtd.conf 파일에서 데몬 동작을 제어한다.

# /etc/libvirt/libvirtd.conf 주요 항목

# TCP 리스닝 활성화 (TLS 사용 권장)
listen_tls = 1
listen_tcp = 0

# 리스닝 주소 (0.0.0.0 = 모든 인터페이스)
listen_addr = "0.0.0.0"

# TCP 인증 방식 (none / sasl / tls)
auth_tcp = "sasl"
auth_tls = "none"

# 최대 클라이언트 연결 수
max_clients = 20
max_queued_clients = 20

# 유닉스 소켓 권한
unix_sock_group = "libvirt"
unix_sock_ro_perms = "0777"
unix_sock_rw_perms = "0770"

# 감사 로깅
audit_level = 1
audit_logging = 1

# 설정 변경 후 재시작
sudo systemctl restart libvirtd

qemu.conf 주요 설정

/etc/libvirt/qemu.conf는 QEMU 프로세스 실행 컨텍스트를 제어한다.

# /etc/libvirt/qemu.conf 주요 항목

# QEMU 프로세스 실행 사용자/그룹
user = "qemu"
group = "qemu"

# 보안 드라이버 (selinux / apparmor / none)
security_driver = "selinux"

# HugePage 디렉토리
hugetlbfs_mount = "/dev/hugepages"

# UEFI 펌웨어 경로 (NVRAM 템플릿)
nvram = [
  "/usr/share/OVMF/OVMF_CODE.fd:/usr/share/OVMF/OVMF_VARS.fd",
  "/usr/share/AAVMF/AAVMF_CODE.fd:/usr/share/AAVMF/AAVMF_VARS.fd"
]

# 메모리 잠금 허용 (Huge Pages / vfio에 필요)
lock_manager = "lockd"

# vnc 리스닝 주소
vnc_listen = "0.0.0.0"

# QEMU 프로세스 stdio 핸들러
stdio_handler = "logd"
현대 libvirt 흐름: 최근 libvirt는 firmware descriptor를 읽어 UEFI 펌웨어를 자동 선택할 수 있으므로, 가능하면 개별 VM XML에서 OVMF 경로를 하드코딩하기보다 <os firmware='efi'>와 firmware feature를 통해 의도를 표현하는 편이 좋다. 위 nvram 배열은 구버전 호환과 수동 템플릿 이해에는 여전히 중요하지만, 실제 자동 선택 가능 여부는 virsh domcapabilities로 확인하는 편이 정확하다.

모듈식 데몬 활성화 (virtqemud)

# libvirt 6.0+ 모듈식 데몬 활성화
# virtqemud 소켓 및 서비스 활성화
sudo systemctl enable --now virtqemud.socket
sudo systemctl enable --now virtqemud.service

# 스토리지 데몬
sudo systemctl enable --now virtstoraged.socket

# 네트워크 데몬
sudo systemctl enable --now virtnetworkd.socket

# 모듈식 데몬 사용 시 URI
virsh -c qemu+unix:///system list --all

# 기존 libvirtd와 충돌 방지 - libvirtd 비활성화
sudo systemctl disable --now libvirtd.socket libvirtd.service

TLS 인증 설정 (원격 보안 연결)

# CA 인증서 생성 (certtool 사용)
certtool --generate-privkey > cakey.pem
certtool --generate-self-signed --load-privkey cakey.pem \
  --template ca.info > cacert.pem

# 서버 키/인증서 생성
certtool --generate-privkey > serverkey.pem
certtool --generate-certificate --load-privkey serverkey.pem \
  --load-ca-certificate cacert.pem \
  --load-ca-privkey cakey.pem \
  --template server.info > servercert.pem

# 인증서 설치
sudo mkdir -p /etc/pki/CA /etc/pki/libvirt/private
sudo cp cacert.pem /etc/pki/CA/
sudo cp servercert.pem /etc/pki/libvirt/
sudo cp serverkey.pem /etc/pki/libvirt/private/

# TLS 원격 연결 테스트
virsh -c qemu+tls://remote-host/system list --all

virsh 원격 SSH 연결 설정

# ~/.ssh/config 설정
Host virt-host
    HostName 192.168.1.100
    User admin
    IdentityFile ~/.ssh/virt_rsa
    ServerAliveInterval 60

# SSH 키 기반 원격 virsh 연결
virsh -c qemu+ssh://virt-host/system list --all

# 원격 VM 마이그레이션을 위한 호스트 간 SSH 키 교환
ssh-copy-id -i ~/.ssh/id_rsa.pub root@virt-host2

방화벽 설정

# libvirt TLS 포트 허용 (firewalld)
sudo firewall-cmd --permanent --add-port=16514/tcp  # TLS
sudo firewall-cmd --permanent --add-port=16509/tcp  # TCP (비권장)
sudo firewall-cmd --permanent --add-port=49152-49215/tcp  # 마이그레이션 포트
sudo firewall-cmd --reload

# iptables 직접 설정
iptables -I INPUT -p tcp --dport 16514 -j ACCEPT
iptables -I INPUT -p tcp --dport 49152:49215 -j ACCEPT

virsh 명령어 체계

virsh는 libvirt의 기본 CLI 도구다. 도메인(VM), 네트워크, 스토리지를 관리한다.

도메인 관리

# 도메인 목록 (실행 중)
virsh list

# 모든 도메인 목록 (정지 포함)
virsh list --all

# 도메인 시작
virsh start myvm

# 도메인 안전 종료 (ACPI 신호)
virsh shutdown myvm

# 도메인 강제 종료
virsh destroy myvm

# 도메인 자동 시작 설정
virsh autostart myvm

# 도메인 일시 정지 / 재개
virsh suspend myvm
virsh resume myvm

# 도메인 삭제 (스토리지 포함)
virsh undefine myvm --remove-all-storage

상태 조회

# 도메인 상세 정보
virsh dominfo myvm

# 도메인 통계 (CPU, 메모리)
virsh domstats myvm

# 블록 I/O 통계
virsh domblkstat myvm vda

# 네트워크 통계
virsh domifstat myvm vnet0

# vCPU 정보
virsh vcpuinfo myvm

콘솔 연결

# 시리얼 콘솔 연결
virsh console myvm

# VNC 디스플레이 포트 확인
virsh vncdisplay myvm

# SSH로 연결 (게스트 IP 확인 후)
virsh domifaddr myvm

설정 편집

# XML 설정 실시간 편집
virsh edit myvm

# XML 덤프
virsh dumpxml myvm > myvm.xml

# XML에서 도메인 정의
virsh define myvm.xml

# XML에서 도메인 생성 및 시작 (임시)
virsh create myvm.xml

네트워크 관련 virsh 명령어

# 네트워크 목록
virsh net-list --all

# 네트워크 XML 확인
virsh net-dumpxml default

# 네트워크 XML 편집
virsh net-edit default

# DHCP 임대 목록 확인
virsh net-dhcp-leases default

# 네트워크 시작/중지/자동시작
virsh net-start mynet
virsh net-destroy mynet
virsh net-autostart mynet

# 네트워크 정의/삭제
virsh net-define mynet.xml
virsh net-undefine mynet

스토리지 관련 virsh 명령어

# 풀 목록
virsh pool-list --all

# 풀 정보
virsh pool-info mypool

# 풀 XML 확인
virsh pool-dumpxml mypool

# 풀 새로고침 (볼륨 목록 갱신)
virsh pool-refresh mypool

# 볼륨 목록
virsh vol-list mypool

# 볼륨 상세 정보
virsh vol-info --pool mypool myvm.qcow2

# 볼륨 경로 확인
virsh vol-path --pool mypool myvm.qcow2

# 볼륨 삭제
virsh vol-delete --pool mypool myvm.qcow2

# 볼륨 크기 조정
virsh vol-resize --pool mypool myvm.qcow2 50G

비밀 관리 (secret)

# 시크릿 XML 정의 (예: Ceph 인증 키)
cat << 'EOF' > ceph-secret.xml
<secret ephemeral='no' private='no'>
  <description>Ceph RBD 인증 키</description>
  <usage type='ceph'>
    <name>client.libvirt secret</name>
  </usage>
</secret>
EOF
virsh secret-define ceph-secret.xml

# 시크릿 값 설정 (base64 인코딩된 Ceph 키)
virsh secret-set-value \
  --secret $(virsh secret-list | grep Ceph | awk '{print $1}') \
  --base64 "AQDrBuBfYbBVBhAA..."

# 시크릿 목록 확인
virsh secret-list

# 시크릿 XML 확인
virsh secret-dumpxml <UUID>

CPU/메모리 핫플러그

# 실행 중 vCPU 수 변경 (최대 vCPU 내에서)
virsh setvcpus myvm 8 --live

# 영구 설정 변경
virsh setvcpus myvm 8 --config

# 실행 중 메모리 변경 (balloon 필요)
virsh setmem myvm 8G --live

# 최대 메모리 설정 (재시작 필요)
virsh setmaxmem myvm 16G --config

# 디바이스 핫플러그 (XML 파일로)
virsh attach-device myvm disk-hotplug.xml --live --config

블록 디바이스 관련 명령어

# 도메인 블록 디바이스 목록
virsh domblklist myvm

# 블록 디바이스 상세 정보
virsh domblkinfo myvm vda

# 블록 풀 (백킹 파일 통합)
virsh blockpull myvm vda --wait --verbose

# 라이브 블록 복사 (디스크 교체)
virsh blockcopy myvm vda /new/path/myvm-new.qcow2 \
  --format qcow2 --wait --pivot

# 블록 커밋 (스냅샷 병합)
virsh blockcommit myvm vda --active --pivot --wait

# 블록 I/O 통계
virsh domblkstat myvm vda --human

인터페이스 관련 명령어

# 도메인 네트워크 인터페이스 목록
virsh domiflist myvm

# 인터페이스 핫플러그 추가
virsh attach-interface myvm network default \
  --model virtio --live --config

# 인터페이스 제거
virsh detach-interface myvm bridge br0 \
  --mac 52:54:00:xx:xx:xx --live --config

# 인터페이스 통계
virsh domifstat myvm vnet0

virsh 배치 처리 스크립트

#!/bin/bash
# 여러 도메인 일괄 스냅샷 생성
DOMAINS=$(virsh list --name)
SNAP_NAME="backup-$(date +%Y%m%d-%H%M%S)"

for dom in $DOMAINS; do
    echo "스냅샷 생성: $dom / $SNAP_NAME"
    virsh snapshot-create-as "$dom" "$SNAP_NAME" \
      "자동 백업 $SNAP_NAME" --atomic
done

# 일괄 종료 후 재시작
for dom in $DOMAINS; do
    virsh shutdown "$dom"
done

sleep 30

for dom in $DOMAINS; do
    virsh start "$dom"
done

# 도메인별 IP 주소 일괄 출력
virsh list --name | while read dom; do
    [ -z "$dom" ] && continue
    echo -n "$dom: "
    virsh domifaddr "$dom" 2>/dev/null | grep -oP '\d+\.\d+\.\d+\.\d+'
done

XML 도메인 설정 심화

libvirt는 XML로 도메인 전체 설정을 기술한다. 커널 개발에서 자주 사용하는 설정 요소를 정리한다.

기본 도메인 XML 구조

<domain type='kvm'>
  <name>myvm</name>
  <memory unit='GiB'>4</memory>
  <currentMemory unit='GiB'>4</currentMemory>
  <vcpu placement='static'>4</vcpu>
  <os>
    <type arch='x86_64' machine='q35'>hvm</type>
    <boot dev='hd'/>
  </os>
  <features>
    <acpi/><apic/>
  </features>
</domain>

CPU 토폴로지 설정

<!-- CPU 토폴로지: 2소켓 x 2코어 x 2스레드 = 8 vCPU -->
<cpu mode='host-passthrough' check='none'>
  <topology sockets='2' cores='2' threads='2'/>
  <numa>
    <cell id='0' cpus='0-3' memory='2' unit='GiB'/>
    <cell id='1' cpus='4-7' memory='2' unit='GiB'/>
  </numa>
</cpu>

vCPU 핀닝 설정

<!-- vCPU 핀닝: 게스트 vCPU를 호스트 CPU에 고정 -->
<cputune>
  <vcpupin vcpu='0' cpuset='2'/>
  <vcpupin vcpu='1' cpuset='3'/>
  <vcpupin vcpu='2' cpuset='6'/>
  <vcpupin vcpu='3' cpuset='7'/>
  <emulatorpin cpuset='0-1'/>
</cputune>

Huge Pages 메모리 설정

<!-- 1GB HugePage 사용 -->
<memoryBacking>
  <hugepages>
    <page size='1' unit='GiB'/>
  </hugepages>
  <locked/>
</memoryBacking>

<!-- 호스트에서 HugePage 설정 (사전 필요) -->
# echo 4 > /sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages

디스크 디바이스 설정

<devices>
  <!-- virtio-blk 디스크 -->
  <disk type='file' device='disk'>
    <driver name='qemu' type='qcow2' cache='none' io='native'/>
    <source file='/var/lib/libvirt/images/myvm.qcow2'/>
    <target dev='vda' bus='virtio'/>
    <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
  </disk>
  <!-- virtio-net 네트워크 인터페이스 -->
  <interface type='network'>
    <source network='default'/>
    <model type='virtio'/>
  </interface>
  <!-- 시리얼 콘솔 -->
  <serial type='pty'>
    <target port='0'/>
  </serial>
  <console type='pty'>
    <target type='serial' port='0'/>
  </console>
</devices>

UEFI Secure Boot + TPM 2.0 XML

libvirt는 도메인 XML에서 "어떤 펌웨어 파일을 직접 쓸지"보다 "어떤 펌웨어 기능이 필요한지"를 먼저 기술하는 방식이 점점 중요해지고 있다. Secure Boot 실습 VM이라면 보통 EFI 펌웨어, pre-enrolled keys, TPM 2.0 에뮬레이터를 함께 선언한다.

<domain type='kvm'>
  <name>sb-lab</name>
  <os firmware='efi'>
    <type arch='x86_64' machine='q35'>hvm</type>
    <firmware>
      <feature enabled='yes' name='secure-boot'/>
      <feature enabled='yes' name='enrolled-keys'/>
    </firmware>
  </os>
  <features>
    <acpi/><apic/>
    <smm state='on'/>
  </features>
  <devices>
    <tpm model='tpm-tis'>
      <backend type='emulator' version='2.0'/>
    </tpm>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2'/>
      <source file='/var/lib/libvirt/images/sb-lab.qcow2'/>
      <target dev='vda' bus='virtio'/>
    </disk>
    <interface type='network'>
      <source network='default'/>
      <model type='virtio'/>
    </interface>
  </devices>
</domain>
# 호스트가 어떤 EFI firmware feature를 지원하는지 확인
virsh domcapabilities --machine q35 --arch x86_64 | less

# TPM 2.0 에뮬레이터 패키지 확인 (libvirt가 내부적으로 swtpm 사용)
which swtpm

# UEFI VM을 먼저 생성한 뒤 XML 수정 워크플로도 흔하다
virt-install \
  --name sb-lab \
  --memory 4096 \
  --vcpus 2 \
  --disk size=20,format=qcow2,bus=virtio \
  --cdrom ./debian-13-netinst.iso \
  --network network=default,model=virtio \
  --boot uefi \
  --tpm backend.type=emulator,backend.version=2.0
자동 선택의 함정: 기존 VM은 처음 정의될 때 해석된 loader/nvram 값이 XML에 남아 있을 수 있다. 나중에 Secure Boot 정책이나 enrolled keys 여부를 바꾸려면, 생성된 XML이 여전히 예전 OVMF 조합을 가리키는지 먼저 확인해야 한다.

완전한 고성능 도메인 XML 예시

<domain type='kvm'>
  <name>highperf-vm</name>
  <uuid>550e8400-e29b-41d4-a716-446655440000</uuid>
  <memory unit='GiB'>16</memory>
  <vcpu placement='static'>8</vcpu>

  <!-- OS 및 펌웨어 -->
  <os firmware='efi'>
    <type arch='x86_64' machine='q35'>hvm</type>
    <boot dev='hd'/>
  </os>

  <!-- HyperV 계몽 + KVM 은닉 -->
  <features>
    <acpi/><apic/>
    <hyperv mode='custom'>
      <relaxed state='on'/>
      <vapic state='on'/>
      <spinlocks state='on' retries='8191'/>
      <vpindex state='on'/>
      <runtime state='on'/>
      <synic state='on'/>
      <stimer state='on'/>
      <frequencies state='on'/>
    </hyperv>
    <kvm>
      <hidden state='on'/>
    </kvm>
    <ioapic driver='kvm'/>
  </features>

  <!-- CPU 호스트 패스스루 -->
  <cpu mode='host-passthrough' check='none' migratable='on'>
    <topology sockets='1' dies='1' cores='4' threads='2'/>
  </cpu>

  <!-- vCPU 핀닝 + IOThread -->
  <cputune>
    <vcpupin vcpu='0' cpuset='4'/>
    <vcpupin vcpu='1' cpuset='5'/>
    <vcpupin vcpu='2' cpuset='6'/>
    <vcpupin vcpu='3' cpuset='7'/>
    <vcpupin vcpu='4' cpuset='12'/>
    <vcpupin vcpu='5' cpuset='13'/>
    <vcpupin vcpu='6' cpuset='14'/>
    <vcpupin vcpu='7' cpuset='15'/>
    <emulatorpin cpuset='0-1'/>
    <iothreadpin iothread='1' cpuset='2-3'/>
  </cputune>

  <!-- 1GB HugePage 메모리 -->
  <memoryBacking>
    <hugepages>
      <page size='1' unit='GiB'/>
    </hugepages>
    <locked/><discard/>
  </memoryBacking>

  <iothreads>1</iothreads>

  <devices>
    <emulator>/usr/bin/qemu-system-x86_64</emulator>

    <!-- 고성능 NVMe 스타일 디스크 -->
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none' io='native'
              iothread='1' discard='unmap'/>
      <source file='/var/lib/libvirt/images/highperf.qcow2'/>
      <target dev='vda' bus='virtio'/>
    </disk>

    <!-- virtio-net multiqueue -->
    <interface type='network'>
      <source network='default'/>
      <model type='virtio'/>
      <driver name='vhost' queues='8'/>
    </interface>

    <!-- virtio-rng (엔트로피 소스) -->
    <rng model='virtio'>
      <backend model='random'>/dev/urandom</backend>
    </rng>

    <!-- watchdog -->
    <watchdog model='itco' action='reset'/>

    <serial type='pty'><target port='0'/></serial>
    <console type='pty'><target type='serial' port='0'/></console>
  </devices>
</domain>

IOMMU/VFIO PCI 패스스루 설정

# 1. 호스트 IOMMU 활성화 (커널 파라미터)
# GRUB_CMDLINE_LINUX에 추가: intel_iommu=on iommu=pt
sudo vim /etc/default/grub
sudo grub2-mkconfig -o /boot/grub2/grub.cfg

# 2. PCI 디바이스 IOMMU 그룹 확인
for d in /sys/kernel/iommu_groups/*/devices/*; do
    n=${d#*/iommu_groups/*}; n=${n%%/*}
    printf 'IOMMU Group %s ' "$n"
    lspci -nns "${d##*/}"
done

# 3. vfio-pci 드라이버 바인딩
echo "10de 1eb8" > /sys/bus/pci/drivers/vfio-pci/new_id
<!-- PCI 패스스루 디바이스 (VFIO) -->
<hostdev mode='subsystem' type='pci' managed='yes'>
  <source>
    <address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
  </source>
  <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/>
</hostdev>

<!-- IOMMU 디바이스 (vIOMMU) 활성화 -->
<iommu model='intel'>
  <driver intremap='on' caching_mode='on' eim='on' iotlb='on'/>
</iommu>

USB 패스스루 설정

<!-- USB 호스트 디바이스 패스스루 -->
<hostdev mode='subsystem' type='usb' managed='yes'>
  <source>
    <!-- vendorid/productid로 지정 -->
    <vendor id='0x046d'/>
    <product id='0xc52b'/>
  </source>
</hostdev>

<!-- USB 버스/디바이스 번호로 지정 -->
<hostdev mode='subsystem' type='usb' managed='no'>
  <source>
    <address bus='2' device='5'/>
  </source>
</hostdev>

SPICE/VNC 그래픽 설정

<!-- VNC 그래픽 -->
<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1'>
  <listen type='address' address='127.0.0.1'/>
</graphics>

<!-- SPICE 그래픽 (고성능, USB 리다이렉션 지원) -->
<graphics type='spice' autoport='yes'>
  <listen type='address'/>
  <image compression='auto_glz'/>
  <streaming mode='filter'/>
  <gl enable='no'/>
</graphics>

<!-- 비디오 디바이스 -->
<video>
  <model type='virtio' heads='1' primary='yes'>
    <acceleration accel3d='no'/>
  </model>
</video>

features 설정 심화 (hyperv enlightenments)

<features>
  <acpi/><apic/>
  <!-- Windows 게스트 최적화 -->
  <hyperv mode='custom'>
    <relaxed state='on'/>       <!-- 타이머 완화 -->
    <vapic state='on'/>         <!-- 가상 APIC -->
    <spinlocks state='on' retries='8191'/>
    <vpindex state='on'/>       <!-- 가상 프로세서 인덱스 -->
    <runtime state='on'/>       <!-- 런타임 계몽 -->
    <synic state='on'/>         <!-- 합성 인터럽트 컨트롤러 -->
    <stimer state='on'>
      <direct state='on'/>
    </stimer>
    <frequencies state='on'/>   <!-- 레퍼런스 TSC 주파수 -->
    <reenlightenment state='on'/>
    <tlbflush state='on'/>
  </hyperv>
  <!-- KVM 은닉 (게스트가 VM임을 숨김) -->
  <kvm>
    <hidden state='on'/>
  </kvm>
  <!-- IOAPIC KVM 처리 -->
  <ioapic driver='kvm'/>
</features>

네트워크 관리

NAT 네트워크 (기본 virbr0)

# 기본 NAT 네트워크 XML 확인
virsh net-dumpxml default
<network>
  <name>default</name>
  <forward mode='nat'>
    <nat><port start='1024' end='65535'/></nat>
  </forward>
  <bridge name='virbr0' stp='on' delay='0'/>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.122.2' end='192.168.122.254'/>
    </dhcp>
  </ip>
</network>

브리지 네트워크 (물리 인터페이스 연결)

# 호스트에서 브리지 생성 (NetworkManager 사용)
nmcli con add type bridge ifname br0 con-name br0
nmcli con add type bridge-slave ifname eth0 master br0
nmcli con up br0
<network>
  <name>bridged</name>
  <forward mode='bridge'/>
  <bridge name='br0'/>
</network>

SR-IOV VF 직접 할당

<!-- SR-IOV VF를 게스트에 직접 할당 -->
<interface type='hostdev' managed='yes'>
  <source>
    <address type='pci' domain='0x0000' bus='0x01' slot='0x10' function='0x0'/>
  </source>
  <model type='virtio'/>
</interface>

<!-- macvtap 방식 -->
<interface type='direct'>
  <source dev='eth0' mode='bridge'/>
  <model type='virtio'/>
</interface>

Isolated 네트워크 (내부 통신 전용)

<!-- 외부 연결 없는 VM 간 내부 전용 네트워크 -->
<network>
  <name>isolated</name>
  <!-- forward 없음 = 완전 격리 -->
  <bridge name='virbr1' stp='on' delay='0'/>
  <ip address='10.10.10.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='10.10.10.2' end='10.10.10.254'/>
    </dhcp>
  </ip>
</network>

네트워크 필터 (nwfilter)

네트워크 필터는 VM별로 방화벽 규칙을 적용한다. iptables/nftables 규칙을 libvirt가 자동 관리한다.

<!-- nwfilter XML 정의 (예: ARP 스푸핑 방지) -->
<filter name='no-arp-spoofing' chain='arp'>
  <uuid>f88f1932-debf-4aa1-9fbe-f10d3aa4bc95</uuid>
  <rule action='drop' direction='out' priority='300'>
    <arp arpsrcmacaddr='$MAC' arpsrcipaddr='$IP' match='no'/>
  </rule>
  <rule action='accept' direction='out' priority='500'>
    <arp arpsrcmacaddr='$MAC' arpsrcipaddr='$IP'/>
  </rule>
</filter>

<!-- 도메인 인터페이스에 nwfilter 적용 -->
<interface type='network'>
  <source network='default'/>
  <model type='virtio'/>
  <filterref filter='no-arp-spoofing'>
    <parameter name='MAC' value='52:54:00:12:34:56'/>
    <parameter name='IP' value='192.168.122.100'/>
  </filterref>
</interface>

VLAN 태깅 설정

<!-- VLAN 태깅이 있는 네트워크 (브리지 + VLAN) -->
<network>
  <name>vlan100</name>
  <forward mode='bridge'/>
  <bridge name='br0'/>
  <vlan trunk='no'>
    <tag id='100'/>
  </vlan>
</network>

<!-- 도메인 인터페이스에서 VLAN 직접 설정 -->
<interface type='bridge'>
  <source bridge='br0'/>
  <vlan>
    <tag id='200'/>
  </vlan>
  <model type='virtio'/>
</interface>

네트워크 대역폭 제한 (QoS)

<!-- 인터페이스별 대역폭 제한 -->
<interface type='network'>
  <source network='default'/>
  <model type='virtio'/>
  <bandwidth>
    <!-- inbound: VM이 받는 트래픽 제한 -->
    <inbound average='100000' peak='200000' burst='256'/>
    <!-- outbound: VM이 보내는 트래픽 제한 (KB/s) -->
    <outbound average='50000' peak='100000'/>
  </bandwidth>
</interface>
네트워크 모드 비교 NAT 모드 VM VM virbr0 (NAT) 외부 인터넷 VM→외부 가능 외부→VM 불가 Bridge 모드 VM VM br0 (L2 브리지) 물리 네트워크 VM이 실제 IP 할당 양방향 통신 가능 Isolated 모드 VM VM virbr1 (격리) 외부 차단 VM 간 통신만 가능 보안 격리 환경 SR-IOV 모드 VM VM VF1 VF2 PF (물리 NIC) 최고 성능 하드웨어 직접 접근 모드별 특성 비교 NAT: VM이 private IP 사용, 호스트가 SNAT으로 외부 연결. 간단하고 방화벽 불필요. 기본 모드. Bridge: VM이 LAN과 동일 세그먼트의 IP 획득. 외부에서 직접 접근 가능. 서버용으로 적합. Isolated: VM 간 통신만 허용, 외부 완전 차단. 보안 테스트 환경, 내부 클러스터에 적합. SR-IOV: PCIe VF를 VM에 직접 할당. 호스트 오버헤드 없음. 네트워크 집약적 워크로드에 최적. virtio-net multiqueue: 단일 인터페이스에서 다중 RX/TX 큐로 멀티코어 병렬 처리 성능 향상. QoS 대역폭 제한: average(평균), peak(최대), burst(버스트 크기, KB) 단위로 per-VM 제어 가능.

스토리지 풀 관리

libvirt는 스토리지 풀을 통해 VM 이미지와 볼륨을 체계적으로 관리한다.

풀 타입

풀 타입설명용도
dir로컬 디렉토리기본 이미지 저장소
logicalLVM 볼륨 그룹고성능 블록 스토리지
netfsNFS/CIFS 원격 FS공유 스토리지
rbdCeph RBD분산 스토리지
iscsiiSCSI 타겟SAN 스토리지
disk전체 디스크 파티션로컬 디스크 직접 사용
glusterGlusterFS 볼륨스케일-아웃 분산 스토리지

dir 풀 설정 및 볼륨 관리

# dir 풀 생성
virsh pool-define-as mypool dir --target /var/lib/libvirt/myimages
virsh pool-build mypool
virsh pool-start mypool
virsh pool-autostart mypool

# 풀 목록 확인
virsh pool-list --all

# 볼륨 생성 (qcow2, 20GB)
virsh vol-create-as mypool myvm.qcow2 20G --format qcow2

# 볼륨 목록
virsh vol-list mypool

# 볼륨 정보
virsh vol-info myvm.qcow2 --pool mypool

LVM 풀 설정 및 볼륨 관리

LVM 풀은 기존 볼륨 그룹을 libvirt에서 관리한다. 씬 프로비저닝과 빠른 스냅샷을 지원한다.

# 호스트에서 LVM 볼륨 그룹 생성
sudo pvcreate /dev/sdb
sudo vgcreate vg_vms /dev/sdb

# libvirt LVM 풀 정의
virsh pool-define-as lvm-pool logical \
  --source-name vg_vms --target /dev/vg_vms
virsh pool-start lvm-pool
virsh pool-autostart lvm-pool

# LVM 볼륨 생성 (raw 형식)
virsh vol-create-as lvm-pool myvm-lv 20G --format raw

# LVM 볼륨 경로 확인
virsh vol-path --pool lvm-pool myvm-lv
# 출력: /dev/vg_vms/myvm-lv
<!-- LVM 풀 XML 예시 -->
<pool type='logical'>
  <name>lvm-pool</name>
  <source>
    <device path='/dev/sdb'/>
    <name>vg_vms</name>
    <format type='lvm2'/>
  </source>
  <target>
    <path>/dev/vg_vms</path>
  </target>
</pool>

NFS 풀 설정 (netfs 타입)

<!-- NFS 풀 XML -->
<pool type='netfs'>
  <name>nfs-pool</name>
  <source>
    <host name='nfs-server.local'/>
    <dir path='/exports/libvirt'/>
    <format type='nfs'/>
  </source>
  <target>
    <path>/var/lib/libvirt/nfs-images</path>
    <permissions>
      <mode>0755</mode>
    </permissions>
  </target>
</pool>
# NFS 풀 생성 및 시작
virsh pool-define nfs-pool.xml
virsh pool-start nfs-pool
virsh pool-autostart nfs-pool

iSCSI 풀 설정

<!-- iSCSI 풀 XML -->
<pool type='iscsi'>
  <name>iscsi-pool</name>
  <source>
    <host name='iscsi-target.local'/>
    <device path='iqn.2023-01.com.example:storage1'/>
    <!-- CHAP 인증 (시크릿 UUID 참조) -->
    <auth type='chap' username='libvirt'>
      <secret usage='iscsi-chap'/>
    </auth>
  </source>
  <target>
    <path>/dev/disk/by-path</path>
  </target>
</pool>

Ceph RBD 풀 설정

<!-- Ceph RBD 풀 XML -->
<pool type='rbd'>
  <name>ceph-pool</name>
  <source>
    <host name='ceph-mon1.local' port='6789'/>
    <host name='ceph-mon2.local' port='6789'/>
    <name>rbd</name>
    <auth type='ceph' username='libvirt'>
      <secret uuid='550e8400-e29b-41d4-a716-446655440001'/>
    </auth>
  </source>
</pool>
# Ceph 시크릿 등록
cat << 'EOF' > ceph-secret.xml
<secret ephemeral='no' private='no'>
  <uuid>550e8400-e29b-41d4-a716-446655440001</uuid>
  <usage type='ceph'>
    <name>client.libvirt secret</name>
  </usage>
</secret>
EOF
virsh secret-define ceph-secret.xml
virsh secret-set-value 550e8400-e29b-41d4-a716-446655440001 \
  --base64 "$(ceph auth get-key client.libvirt | base64)"

# Ceph RBD 볼륨 생성
virsh vol-create-as ceph-pool myvm-rbd 20G --format raw

볼륨 클론 및 업로드/다운로드

# 볼륨 클론 (같은 풀 내)
virsh vol-clone --pool mypool myvm.qcow2 myvm-clone.qcow2

# 볼륨 업로드 (로컬 파일 → 풀)
virsh vol-upload --pool mypool myvm.qcow2 /tmp/myvm.qcow2 \
  --sparse

# 볼륨 다운로드 (풀 → 로컬 파일)
virsh vol-download --pool mypool myvm.qcow2 /backup/myvm-backup.qcow2 \
  --sparse

# 볼륨 크기 조정 (확장만 가능)
virsh vol-resize --pool mypool myvm.qcow2 50G

qcow2 스냅샷 체인

# 백킹 파일 기반 qcow2 스냅샷 체인 생성
qemu-img create -f qcow2 base.qcow2 20G
qemu-img create -f qcow2 -b base.qcow2 -F qcow2 snap1.qcow2
qemu-img create -f qcow2 -b snap1.qcow2 -F qcow2 snap2.qcow2

# 스냅샷 체인 확인
qemu-img info --backing-chain snap2.qcow2
qcow2 스냅샷 체인 구조 base.qcow2 베이스 이미지 OS 설치 완료 상태 snap1.qcow2 스냅샷 1 base 기반 델타 snap2.qcow2 스냅샷 2 snap1 기반 델타 current.qcow2 현재 활성 실시간 기록 중 backing backing backing 읽기: base <- snap1 <- snap2 <- current (역방향 체인 탐색) 쓰기: 항상 current에만 기록, 아래 레이어는 불변 현재 VM 사용 중

스냅샷 & 마이그레이션

내부 스냅샷 (qcow2 내부)

# 내부 스냅샷 생성 (VM 일시 정지 후)
virsh snapshot-create-as myvm snap1 "스냅샷 설명" --atomic

# 스냅샷 목록
virsh snapshot-list myvm

# 스냅샷 정보
virsh snapshot-info myvm snap1

# 스냅샷으로 복원
virsh snapshot-revert myvm snap1 --running

# 스냅샷 삭제
virsh snapshot-delete myvm snap1

외부 스냅샷 (분리된 파일)

# 외부 스냅샷 생성 (실행 중에도 가능)
virsh snapshot-create-as myvm snap-ext \
  --disk-only \
  --diskspec vda,snapshot=external,file=/tmp/snap-vda.qcow2 \
  --atomic

# 블록 커밋으로 스냅샷 병합 (live block commit)
virsh blockcommit myvm vda --active --pivot

체크포인트 (백업용)

체크포인트는 증분 백업을 위해 어느 블록이 변경되었는지 추적한다. libvirt 6.0+, QEMU 4.2+에서 지원한다.

# 체크포인트 생성
virsh checkpoint-create-as myvm chk1 --diskspec vda,checkpoint=bitmap

# 체크포인트 목록
virsh checkpoint-list myvm

# 체크포인트 XML 확인
virsh checkpoint-dumpxml myvm chk1

# 체크포인트 삭제
virsh checkpoint-delete myvm chk1

라이브 마이그레이션

# 오프라인 마이그레이션
virsh migrate myvm qemu+ssh://destination-host/system

# 라이브 마이그레이션 (무중단)
virsh migrate --live myvm qemu+ssh://destination-host/system

# 공유 스토리지 없는 라이브 마이그레이션 (디스크도 전송)
virsh migrate --live --copy-storage-all \
  myvm qemu+ssh://destination-host/system

# 마이그레이션 상태 확인
virsh domjobinfo myvm

마이그레이션 압축 및 고급 옵션

# xbzrle 압축 마이그레이션 (반복 패이지 압축)
virsh migrate --live --compressed \
  --comp-methods xbzrle \
  myvm qemu+ssh://dest-host/system

# multifd 병렬 마이그레이션 (다중 스트림)
virsh migrate --live \
  --parallel --parallel-connections 4 \
  myvm qemu+ssh://dest-host/system

# 마이그레이션 속도 제한 (대역폭: Mbps)
virsh migrate-setspeed myvm 1000

# 최대 다운타임 설정 (ms)
virsh migrate-setmaxdowntime myvm 200

# post-copy 마이그레이션 (메모리를 점진적으로 전송)
virsh migrate --live --postcopy \
  myvm qemu+ssh://dest-host/system
post-copy 마이그레이션: 메모리를 모두 전송하기 전에 VM을 대상 호스트에서 시작하고, 이후 요청에 따라 페이지를 전송한다. 전환 시간이 짧지만 네트워크 단절 시 VM이 중단될 위험이 있다.
전제 조건: 라이브 마이그레이션은 두 호스트 간에 libvirt가 실행 중이어야 하며, SSH 또는 TLS 인증이 설정되어 있어야 한다. 공유 스토리지 방식은 NFS 등 공유 파일시스템이 필요하다.
라이브 마이그레이션 단계 (pre-copy) ① Setup 연결 수립 대상 도메인 준비 VM: 계속 실행 중 ② Pre-copy 메모리 반복 전송 변경 페이지 재전송 VM: 계속 실행 중 ③ Stop & Copy VM 일시 정지 나머지 상태 전송 VM: 잠시 중단 (다운타임) ④ Resume 대상에서 VM 재개 소스 VM 삭제 VM: 재개됨 소스 호스트 (Source) 대상 호스트 (Destination) 메모리 페이지 스트리밍 (네트워크)

성능 튜닝 통합 정리

KVM/libvirt 환경에서 성능 최적화는 CPU 핀닝, NUMA 정책, Huge Pages, I/O 스케줄러 설정이 핵심이다.

CPU 핀닝 & NUMA 정책 적용 예시

<domain type='kvm'>
  <vcpu placement='static'>8</vcpu>
  <cpu mode='host-passthrough'>
    <numa>
      <cell id='0' cpus='0-3' memory='4' unit='GiB' memAccess='shared'/>
      <cell id='1' cpus='4-7' memory='4' unit='GiB' memAccess='shared'/>
    </numa>
  </cpu>
  <cputune>
    <vcpupin vcpu='0' cpuset='4'/>
    <vcpupin vcpu='1' cpuset='5'/>
    <vcpupin vcpu='2' cpuset='6'/>
    <vcpupin vcpu='3' cpuset='7'/>
    <vcpupin vcpu='4' cpuset='12'/>
    <vcpupin vcpu='5' cpuset='13'/>
    <vcpupin vcpu='6' cpuset='14'/>
    <vcpupin vcpu='7' cpuset='15'/>
    <emulatorpin cpuset='0-1'/>
  </cputune>
  <memoryBacking>
    <hugepages>
      <page size='1' unit='GiB' nodeset='0'/>
      <page size='1' unit='GiB' nodeset='1'/>
    </hugepages>
    <locked/>
  </memoryBacking>
</domain>

IOThread 설정 (스토리지 I/O 분리)

IOThread는 스토리지 I/O를 전용 스레드로 분리하여 vCPU 간섭을 줄인다. NVMe급 성능이 요구되는 환경에 필수적이다.

<!-- IOThread 수 설정 -->
<iothreads>2</iothreads>

<!-- IOThread 핀닝 -->
<cputune>
  <iothreadpin iothread='1' cpuset='2'/>
  <iothreadpin iothread='2' cpuset='3'/>
</cputune>

<!-- 디스크에 IOThread 할당 -->
<disk type='file' device='disk'>
  <driver name='qemu' type='qcow2' cache='none' io='native'
          iothread='1' discard='unmap'/>
  <source file='/var/lib/libvirt/images/myvm.qcow2'/>
  <target dev='vda' bus='virtio'/>
</disk>

스케줄러 정책 설정

<!-- vCPU 스케줄러 정책 (실시간 우선순위) -->
<cputune>
  <vcpusched vcpus='0-7' scheduler='fifo' priority='1'/>
  <iothreadsched iothreads='1' scheduler='fifo' priority='2'/>
</cputune>
주의: FIFO/RR 실시간 스케줄러를 사용하면 CPU 독점 가능성이 있다. ulimit -r 및 cgroup 설정으로 안전 장치를 마련해야 한다.

balloon 메모리 설정 (동적 메모리 조절)

<!-- virtio-balloon 디바이스 (메모리 동적 회수) -->
<memballoon model='virtio'>
  <stats period='5'/>
</memballoon>
# balloon으로 메모리 동적 조절
virsh setmem myvm 4G --live

# balloon 통계 조회
virsh dommemstat myvm

게스트 CPU 플래그 최적화

CPU 모드설명마이그레이션성능
host-passthrough호스트 CPU 그대로 노출동일 CPU만 가능최고
host-model호스트 CPU 모델 추정호환 CPU 간 가능높음
custom특정 CPU 모델 지정광범위한 호환낮음
maximumQEMU 지원 최대 기능TCG용중간

virtio-net multiqueue 성능 설정

<!-- virtio-net multiqueue (queues = vCPU 수와 일치 권장) -->
<interface type='network'>
  <source network='default'/>
  <model type='virtio'/>
  <driver name='vhost' queues='8'/>
</interface>
# 게스트에서 multiqueue 활성화
ethtool -L eth0 combined 8

I/O 최적화 설정

# 게스트 디스크 I/O 스케줄러 확인
cat /sys/block/vda/queue/scheduler

# cache='none': O_DIRECT (최고 성능, 데이터 보호 주의)
# cache='writeback': writeback 캐시 (기본, 성능/안전 균형)
# cache='writethrough': writethrough (안전 우선)

# I/O 통계 모니터링
virsh domblkstat myvm vda --human

성능 측정 명령어

# 종합 도메인 통계 (CPU, 메모리, 블록, 네트워크)
virsh domstats myvm --raw

# 블록 통계
virsh domblkstat myvm vda

# 네트워크 통계
virsh domifstat myvm vnet0

# CPU 사용률 확인 (반복)
watch -n 1 'virsh domstats myvm | grep cpu'

# 메모리 통계 (balloon 활성 시)
virsh dommemstat myvm

# 전체 도메인 통계 덤프
virsh domstats --raw --enforce --domain myvm \
  --balloon --block --cpu-total --vcpu --net

성능 튜닝 체크리스트

항목설정효과비고
CPU 모드host-passthrough네이티브 명령어 사용마이그레이션 제한
vCPU 핀닝vcpupin캐시 미스 감소NUMA 토폴로지 고려
Huge Pages1GB/2MBTLB 미스 감소호스트 사전 설정 필요
메모리 잠금<locked/>스왑 방지Huge Pages 필수 동반
IOThreadvCPU와 별도 cpusetI/O 지연 감소디스크당 1개 권장
디스크 캐시cache='none'더블 버퍼 제거배리어/fsync 주의
네트워크 큐queues=vCPU수멀티코어 처리vhost 드라이버 사용
NUMA 정책cell 기반 분할원격 메모리 접근 감소numactl 병행 사용
투명 Huge Pages호스트 THP 비활성화지터 감소never 설정 권장
CPU Governorperformance주파수 조절 지연 제거전력 소비 증가

libvirt Python API

libvirt Python 바인딩을 사용하면 VM 관리를 프로그래밍 방식으로 자동화할 수 있다. 커널 개발에서 테스트 VM 자동 프로비저닝, 부팅 검증, 로그 수집 등에 활용할 수 있다.

# Python libvirt 바인딩 설치
pip install libvirt-python
import libvirt
import sys
import xml.etree.ElementTree as ET

# libvirtd에 연결
conn = libvirt.open('qemu:///system')
if conn is None:
    print('libvirt 연결 실패')
    sys.exit(1)

# 실행 중인 도메인 목록
domains = conn.listAllDomains()
for dom in domains:
    state, reason = dom.state()
    print(f"{dom.name()}: state={state}")

# 특정 도메인 가져오기
dom = conn.lookupByName('myvm')

# 도메인 시작
if dom.state()[0] == libvirt.VIR_DOMAIN_SHUTOFF:
    dom.create()

# 도메인 XML 파싱
xml_desc = dom.XMLDesc()
root = ET.fromstring(xml_desc)
vcpu_count = root.find('vcpu').text
print(f"vCPU 수: {vcpu_count}")

# 메모리 통계
mem_stats = dom.memoryStats()
print(f"사용 가능 메모리: {mem_stats.get('usable', 0) // 1024} MB")

conn.close()

커널 개발 자동화 스크립트 예제

import libvirt, time, subprocess

def boot_and_test_kernel(kernel_path, initrd_path):
    """커널 빌드 후 자동 부팅 테스트"""
    conn = libvirt.open('qemu:///system')

    try:
        dom = conn.lookupByName('kernel-test')
        if dom.state()[0] != libvirt.VIR_DOMAIN_SHUTOFF:
            dom.destroy()
            time.sleep(2)
    except libvirt.libvirtError:
        pass

    subprocess.run([
        'virt-install', '--name', 'kernel-test',
        '--memory', '2048', '--vcpus', '2',
        '--boot', f'kernel={kernel_path},initrd={initrd_path},'
                  'kernel_args="console=ttyS0 nokaslr panic=-1"',
        '--graphics', 'none', '--noautoconsole'
    ])

    time.sleep(10)
    dom = conn.lookupByName('kernel-test')
    state = dom.state()[0]
    print("부팅 성공" if state == libvirt.VIR_DOMAIN_RUNNING else "부팅 실패")
    conn.close()

이벤트 모니터링

import libvirt

def domain_event_callback(conn, dom, event, detail, opaque):
    """도메인 이벤트 콜백"""
    event_str = {
        libvirt.VIR_DOMAIN_EVENT_STARTED: "시작됨",
        libvirt.VIR_DOMAIN_EVENT_SUSPENDED: "일시 정지됨",
        libvirt.VIR_DOMAIN_EVENT_RESUMED: "재개됨",
        libvirt.VIR_DOMAIN_EVENT_STOPPED: "중지됨",
        libvirt.VIR_DOMAIN_EVENT_SHUTDOWN: "종료 중",
        libvirt.VIR_DOMAIN_EVENT_CRASHED: "크래시됨",
    }.get(event, f"알 수 없음({event})")
    print(f"[이벤트] {dom.name()}: {event_str} (detail={detail})")

conn = libvirt.open('qemu:///system')

# 이벤트 루프 등록
libvirt.virEventRegisterDefaultImpl()

# 도메인 이벤트 구독
conn.domainEventRegisterAny(
    None,
    libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE,
    domain_event_callback,
    None
)

# 이벤트 루프 실행 (블로킹)
while True:
    libvirt.virEventRunDefaultImpl()

도메인 스냅샷 Python API

import libvirt

conn = libvirt.open('qemu:///system')
dom = conn.lookupByName('myvm')

# 스냅샷 생성 XML
snap_xml = """
<domainsnapshot>
  <name>test-snap</name>
  <description>Python API 생성 스냅샷</description>
</domainsnapshot>
"""

snap = dom.snapshotCreateXML(snap_xml,
    libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC)
print(f"스냅샷 생성: {snap.getName()}")

# 스냅샷 목록
for s in dom.listAllSnapshots():
    print(f"  - {s.getName()}")

# 스냅샷 복원
snap = dom.snapshotLookupByName('test-snap')
dom.revertToSnapshot(snap)

conn.close()

네트워크/스토리지 관리 API

import libvirt

conn = libvirt.open('qemu:///system')

# 네트워크 목록
for net in conn.listAllNetworks():
    active = "활성" if net.isActive() else "비활성"
    print(f"네트워크: {net.name()} [{active}]")

# 특정 네트워크 조회
net = conn.networkLookupByName('default')
print(net.XMLDesc())

# 스토리지 풀 목록
for pool in conn.listAllStoragePools():
    info = pool.info()
    print(f"풀: {pool.name()}, 용량: {info[1]//1024//1024//1024}GB")

# 특정 풀의 볼륨 목록
pool = conn.storagePoolLookupByName('default')
for vol in pool.listAllVolumes():
    print(f"  볼륨: {vol.name()}")

conn.close()

통계 수집 및 모니터링 스크립트

import libvirt, time, json

def collect_stats(interval=5):
    """도메인 통계를 주기적으로 수집"""
    conn = libvirt.open('qemu:///system')
    while True:
        stats = {}
        for dom in conn.listAllDomains(
                libvirt.VIR_CONNECT_LIST_DOMAINS_RUNNING):
            name = dom.name()
            cpu_stats = dom.getCPUStats(True)
            mem_stats = dom.memoryStats()
            stats[name] = {
                'cpu_time': cpu_stats[0].get('cpu_time', 0),
                'mem_rss': mem_stats.get('rss', 0) // 1024,
                'mem_available': mem_stats.get('usable', 0) // 1024,
            }
        print(json.dumps(stats, indent=2))
        time.sleep(interval)

collect_stats()

virtiofsd (virtio-fs 데몬)

virtiofsd는 호스트 디렉토리를 게스트에 공유하는 virtio-fs의 사용자 공간 데몬이다. QEMU의 9p virtio보다 성능이 우수하며, DAX(Direct Access) 모드를 지원한다.

virtiofsd 시작

# virtiofsd 시작 (C 구현체, QEMU 내장)
sudo /usr/libexec/virtiofsd \
  --socket-path=/var/run/virtiofsd.sock \
  --shared-dir=/path/to/host/dir \
  --cache=auto \
  --sandbox=namespace

libvirt XML 설정

<devices>
  <!-- virtiofs 파일시스템 공유 -->
  <filesystem type='mount' accessmode='passthrough'>
    <driver type='virtiofs'/>
    <source dir='/path/to/host/dir'/>
    <target dir='hostshare'/>
  </filesystem>
</devices>

<!-- virtiofs는 shared 메모리 설정 필요 -->
<memoryBacking>
  <source type='memfd'/>
  <access mode='shared'/>
</memoryBacking>
# 게스트에서 마운트
mount -t virtiofs hostshare /mnt/host

# /etc/fstab에 추가
hostshare /mnt/host virtiofs defaults 0 0

DAX 윈도우(dax-window) 설정

DAX(Direct Access) 모드는 호스트의 페이지 캐시를 게스트에 직접 매핑한다. 데이터를 두 번 복사하지 않아 메모리 효율과 I/O 성능이 크게 향상된다.

<!-- DAX 윈도우 활성화 (shared memory 매핑) -->
<filesystem type='mount' accessmode='passthrough'>
  <driver type='virtiofs'/>
  <source dir='/path/to/host/dir'/>
  <target dir='hostshare'/>
  <!-- DAX 윈도우 크기 설정 (게스트 메모리 공간 사용) -->
  <driver type='virtiofs' queue='1024'>
    <binary path='/usr/libexec/virtiofsd'>
      <cache mode='auto'/>
      <sandbox mode='namespace'/>
    </binary>
  </driver>
</filesystem>
# virtiofsd DAX 활성화 옵션
sudo virtiofsd \
  --socket-path=/var/run/virtiofsd-dax.sock \
  --shared-dir=/path/to/host/dir \
  --cache=always \
  --announce-submounts \
  --allow-direct-io

캐시 모드 비교

캐시 모드동작일관성성능권장 상황
none캐싱 없음, 매번 호스트 접근강함낮음파일 자주 변경 시
auto열린 파일만 캐시 (close-to-open)중간중간일반 목적 (기본값)
always모든 파일 공격적 캐싱약함높음읽기 전용 데이터셋

보안 모델 옵션 (sandbox)

sandbox 모드설명격리 수준
none격리 없음 (테스트용)낮음
namespaceLinux 네임스페이스 격리중간 (권장)
chrootchroot 격리 (레거시)낮음
seccompsyscall 화이트리스트 필터높음

성능 튜닝 옵션

# 스레드 풀 크기 설정 (기본: 64)
sudo virtiofsd \
  --socket-path=/var/run/virtiofsd.sock \
  --shared-dir=/data \
  --cache=auto \
  --thread-pool-size=128 \
  --writeback \
  --xattr \
  --posix-lock \
  --flock
옵션설명효과
--thread-pool-size=N요청 처리 스레드 수병렬 I/O 처리량 향상
--writebackwriteback 캐시 활성화쓰기 성능 향상
--allow-direct-io게스트 O_DIRECT 허용버퍼 없는 직접 I/O
--announce-submounts서브마운트 알림마운트 포인트 정확한 처리
--xattr확장 속성 지원SELinux/ACL 동작
--posix-lockPOSIX 잠금 전달데이터베이스 파일 안전성
virtiofsd 데이터 흐름 게스트 커널 VFS 레이어 파일 시스템 추상화 virtio-fs 드라이버 FUSE 프로토콜 변환 virtio 링 (공유 메모리) 호스트 사용자 공간 virtiofsd 데몬 FUSE 요청 처리 호스트 VFS 실제 파일시스템 vhost-user 소켓 UNIX 소켓 DAX 모드: 공유 메모리 직접 매핑 (제로 카피) 호스트 페이지 캐시 → 게스트 메모리 공간에 직접 mmap → 복사 없이 접근 일반 모드: 게스트 커널 버퍼 → virtio 링 복사 → virtiofsd → 호스트 VFS (2회 복사) DAX 모드: 게스트 메모리 = 호스트 페이지 캐시 (0회 복사, 메모리 절약)

9p vs virtiofs 성능 비교

항목9p virtiovirtiofs (캐시=auto)virtiofs + DAX
순차 읽기 처리량기준 (1x)3~5x5~10x
순차 쓰기 처리량기준 (1x)2~4x3~6x
메타데이터 레이턴시높음중간중간
랜덤 읽기 IOPS낮음높음매우 높음
메모리 사용량이중 캐싱이중 캐싱단일 캐시 (절약)
POSIX 완전 지원부분거의 완전거의 완전
파일 잠금부분지원지원
mmap 지원제한적지원네이티브 mmap
live 마이그레이션가능가능제한 (DAX 윈도우)
커널 지원오래됨 (v9fs)5.4+ (virtiofs)5.4+ (virtiofs)

virtiofsd Rust 구현체

vhost-device 프로젝트(Rust 구현)는 C 구현 대비 메모리 안전성과 성능이 향상된 virtiofsd를 제공한다. Cloud Hypervisor, Firecracker 등에서 사용된다.

# Rust 구현체 설치 (cargo 사용)
cargo install virtiofsd

# 또는 패키지 설치 (Fedora 38+)
sudo dnf install virtiofsd

# Rust virtiofsd 실행 (옵션 구조 동일)
virtiofsd \
  --socket-path=/var/run/virtiofsd-rust.sock \
  --shared-dir=/path/to/host/dir \
  --cache=auto \
  --sandbox=namespace \
  --log-level=info

# libvirt에서 Rust 구현체 사용 (binary 경로 지정)
<!-- libvirt XML에서 Rust virtiofsd 경로 지정 -->
<filesystem type='mount' accessmode='passthrough'>
  <driver type='virtiofs'>
    <binary path='/usr/bin/virtiofsd'>
      <cache mode='auto'/>
      <sandbox mode='namespace'/>
    </binary>
  </driver>
  <source dir='/path/to/host/dir'/>
  <target dir='hostshare'/>
</filesystem>
성능 비교: virtiofsd는 9p virtio 대비 순차 읽기 기준 약 3~10배 높은 성능을 보인다. DAX 모드를 사용하면 호스트 페이지 캐시를 게스트와 직접 공유하여 메모리 사용량도 절감된다.
다음 학습:
  • 가상화 (KVM) 심화 — KVM 내부 구조, 하드웨어 가상화 확장, 실험 기준선
  • QEMU 실전 가이드 — QMP, OVMF, swtpm, 디버그용 CLI 실습
  • UEFI — 펌웨어, EFI 변수, HTTP Boot, OVMF 디버깅 기초
  • Secure Boot — shim, enrolled keys, UKI, 네트워크 부팅 체인 검증
  • VFIO & mdev (디바이스 패스스루) — IOMMU 그룹, PCI passthrough, mediated device 운영
  • NUMA — vCPU pinning, hugepage, 메모리 locality 튜닝 전제
  • FUSE — virtiofsd와 사용자 공간 파일시스템 구조 심화