콘텐츠로 이동

VM 관리

2.0.0 시작 계약: 정지 VM의 NUMA·2MiB hugepage 요구를 실제 XML로 확인하고 DPDK 준비 뒤 다시 검사합니다.
용량 snapshot은 자원 예약 보장이 아닙니다.
PMSUSPENDED VM은 깨우기 요청 뒤 RUNNING을 확인하며 기존 active CPU 예약을 다시 할당하지 않습니다.

Terminal window
pcvctl vm create \
web-prod \
--vcpu 2 \
--memory_mb 2048 \
--disk_size_gb 20 \
--qos_min_mbps 0 \
--qos_max_mbps 1000

QoS SLA 필수(D09): 커널 netdev(tc 셰이핑 가능) 조합 — network_bridge 미지정/bridge, 또는 tenant-overlay — 은 --qos_min_mbps/--qos_max_mbps가 필수다(nic_type이 dpdk/sriov인 경우만 면제).
생략하면 서버가 vm.create 자체를 -32602로 거부한다.
아래 스토리지 타입 예시들은 지면상 이 두 플래그를 생략했지만 실제 호출에는 포함해야 한다.

VM 디스크의 스토리지 백엔드를 선택할 수 있습니다.
저장 위치 계약의 설계 기준은 ADR-0022: VM 생성 저장 위치 계약을 따른다.

타입설명적합한 용도
zvolZFS 볼륨 (블록 디바이스)고성능 I/O, 스냅샷/복제
qcow2QEMU Copy-on-Write범용, 씬 프로비저닝
rawRAW 이미지최대 I/O 성능
Terminal window
# ZFS zvol (기본, ZFS 풀이 있을 때)
pcvctl vm create db-prod --vcpu 4 --memory_mb 8192 --disk_size_gb 100 --storage_type zvol
# ZFS zvol 저장 위치 지정
pcvctl vm create db-prod --vcpu 4 --memory_mb 8192 --disk_size_gb 100 --storage_type zvol --storage_pool tank/vms
# qcow2 (ZFS 풀 없는 localhost 또는 파일 디스크가 필요한 경우)
pcvctl vm create dev-vm --vcpu 2 --memory_mb 4096 --disk_size_gb 50 --storage_type qcow2
# qcow2 저장 디렉터리 지정
pcvctl vm create dev-vm --vcpu 2 --memory_mb 4096 --disk_size_gb 50 --storage_type qcow2 --image_dir /var/lib/libvirt/images
# RAW (최대 성능)
pcvctl vm create bench-vm --vcpu 8 --memory_mb 16384 --disk_size_gb 200 --storage_type raw

자동 감지: CLI/REST/RPC에서 storage_type을 지정하지 않으면 dispatcher inline vm.create가 vm_manager.c로 위임하고, vm_manager.c가 ZFS 풀 존재 여부를 감지합니다.
ZFS 풀이 있으면 zvol, 없으면 daemon.conf [storage] image_dir에 qcow2로 폴백합니다.
storage_pool 또는 image_dir를 함께 주면 자동 감지 대상 위치도 해당 값으로 바뀝니다.
storage_type=zvol을 명시하면 지정한 ZFS 부모 데이터셋이 없을 때 실패합니다.

Terminal window
pcvctl vm create \
db-prod \
--vcpu 4 \
--memory_mb 8192 \
--disk_size_gb 100 \
--storage_type zvol \
--storage_pool tank/vms \
--network_bridge pcvnat0 \
--iso_path /pcvpool/iso/ubuntu-24.04-live-server-amd64.iso \
--qos_min_mbps 100 \
--qos_max_mbps 500
옵션설명
--network_bridge연결할 브릿지. 미지정 시 관리형 기본 NAT 네트워크([network] default_bridge, 기본 pcvnat0)에 부착. none이면 NIC 미부착
--iso_path설치용 ISO 또는 seed ISO 경로
--storage_type디스크 타입 (zvol, qcow2, raw)
--storage_poolzvol 부모 데이터셋. 예: tank/vms
--image_dirqcow2/raw 파일 디스크 저장 디렉터리. 예: /var/lib/libvirt/images
--templateVM 템플릿 이름
--qos_min_mbpsQoS 보장 대역(Mbit/s). 커널 netdev 셰이핑 대상 VM 은 필수(위 안내 참고)
--qos_max_mbpsQoS 상한 대역(Mbit/s). 0 이면 서버가 거부(> 0 필수)

고급 VM 속성(firmware, boot_mode, tpm, cpu_mode, hugepages, vlan_id, base_image, ovn_switch)은 현재 REST/RPC body로 지정한다.
pcvctl vm create CLI는 위 표의 기본 옵션과 저장 위치 옵션을 직접 파싱한다.

Terminal window
echo '{"jsonrpc":"2.0","method":"vm.create","params":{
"name": "web-prod",
"vcpu": 2,
"memory_mb": 2048,
"disk_size_gb": 20,
"os_variant": "ubuntu24.04",
"storage_type": "zvol",
"storage_pool": "tank/vms",
"network_bridge": "pcvnat0",
"iso_path": "/pcvpool/iso/ubuntu-24.04-live-server-amd64.iso",
"qos_min_mbps": 100,
"qos_max_mbps": 500
},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool
Terminal window
curl -X POST http://127.0.0.1:8080/api/v1/vms \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "web-prod",
"vcpu": 2,
"memory_mb": 2048,
"disk_size_gb": 20,
"storage_type": "zvol",
"network_bridge": "pcvnat0",
"qos_min_mbps": 100,
"qos_max_mbps": 500
}'

응답:

{
"result": {
"accepted": true,
"message": "VM creation started in background"
}
}

fire-and-forget 패턴: VM 생성은 즉시 accepted: true를 반환하고 백그라운드에서 비동기 실행됩니다.
virDomainDefineXML 실패 시 zvol/디스크가 자동 롤백됩니다.

network_bridge에 OVS 브릿지를 지정하면, 데몬이 ovs-vsctl br-exists로 OVS 여부를 자동 확인하고 VM XML에 <virtualport type='openvswitch'/>를 자동 추가합니다.

부팅 디스크 I/O 정책과 메모리 격리 (2.0.0, NXV-F1)

섹션 제목: “부팅 디스크 I/O 정책과 메모리 격리 (2.0.0, NXV-F1)”

2.0.0 현행 정본에서 vm.create가 만드는 도메인 XML에 다음 정책이 항상 적용됩니다.
켜고 끄는 옵션은 없습니다.

항목값이유
부팅 디스크 캐시cache=none호스트 페이지캐시 우회 — zvol/데이터셋 위에서 ZFS ARC와의 이중 캐싱 제거
부팅 디스크 AIOio=nativecache=none(O_DIRECT)과 짝. 버퍼 I/O에서 native AIO는 블로킹될 수 있음
부팅 디스크 discarddiscard=unmap게스트 fstrim이 zvol/qcow2 블록을 실제 해제 → 스냅샷 델타·복제 전송량 감소
메모리 병합<nosharepages/>호스트 KSM의 page-dedup 측면 채널 차단

핫플러그로 붙는 보조 디스크는 이전부터 같은 I/O 정책을 썼습니다.
NXV-F1 시정은 부팅 디스크만 QEMU 기본값 (cache=writeback, io=threads, discard 무시)으로 남아 있던 두 경로의 정책 비대칭을 없앤 것입니다.
전제는 백엔드가 O_DIRECT를 지원한다는 점이며, 지원하지 않는 배치는 비지원입니다.

<nosharepages/>(QEMU mem-merge=off)는 호스트 KSM이 서로 다른 테넌트 VM의 동일 페이지를 병합할 때 생기는 측면 채널을 막습니다 — 병합된 페이지에 쓸 때의 copy 지연을 재는 것만으로 “옆 VM이 이 페이지를 갖고 있는가”를 알아낼 수 있기 때문입니다.
대가는 동종 게스트를 대량 배치할 때의 메모리 절감 포기이며, 도메인별 설정이라 호스트 전역 ksm/run=0보다 되돌리기 쉽습니다.

hugepage 프리플라이트: hugepages=true로 생성하는데 호스트의 2MB 여유 페이지가 부족하면 디스크 프로비저닝 직전에 즉시 실패합니다(필요 개수와 여유 개수를 오류 메시지에 담습니다).
이 검사가 없으면 정의는 성공하고 vm.start가 libvirt 내부 오류로 죽어 “만들 때는 됐는데 켜지지 않는” 불투명한 상태가 됩니다.
판정은 total이 아니라 free 기준이고, sysfs를 읽지 못하면 막지 않습니다 (프리플라이트가 새 실패 지점이 되면 안 되므로).
프리플라이트를 디스크 생성보다 앞에 두는 이유는 뒤에 두면 실패해도 zvol/qcow2가 남기 때문입니다.

vhost-user(DPDK) 공유 메모리: nic_type="dpdk"는 libvirt가 vhost-user 인터페이스에 공유 메모리 backend를 요구하기 때문에 해당 시정 전에는 도메인 정의 자체가 거부되던 죽은 경로였습니다 (unsupported configuration: 'interface' requires shared memory).
NXV-F1은 memoryBacking을 조합으로 조립해 해소했습니다.

조합memoryBacking
dpdk + hugepages<hugepages…/> + <access mode='shared'/>
dpdk만<source type='memfd'/> + <access mode='shared'/>
hugepages만종전과 동일

OVS-DPDK 소켓이 없으면 정의가 통과해도 vm.start는 여전히 실패합니다.
NXV-F1의 시정 범위는 “정의조차 되지 않던” 결함까지입니다.

가상 머신 화면에서 VM을 선택한 뒤 상단 VM 삭제를 누릅니다.
여러 VM은 목록 또는 카드의 체크박스를 선택하고 아래 일괄 삭제 (N) 또는 일괄 작업 → 선택한 VM 삭제를 사용합니다.
전화 폭(600px 이하)은 하단 전원 탭의 VM 카드와 일괄 삭제를 사용합니다.
ADMIN/OPERATOR에게 표시되며 실제 요청은 서버의 소유권·권한 검사를 받습니다.

확인창은 대상 이름 전체와 영구 디스크 삭제 경고를 표시합니다.
단일 삭제는 VM 이름, 일괄 삭제는 표시된 수량 문구(예: 삭제 2)를 정확히 입력해야 진행할 수 있습니다.
실행 중인 VM도 강제 종료됩니다.
취소하면 삭제 요청을 보내지 않습니다.

요청은 하나씩 전송하고 대상별 결과를 남깁니다.
요청 접수 · 완료 미확인은 삭제 완료가 아닙니다.
현재 VM 삭제 서버는 접수만 반환하므로 최종 워커 결과는 감사 로그의 vm.delete 기록을 확인합니다.
목록에서 VM이 사라져도 디스크 정리가 끝났다고 단정하지 않습니다.
결과 창을 닫으면 아직 보내지 않은 요청만 중단하며, 접수된 삭제는 계속됩니다.
통신 오류 시 자동 재전송하지 않습니다.
대상이 없어지거나 동명 VM의 UUID가 바뀌면 삭제 요청을 보내지 않으므로 목록을 새로고침하고 다시 선택합니다.

Terminal window
# 목록 조회
pcvctl vm list
# 시작
pcvctl vm start web-prod
# 정상 중지 (graceful 30초 → force destroy)
pcvctl vm stop web-prod
# 일시 정지 / 재개
pcvctl vm pause web-prod
pcvctl vm resume web-prod
# 삭제 (비동기, 스토리지 포함)
pcvctl vm delete web-prod
# 삭제 진행 상태 확인
pcvctl vm delete-status web-prod

중지 동작 상세:

  1. virDomainShutdown으로 ACPI 셧다운 신호 전송
  2. 1초 간격으로 최대 30초 동안 정상 종료 폴링
  3. 타임아웃 시 virDomainDestroy로 강제 종료
  4. 반환값 검증 후 결과 보고

삭제 진행 상태:

Terminal window
# RPC로 삭제 상태 확인
echo '{"jsonrpc":"2.0","method":"vm.delete.status","params":{"name":"web-prod"},"id":"1"}' \
| nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool

응답 상태값: pending | deleting | done | failed

이름 변경:

VM 이름 변경은 정지된 VM에서만 허용된다.
libvirt domain 이름, 표준 ZFS zvol 또는 표준 qcow2/raw/img 파일 디스크 경로, UEFI NVRAM 경로를 함께 변경한다.

지원 조건:

  • VM 상태가 shut off여야 한다.
  • 새 이름은 pcv_validate_vm_name() 규칙을 따른다.
    허용 문자는 영문, 숫자, 하이픈, 언더스코어이며 최대 64자다.
  • 기본 디스크는 /dev/zvol/<parent>/<vm> 또는 <vm>.qcow2, <vm>.raw, <vm>.img 형식이어야 한다.
  • libvirt snapshot metadata가 남아 있으면 이름 변경을 거부한다.
Terminal window
# CLI
pcvctl vm rename web-prod web-prod-01
# RPC
echo '{"jsonrpc":"2.0","method":"vm.rename","params":{
"name":"web-prod",
"new_name":"web-prod-01"
},"id":"1"}' \
| nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool
Terminal window
# VM 목록
curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8080/api/v1/vms | python3 -m json.tool
# VM 시작
curl -X POST -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8080/api/v1/vms/web-prod/start
# VM 중지
curl -X POST -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8080/api/v1/vms/web-prod/stop
# VM 일시 정지
curl -X POST -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8080/api/v1/vms/web-prod/suspend
# VM 재개
curl -X POST -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8080/api/v1/vms/web-prod/resume
# VM 삭제
curl -X DELETE -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8080/api/v1/vms/web-prod
# VM 이름 변경
curl -X PUT -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"new_name":"web-prod-01"}' \
http://127.0.0.1:8080/api/v1/vms/web-prod/rename
# 삭제 상태 확인
curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8080/api/v1/vms/web-prod/delete-status

실행 중인 VM에 리소스를 동적으로 추가하거나 변경할 수 있습니다.

Terminal window
# vCPU 조정 (라이브)
pcvctl vm set-vcpu web-prod 4
# 메모리 조정 (balloon, MB 단위)
pcvctl vm set-memory web-prod 4096
# CPU 피닝 (특정 물리 코어에 고정)
pcvctl vm pin-vcpu web-prod --vcpu 0 --cpuset 2,3
pcvctl vm pin-vcpu web-prod --vcpu 1 --cpuset 4,5
# CPU 통계 확인
echo '{"jsonrpc":"2.0","method":"vm.cpu.stats","params":{"name":"web-prod"},"id":"1"}' \
| nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool
# 메모리 balloon 통계 확인
echo '{"jsonrpc":"2.0","method":"vm.memory.stats","params":{"name":"web-prod"},"id":"1"}' \
| nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool

메모리 통계 응답 예시:

{
"actual": 4194304,
"rss": 3145728,
"unused": 1048576,
"available": 4194304,
"swap_in": 0,
"swap_out": 0
}
Terminal window
# NIC 목록
pcvctl nic list web-prod
# NIC 추가
pcvctl nic add web-prod --bridge pcvnat0 --model virtio
# NIC 제거 (MAC 주소 지정)
pcvctl nic remove web-prod --mac 52:54:00:ab:cd:ef

model 허용목록: --model은 virtio / e1000 / e1000e / rtl8139만 허용한다.
범위 밖 값은 device.nic.attach에서 -32602 INVALID_PARAMS로 거부된다.

MTU 명시(N8): NIC XML의 <mtu>는 attach 시점 브리지의 실측 MTU(/sys/class/net/<bridge>/mtu)를 1500 포함 항상 명시한다.
자세한 계약은 6.1 절 참조.

Terminal window
# ISO 목록 (설정된 iso_dirs 전체 스캔)
pcvctl iso list
# ISO 마운트
pcvctl iso mount web-prod /pcvpool/iso/ubuntu-24.04-live-server-amd64.iso
# ISO 꺼내기
pcvctl iso eject web-prod
Terminal window
# USB 장치 목록
pcvctl vm usb-list web-prod
# USB 장치 연결
pcvctl vm usb-attach web-prod 0x1234 0x5678
# USB 장치 분리
pcvctl vm usb-detach web-prod 0x1234 0x5678
Terminal window
# 라이브 디스크 확장 (축소 불가, GB 단위)
pcvctl vm disk-resize web-prod vda 50
# REST API
curl -X POST -H "Authorization: Bearer $TOKEN" \
http://127.0.0.1:8080/api/v1/vms/web-prod/disk-resize \
-H "Content-Type: application/json" \
-d '{"new_size_gb": 50}'

주의: ZFS zvol의 경우 zfs set volsize와 virDomainBlockResize가 동시에 수행됩니다.
게스트 OS 내에서 파티션 확장이 별도로 필요할 수 있습니다.

Terminal window
# I/O 제한 설정 (IOPS, bytes/sec)
pcvctl vm disk-throttle web-prod --read-iops 1000 --write-iops 500
pcvctl vm blkio-set web-prod --read_iops 1000 --write_iops 500
# 현재 I/O 제한 조회
pcvctl vm blkio-get web-prod

RPC 직접 호출:

Terminal window
echo '{"jsonrpc":"2.0","method":"vm.blkio.set","params":{
"name": "web-prod",
"device": "vda",
"read_bytes_sec": 104857600,
"write_bytes_sec": 52428800,
"read_iops_sec": 1000,
"write_iops_sec": 500
},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool
Terminal window
# VM 네트워크 대역폭 제한 (KB/s)
pcvctl vm bandwidth web-prod --inbound-kbps 100000 --outbound-kbps 100000
Terminal window
# 스냅샷 생성
pcvctl snapshot create web-prod before-upgrade
# 스냅샷 목록
pcvctl snapshot list web-prod
# 스냅샷 롤백 (fire-and-forget: VM 중지 -> 롤백 -> 재시작)
pcvctl snapshot rollback web-prod before-upgrade
# 스냅샷 삭제
pcvctl snapshot delete web-prod before-upgrade

prefix 패턴 필터와 최근 N개 보존 옵션을 지원합니다.

Terminal window
# "auto-" 프리픽스 스냅샷 중 최근 5개만 보존, 나머지 삭제
pcvctl vm snapshot-delete-all web-prod --prefix auto- --keep 5
# 모든 스냅샷 삭제 (보존 없음)
pcvctl vm snapshot-delete-all web-prod

RPC 직접 호출:

Terminal window
echo '{"jsonrpc":"2.0","method":"vm.snapshot.delete_all","params":{
"name": "web-prod",
"prefix": "auto-",
"keep_recent": 5
},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool
Terminal window
# 스케줄 상태 조회
pcvctl snapshot schedule-status
Terminal window
# 준비된 템플릿: guest reset 생략
pcvctl vm clone web-template web-staging --mode cow --template-prepared
# 일반 VM: target disk 생성 후 libguestfs guest reset 수행
pcvctl vm clone web-prod web-prod-copy --mode full --guest-reset

RPC 직접 호출:

Terminal window
echo '{"jsonrpc":"2.0","method":"vm.clone","params":{
"source": "web-template",
"clone_name": "web-staging",
"mode": "cow",
"template_prepared": true
},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool

안전 제한: vm.clone은 source VM이 shut off 상태일 때만 허용하며, 단일 data disk VM만 지원한다.
template_prepared=true가 없으면 guest_reset=true 경로로 libguestfs-tools의 virt-sysprep, virt-filesystems, guestfish, virt-customize를 실행해야 한다.
qcow2/raw는 추가로 mode=full만 허용한다.
자세한 기준은 ADR-0023을 따른다.

fire-and-forget: 클론은 즉시 accepted: true를 반환하고 백그라운드에서 disk clone + guest reset + XML 패치를 수행합니다.

accepted 응답에는 실제 XML에서 확인한 source/target disk가 포함된다.

{
"status": "accepted",
"source": "web-template",
"clone_name": "web-staging",
"mode": "cow",
"job_id": "vm.clone:web-template:web-staging",
"guest_reset": false,
"storage_type": "zvol",
"source_disk": "/dev/zvol/rpool/web-template",
"target_disk": "/dev/zvol/rpool/web-staging"
}

동작 기준:

  • clone plan은 daemon.conf [storage] zvol_pool이나 image_dir을 추측하지 않고 libvirt XML의 실제 disk source를 기준으로 계산한다.
  • source VM이 power on 상태이면 storage type과 무관하게 preflight에서 거부한다.
  • --mode cow는 source snapshot을 origin으로 유지하는 ZFS CoW clone이다.
  • --mode full은 pcv_spawn_pipe_sync()로 zfs send와 zfs recv를 직접 연결해 독립 zvol을 만든다.
    셸 파이프, 리다이렉션, /tmp 대용량 임시 파일은 사용하지 않으며, 성공 후 source 임시 snapshot은 정리한다.
  • snapshot 생성 이후 worker가 실패하면 target dataset을 먼저 best-effort 정리하고, source 임시 snapshot이 origin으로 필요하지 않으면 함께 best-effort 정리한다.
  • qcow2/raw 파일 디스크는 mode=full에서 qemu-img convert로 별도 target 파일을 만든다.
  • guest_reset=true는 virt-sysprep으로 machine-id, DHCP/SSH/cloud-init 상태, hostname, LVM PV/VG UUID를 분리하고, guestfish로 ext filesystem UUID를 보정하며, virt-customize로 /etc/fstab UUID 참조와 Ubuntu/Rocky 계열 boot artifact 재생성 command를 실행한다.
  • 현재 실환경 완료 범위는 준비된 zvol clone, Ubuntu 24.04 non-LVM qcow2/raw full clone + guest reset, Ubuntu 24.04 LVM qcow2/raw/ZFS zvol full clone + guest reset이다.
    Rocky/RHEL LVM, SELinux enforcing boot smoke는 문서상 후속 검증 항목으로만 유지한다.
  • 이름, UUID, MAC, disk source를 각각 패치한다.
    MAC 재생성은 원본 XML을 한 번만 스캔해 새 MAC이 다시 매칭되는 무한 루프를 방지한다.
  • clone 생성 결과는 자동 기동하지 않는다.
    운영자가 검증 후 수동으로 시작한다.
  • worker 결과는 accepted 응답의 job_id, /var/log/purecvisor/audit.log의 vm.clone 결과, WebSocket job completion으로 확인한다.

Guest reset과 Prepared template 선택 기준:

  • Guest reset은 일반 VM 복제 기본값이다.
    운영 서버에 libguestfs-tools가 설치되어 있어야 하며, target disk 생성 후 machine-id, hostname, SSH/DHCP/cloud-init 상태, filesystem/LVM UUID, /etc/fstab 참조를 새 VM 기준으로 분리한다.
  • Prepared template은 운영자가 이미 guest identity를 정리한 템플릿 VM에만 사용한다.
    이 선택은 guest reset을 건너뛰므로 source VM에 중복 식별자가 남아 있지 않다는 책임은 운영자에게 있다.
  • 두 선택을 동시에 사용할 필요는 없다.
    준비된 템플릿이면 --template-prepared, 일반 VM이면 --guest-reset 또는 기본 Guest reset 경로를 사용한다.

Guest reset 후 로그인 정보:

  • Guest reset은 guest OS의 기존 사용자 계정과 /etc/shadow 비밀번호 해시를 새 값으로 바꾸지 않는다.
    현재 구현은 virt-sysprep의 user-account나 비밀번호 재설정 operation을 사용하지 않는다.
  • 콘솔 로그인은 원본 VM의 기존 계정/비밀번호가 유지되는 것이 기본 동작이다.
  • virt-sysprep defaults는 SSH host key와 사용자 홈의 .ssh 디렉터리를 정리할 수 있다.
    따라서 SSH 키 로그인은 실패할 수 있고, SSH 비밀번호 로그인 가능 여부는 guest OS의 sshd 설정에 따른다.
  • cloud-init으로 생성한 webadmin 계정도 평문 비밀번호를 복구할 수 있다고 가정하면 안 된다.
    Ubuntu autoinstall의 identity.password는 보통 $6$... 형태의 SHA-512 crypt 해시로 들어가며, 운영 문서에는 해시 원문도 저장하지 않는다.
  • autoinstall seed에 chage -d 0 webadmin이 포함된 VM은 첫 로그인 시 비밀번호 변경을 요구할 수 있다.
  • webadmin 접속 복구가 필요하면 source/target VM을 종료한 뒤 sudo virt-customize -d <vm_name> --password webadmin:password:'새비밀번호'로 새 비밀번호를 주입하고 수동 boot smoke를 수행한다.

실환경 확인 예시:

Terminal window
sudo pcvctl vm clone example-vm-source example-vm-clone --mode cow --template-prepared
virsh -c qemu:///system list --all | grep example-vm-clone
sudo zfs list -H -o name,origin rpool/example-vm-clone

예상 결과:

example-vm-clone shut off
rpool/example-vm-clone rpool/example-vm-source@clone-example-vm-clone

full clone 확인 예시:

Terminal window
sudo pcvctl --format=json vm clone example-vm-source example-vm-full-clone --mode full --template-prepared
virsh -c qemu:///system dominfo example-vm-full-clone
sudo zfs list -H -o name,origin rpool/example-vm-full-clone
sudo zfs list -t snapshot -H -o name rpool/example-vm-source@clone-example-vm-full-clone || echo "not found"

예상 결과:

example-vm-full-clone shut off / Persistent: yes
rpool/example-vm-full-clone -
not found

2026-04-29 KST 운영 서버 검증에서는 위 full clone 경로가 accepted, target zvol origin=-, source 임시 snapshot 없음, audit result=ok로 확인됐다.
이어 Ubuntu 24.04 non-LVM qcow2/raw와 Ubuntu 24.04 LVM qcow2/raw/ZFS zvol clone은 guest reset, hostname/machine-id 재생성, filesystem UUID 분리, LVM PV/VG UUID 분리, /etc/fstab UUID 참조 갱신, 수동 boot smoke까지 성공했다.

클론 후 독립 데이터셋으로 전환하려면:

Terminal window
# ZFS 프로모트 (원본 스냅샷 의존 해소)
pcvctl storage promote rpool/web-staging
Terminal window
# OVA 내보내기 (qemu-img VMDK 변환 + OVF + tar)
pcvctl vm export-ova web-prod --output-dir /tmp
# OVA 가져오기
pcvctl vm import-ova /tmp/web-prod.ova web-imported

QEMU Guest Agent는 VM 내부 패키지와 libvirt channel이 함께 있어야 사용할 수 있다.
v1.1부터 vm create가 생성하는 VM에는 guest-agent channel이 기본 포함되므로 신규 VM은 별도 보정이 필요 없다(패키지만 VM 내부에서 설치).
guest-agent-ensure-channel은 채널이 없는 기존/레거시 VM 보정용이다.
PureCVisor는 상태 진단과 channel 보정을 함께 제공한다.

Web UI에서는 대시보드 > 요약에서 VM을 선택한 뒤 Storage 카드의 디스크 사용량 버튼으로 게스트 파일시스템 사용량을 확인한다.
이 조회는 qemu-guest-agent의 고정 guest-get-fsinfo 명령만 사용하며, 임의 guest-exec 명령을 실행하지 않는다.

Terminal window
# Guest Agent 상태 진단
pcvctl vm guest-agent-status web-prod
echo '{"jsonrpc":"2.0","method":"vm.guest.agent.status","params":{"name":"web-prod"},"id":"1"}' \
| nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool
# 기존 VM XML에 Guest Agent channel 보정
pcvctl vm guest-agent-ensure-channel web-prod
echo '{"jsonrpc":"2.0","method":"vm.guest.agent.ensure_channel","params":{"name":"web-prod"},"id":"1"}' \
| nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool
# Guest Agent 연결 확인 (5초 타임아웃)
pcvctl vm guest-ping web-prod
echo '{"jsonrpc":"2.0","method":"vm.guest.ping","params":{"name":"web-prod"},"id":"1"}' \
| nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool
# Guest Agent를 통한 안전한 셧다운 (ACPI 폴백)
pcvctl vm guest-shutdown web-prod
echo '{"jsonrpc":"2.0","method":"vm.guest.shutdown","params":{"name":"web-prod"},"id":"1"}' \
| nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool
# Guest Agent를 통한 명령 실행 (base64 stdout/stderr)
pcvctl vm guest-exec web-prod "hostname -I"
echo '{"jsonrpc":"2.0","method":"vm.guest.exec","params":{
"name":"web-prod",
"command":"hostname -I"
},"id":"1"}' | nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool
# 게스트 파일시스템 디스크 사용량 조회
echo '{"jsonrpc":"2.0","method":"vm.guest.fsinfo","params":{"name":"web-prod"},"id":"1"}' \
| nc -U /var/run/purecvisor/daemon.sock | python3 -m json.tool

REST API:

Terminal window
# Guest Agent 상태 진단
curl -H "Authorization: Bearer $TOKEN" \
http://127.0.0.1:8080/api/v1/vms/web-prod/guest-agent
# Guest Agent channel 보정
curl -X POST -H "Authorization: Bearer $TOKEN" \
http://127.0.0.1:8080/api/v1/vms/web-prod/guest-agent-channel
# Guest Agent ping
curl -X POST -H "Authorization: Bearer $TOKEN" \
http://127.0.0.1:8080/api/v1/vms/web-prod/guest-ping
# Guest Agent 명령 실행
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
http://127.0.0.1:8080/api/v1/vms/web-prod/guest-exec \
-d '{"command": "cat /etc/hostname"}'
# 게스트 파일시스템 디스크 사용량 조회
curl -H "Authorization: Bearer $TOKEN" \
http://127.0.0.1:8080/api/v1/vms/web-prod/disk-usage

VM 내부 설치 명령:

Terminal window
# Debian / Ubuntu
sudo apt update && sudo apt install -y qemu-guest-agent
sudo systemctl enable --now qemu-guest-agent
# RHEL / Rocky / Fedora
sudo dnf install -y qemu-guest-agent
sudo systemctl enable --now qemu-guest-agent

상태 해석:

상태의미다음 조치
okchannel이 있고 agent ping 성공정상
channel_missingVM XML에 guest agent channel이 없음guest-agent-channel 보정
reboot_required영구 XML에는 channel이 있으나 실행 중 VM에는 아직 없음VM 재시작 또는 live attach 재시도
agent_unavailablechannel은 있으나 VM 내부 agent가 응답하지 않음VM 내부 qemu-guest-agent 설치/시작
vm_stoppedchannel은 있으나 VM이 꺼져 있어 ping 불가VM 시작 후 재확인

템플릿을 사용하면 사전 정의된 설정으로 빠르게 VM을 생성할 수 있습니다.

Terminal window
# 프리셋 템플릿 목록
pcvctl template list
# 템플릿 생성
pcvctl template create web \
--vcpu 2 \
--memory_mb 2048 \
--disk_gb 20 \
--os_variant ubuntu24.04
# 템플릿으로 VM 생성
pcvctl template apply web --name web-prod-01
# 템플릿 삭제
pcvctl template delete web

이름 검증: 템플릿 이름은 pcv_validate_vm_name() 규칙을 따릅니다 (영문소문자, 숫자, 하이픈, 최대 64자).

Terminal window
# 개별 VM 메트릭
pcvctl monitor vm web-prod

출력 예시:

VM: web-prod (running)
CPU: 15.2%
Memory: 1024/2048 MB (50.0%)
Disk: 8.5 GB / 20 GB
Net RX: 1.2 MB/s TX: 0.3 MB/s
Terminal window
# 전체 VM 일괄 메트릭 (fleet 뷰)
pcvctl monitor fleet

출력 예시(사이버 테마):

ENTITY_ID │ LIFELINE │ CPU_TIME │ MEM%
──────────────────────┼────────────┼──────────┼────────
example-vm-source │ RUNNING │ 63.0s │ 26.4%
fitlog │ RUNNING │ 50.7s │ 17.2%

PLAIN/CSV(--format=plain/--csv)는 헤더가 NAME,STATE,CPU_TIME,MEM%로 바뀐다.
CPU_TIME은 누적 CPU 시간(초, 예 63.0s, 값 없으면 -)이고 MEM%는 mem_used_mb/mem_max_mb*100이다(정지 VM 등 계산 불가 시 N/A).

REST API:

Terminal window
# 개별 VM 메트릭
curl -s -H "Authorization: Bearer $TOKEN" \
http://127.0.0.1:8080/api/v1/vms/web-prod/metrics | python3 -m json.tool