가상화 기초 — KVM/libvirt
테스트 서버 한 대가 남아 개발팀 3개 팀이 서로 쓰겠다고 다툽니다. 물리 서버를 더 사기엔 예산이 없고, 한 대를 셋이 나눠 쓰자니 패키지 충돌로 매번 환경이 깨집니다.
선임이 "그거 그냥 KVM으로 VM 세 개 띄워"라고 합니다. virsh list 를 쳐보니 이미 죽어 있는 VM 두 개가 있고, 하나는 virsh start 하자마자 "cannot access storage file: Permission denied" 로 거부됩니다. qcow2 이미지의 소유권과 SELinux 레이블 문제였습니다.
가상화는 "서버 한 대를 여러 대처럼" 쓰는 가장 기본적인 인프라 기술입니다. 클라우드 인스턴스의 정체이기도 합니다. KVM/libvirt로 VM을 만들고, 띄우고, 안 뜰 때 어디를 봐야 하는지를 이 모듈에서 직접 해봅니다.
클라우드 이전의 온프레미스 환경에서, 그리고 지금도 프라이빗 클라우드 환경에서 KVM은 현역입니다. "서버 1대에 10개의 가상 서버"를 만드는 기술 — 이게 가상화입니다. AWS EC2도 내부적으로는 이런 기술 위에서 돌아갑니다.
KVM을 알면 AWS EC2가 어떻게 동작하는지 이해가 됩니다. 원리를 알면 클라우드도 더 잘 쓸 수 있습니다.
- 1하이퍼바이저 Type 1·2·1.5를 구분하고 KVM의 위치를 설명할 수 있다
- 2KVM을 설치하고 하드웨어 가상화 지원 여부를 확인할 수 있다
- 3virt-install로 명령줄에서 VM을 생성할 수 있다
- 4virsh로 VM 생명주기(시작·정지·스냅샷)를 관리할 수 있다
- 5NAT와 브리지 네트워크 차이를 이해하고 VM 네트워크를 진단할 수 있다
- 6KVM·QEMU·libvirt의 역할을 구분해 클라우드 동작 원리와 연결할 수 있다
하이퍼바이저 타입과 KVM 위치
확대
- Type 1 (베어메탈) — 하드웨어 위에 하이퍼바이저를 직접 설치합니다. 예: VMware ESXi, Hyper-V, Xen. 성능이 가장 높아 운영 서버에 씁니다.
- Type 2 (호스트 OS 위) — 일반 OS 위에서 앱처럼 동작합니다. 예: VirtualBox, VMware Workstation. 데스크톱·개발용이며 OS 계층만큼 오버헤드가 있습니다.
- KVM (Type 1.5) — 리눅스 커널 자체가 하이퍼바이저 역할을 합니다. CPU의 VT-x/AMD-V 가속을 직접 써서 성능이 Type 1에 근접하며, AWS EC2도 이 기술 위에서 동작합니다.
# KVM 커널 모듈 확인
lsmod | grep kvm
# kvm_intel (Intel CPU) 또는 kvm_amd (AMD CPU)
# 가상화 가속 지원 확인
sudo kvm-ok
# INFO: /dev/kvm exists
# KVM acceleration can be used ← OK
KVM · QEMU · libvirt — 누가 무엇을 하는가
"KVM만 설치하면 된다"는 흔한 오해입니다. KVM은 CPU 가속만 담당하고, 디스크·NIC 같은 장치는 QEMU가 에뮬레이션하며, 그 조합을 libvirt가 관리합니다. 세 계층이 각자 다른 일을 하므로 역할을 구분해 두어야 문제가 났을 때 어디를 봐야 할지 알 수 있습니다.
확대
- KVM (커널 모듈) — VT-x/AMD-V로 게스트 CPU 코드를 호스트에서 직접 실행합니다.
- QEMU — VM이 보는 디스크·네트워크 카드·USB 등 I/O 디바이스를 소프트웨어로 에뮬레이션합니다.
- libvirt — QEMU-KVM 조합을 표준 API로 추상화합니다.
virsh·virt-install이 libvirt를 통해 VM을 제어하며,virsh dominfo는 호스트 측 메타데이터만 보여줍니다(VM 내부 프로세스는 SSH로 접속해 확인).
virt-install — VM 생성
# Ubuntu 22.04 VM 생성 예시
sudo virt-install \
--name ubuntu-test \
--ram 2048 \
--vcpus 2 \
--disk path=/var/lib/libvirt/images/ubuntu-test.qcow2,size=20 \
--os-variant ubuntu22.04 \
--cdrom /tmp/ubuntu-22.04-server-amd64.iso \
--network network=default \
--graphics none \
--console pty,target_type=serial \
--extra-args 'console=ttyS0,115200n8 serial'
# 주요 옵션 설명
# --name: VM 이름
# --ram: 메모리 MB
# --vcpus: 가상 CPU 수
# --disk: 디스크 경로 + 크기(GB)
# --os-variant: OS 최적화 설정 (osinfo-query os 로 목록 확인)
# --network: NAT (default) 또는 bridge=br0 (브리지)
# 지원 OS 목록 확인
osinfo-query os | grep ubuntu
# 기존 이미지로 빠르게 VM 만들기 (클라우드 이미지 활용)
# Ubuntu cloud image 다운로드
wget https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img
# 이미지 크기 확장
qemu-img resize jammy-server-cloudimg-amd64.img +20G
# cloud-init 설정 ISO 생성
cat > user-data << 'EOF'
#cloud-config
password: mypassword
chpasswd: { expire: False }
ssh_pwauth: True
EOF
cloud-localds user-data.iso user-data
# VM 생성
sudo virt-install \
--name ubuntu-cloud \
--ram 2048 --vcpus 2 \
--disk jammy-server-cloudimg-amd64.img \
--disk user-data.iso,device=cdrom \
--os-variant ubuntu22.04 \
--network network=default \
--import --noautoconsole
virsh — VM 생명주기 관리
# ── 기본 관리 ──
virsh list --all # 전체 VM 목록 (실행 중 + 중지된 것)
virsh dominfo ubuntu-test # VM 상세 정보 (메모리, CPU, 상태)
virsh domstate ubuntu-test# 현재 상태만
# 시작/정지/재시작
virsh start ubuntu-test
virsh shutdown ubuntu-test # 정상 종료 (OS shutdown 신호)
virsh destroy ubuntu-test # 강제 종료 (전원 차단)
virsh reboot ubuntu-test
# 콘솔 접속
virsh console ubuntu-test # 직렬 콘솔 (Ctrl+] 로 나가기)
# ── 스냅샷 ──
# 스냅샷 생성 (OS 업그레이드 전)
virsh snapshot-create-as ubuntu-test \
--name "before-upgrade" \
--description "Ubuntu 22.04 → 24.04 업그레이드 전"
# 스냅샷 목록
virsh snapshot-list ubuntu-test
# 스냅샷으로 롤백
virsh snapshot-revert ubuntu-test before-upgrade
# 스냅샷 삭제 (누적되면 성능 저하)
virsh snapshot-delete ubuntu-test before-upgrade
# ── 리소스 조정 ──
# 메모리 런타임 조정 (최대값 내에서)
virsh setmem ubuntu-test 4096M --live
# CPU 런타임 조정
virsh setvcpus ubuntu-test 4 --live --maximum
# ── VM 설정 편집 ──
virsh edit ubuntu-test # XML 설정 편집 (저장 후 재시작 필요)
virsh dumpxml ubuntu-test # 현재 설정 XML 출력
- virsh list --all 출력에서 먼저 State 컬럼을 확인하고 — running이면 정상, shut off면 virsh start로 시작, paused면 virsh resume으로 재개
- KVM 지원 수치 기준: egrep -c "(vmx|svm)" /proc/cpuinfo 결과가 1 이상이면 사용 가능, 0이면 BIOS에서 VT-x/AMD-V를 활성화하거나 중첩 가상화가 지원되는 환경 필요
- virsh start 성공 후 virsh console에서 로그인 프롬프트가 안 나오면 → 직렬 콘솔 미설정, virsh console 응답 없이 멈추면 → 게스트 OS 부팅 중 오류(virsh domblkerror로 확인)를 의미
VM 네트워크 — NAT vs 브리지
# ── 현재 네트워크 확인 ──
virsh net-list --all
# Name State Autostart Persistent
# default active yes yes
virsh net-info default
# Bridge: virbr0 ← 호스트의 가상 브리지
ip addr show virbr0
# inet 192.168.122.1/24 ← VM들의 게이트웨이
# ── NAT 모드 (기본) ──
# VM → 외부: 가능 (호스트 NAT 통해)
# 외부 → VM: 포트 포워딩 필요
# 용도: 개발/테스트 환경
# VM에서 호스트 접근
# 게이트웨이: 192.168.122.1 (호스트)
# ── 브리지 모드 (실제 네트워크 직접 연결) ──
# VM이 물리 스위치에 직접 연결된 것처럼 동작
# DHCP에서 실제 IP 할당
# 용도: 운영 서버, 외부 접근 필요한 환경
# 브리지 생성 (/etc/netplan/01-netcfg.yaml)
network:
version: 2
ethernets:
ens3:
dhcp4: false
bridges:
br0:
interfaces: [ens3]
dhcp4: true
# VM을 브리지에 연결
virt-install ... --network bridge=br0
KVM/libvirt 설치 및 하드웨어 가상화 지원 확인
egrep -c '(vmx|svm)' /proc/cpuinfo && sudo apt install qemu-kvm libvirt-daemon-system virtinst -y 2>/dev/null | tail -3예상 출력
4 (0보다 크면 하드웨어 가상화 지원) libvirt-daemon-system is already the newest version
libvirtd 서비스 시작 및 기본 네트워크 확인
sudo systemctl enable --now libvirtd && virsh net-list --all예상 출력
Name State Autostart Persistent default active yes yes
현재 VM 목록 확인
virsh list --all예상 출력
Id Name State ------------------- (VM이 없으면 빈 목록 표시)
virbr0 네트워크 브리지 확인
ip addr show virbr0예상 출력
virbr0: <...> mtu 1500
inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0$ virsh start myvm
error: Failed to start domain 'myvm'
error: internal error: process exited while connecting to monitor:
qemu-system-x86_64: -drive file=/var/lib/libvirt/images/myvm.qcow2:
Could not open '/var/lib/libvirt/images/myvm.qcow2':
Permission denied
원인: QEMU 프로세스는 libvirt-qemu 사용자로 실행됩니다. 디스크 이미지 파일의 소유권이나 권한이 맞지 않으면 접근 불가.
# 권한 확인
ls -la /var/lib/libvirt/images/myvm.qcow2
# 수정
sudo chown libvirt-qemu:kvm /var/lib/libvirt/images/myvm.qcow2
sudo chmod 660 /var/lib/libvirt/images/myvm.qcow2
# 또는 이미지를 libvirt 기본 경로에 복사
sudo mv myvm.qcow2 /var/lib/libvirt/images/
sudo chown root:root /var/lib/libvirt/images/myvm.qcow2
AppArmor가 막는 경우 (Ubuntu):
# AppArmor 로그 확인
sudo aa-status | grep qemu
sudo journalctl -k | grep apparmor | grep DENIED
# 임시 해제 (테스트용)
sudo aa-complain /usr/sbin/libvirtd
# 근본 해결: 이미지를 /var/lib/libvirt/images/ 아래에만 사용
KVM이 쓰이는 실제 환경
온프레미스 서버 운영 환경:
─────────────────────────────
물리 서버 (64GB RAM, 32 코어)
│
├── VM: web-server-01 (4GB RAM, 2 core) → Nginx
├── VM: web-server-02 (4GB RAM, 2 core) → Nginx
├── VM: db-primary (16GB RAM, 8 core) → PostgreSQL
├── VM: db-replica (16GB RAM, 8 core) → PostgreSQL
└── VM: monitoring (4GB RAM, 2 core) → Grafana
실무 운영 명령 모음:
# VM 일괄 상태 확인
virsh list --all
# VM 디스크 사용량 확인
du -sh /var/lib/libvirt/images/*.qcow2 | sort -rh
# VM 복제 (템플릿에서 빠르게 생성)
virt-clone --original ubuntu-template \
--name web-server-03 \
--file /var/lib/libvirt/images/web-server-03.qcow2
# 백업 (디스크 이미지 복사)
virsh suspend myvm # 일시 정지
cp /var/lib/libvirt/images/myvm.qcow2 /backup/myvm-$(date +%Y%m%d).qcow2
virsh resume myvm # 재개
# 호스트 종료 전 VM 전부 종료
for vm in $(virsh list --name); do virsh shutdown "$vm"; done
KVM vs 클라우드 VM 개념 매핑:
| KVM | AWS |
|---|---|
| VM 생성 (virt-install) | EC2 인스턴스 시작 |
| 디스크 이미지 (.qcow2) | EBS 볼륨 |
| 스냅샷 (virsh snapshot) | AMI / EBS 스냅샷 |
| 브리지 네트워크 | VPC + 서브넷 |
| libvirt NAT | Security Group (기본 차단) |
클라우드를 쓰더라도 KVM을 알면 "EC2 인스턴스가 결국 이런 것이구나"를 이해하고, 네트워크 문제나 성능 이슈를 훨씬 체계적으로 디버깅할 수 있습니다.
다음 모듈에서는 Ansible 기초 — 에이전트 없이 SSH로 수십 대 서버를 동시에 설정하고 자동화하는 방법을 다룹니다.