Initial: PVE VM 원격 제어 가이드 + VirtIO 마이그레이션 함정 분석
- GUIDE.ko.md: VM 원격 제어 (화면 캡처, QGA, qm sendkey, vhd 임포트, DR 이전, 트러블슈팅) - JOURNEY.md: SATA→VirtIO-SCSI 마이그레이션 실패 연대기 15단계 - 핵심 발견: vioscsi START_TYPE=BOOT_START(0) 승격 필수 (pnputil만으론 부족) - screenshots: 부팅 검증 화면 검증 환경: PVE 8.1, Win10 Pro 19045, virtio-win 0.1.285
This commit is contained in:
391
GUIDE.ko.md
Normal file
391
GUIDE.ko.md
Normal file
@@ -0,0 +1,391 @@
|
||||
# VM 원격 제어 가이드 (PVE + QEMU)
|
||||
|
||||
> Claude Code 환경에서 Proxmox 위의 Windows/Linux VM을 화면 캡처 + 명령 실행 + GUI 조작까지 원격으로 다루는 방법.
|
||||
>
|
||||
> 작성일: 2026-05-18 / 검증 환경: Windows 10 Pro VM on Proxmox VE 8.1, virtio-scsi-single + iothread + discard
|
||||
|
||||
## 표기 규약
|
||||
|
||||
- `<PVE_HOST>` `<PVE_HOST_2>`: Proxmox 노드 IP
|
||||
- `<PVE_PASSWORD>` `<PVE_PASSWORD_2>`: 각 노드 root 비밀번호 (또는 SSH key 사용 권장)
|
||||
- `<SMB_HOST>` `<SMB_USER>` `<SMB_PASSWORD>`: SMB/CIFS 파일 서버 접속 정보
|
||||
- `<windows_user>`: Windows 게스트 로그인 사용자
|
||||
- VMID 예시는 `101`, zvol 예시는 `vm-101-disk-N` — 본인 환경 값으로 치환
|
||||
|
||||
---
|
||||
|
||||
## 1. 인프라 개요
|
||||
|
||||
### Proxmox 호스트
|
||||
| 호스트 | IP | SSH | 비고 |
|
||||
|---|---|---|---|
|
||||
| pve5 | `<PVE_HOST>` | `root` / `<PVE_PASSWORD>` | 메인 VM 호스트 (운영) |
|
||||
| pve7 | `<PVE_HOST_2>` | `root` / `<PVE_PASSWORD_2>` | 보조 / 백업 호스트 |
|
||||
|
||||
### SMB 파일 서버
|
||||
- 주소: `<SMB_HOST>`
|
||||
- 인증: `<SMB_USER>` / `<SMB_PASSWORD>`
|
||||
- 주요 공유: `vhd` (VHD 디스크 이미지 보관)
|
||||
|
||||
### 접속 패턴
|
||||
```bash
|
||||
# pve5 SSH (모든 VM 작업은 여기서)
|
||||
sshpass -p "$PVE_PASSWORD" ssh -o StrictHostKeyChecking=no root@<PVE_HOST> '<명령>'
|
||||
|
||||
# SMB 마운트 (pve5 또는 작업 VM에서)
|
||||
mkdir -p /mnt/vhd-src
|
||||
mount -t cifs //<SMB_HOST>/vhd /mnt/vhd-src \
|
||||
-o username=<SMB_USER>,password=$SMB_PASSWORD,ro,vers=3.0,iocharset=utf8,file_mode=0444,dir_mode=0555
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. VM 화면 캡처 (보기)
|
||||
|
||||
PVE 8.x에는 `qm screendump` 명령이 **없음**. QEMU monitor에 직접 명령 보내야 함.
|
||||
|
||||
### 한 줄 캡처 (pve5에서)
|
||||
```bash
|
||||
echo "screendump /tmp/vm101.ppm" | qm monitor 101
|
||||
```
|
||||
|
||||
결과는 PPM(Netpbm raw bitmap) 형식. 일반 뷰어가 못 읽으므로 PNG로 변환 필요.
|
||||
|
||||
### Claude 환경에서 보기까지 풀 흐름
|
||||
```bash
|
||||
# 1) pve5에서 screendump
|
||||
sshpass -p "$PVE_PASSWORD" ssh root@<PVE_HOST> \
|
||||
'echo "screendump /tmp/vm101.ppm" | qm monitor 101'
|
||||
|
||||
# 2) PPM 가져오기
|
||||
sshpass -p "$PVE_PASSWORD" scp root@<PVE_HOST>:/tmp/vm101.ppm /tmp/vm101.ppm
|
||||
|
||||
# 3) PNG 변환 (ffmpeg는 작업 VM에 설치돼있음, pve5에는 없음)
|
||||
ffmpeg -y -i /tmp/vm101.ppm /tmp/vm101.png
|
||||
|
||||
# 4) Read 툴로 열기 → 멀티모달 모델이 이미지 인식
|
||||
```
|
||||
|
||||
### PVE API 방식 (대안)
|
||||
```bash
|
||||
pvesh get /nodes/pve5/qemu/101/screenshot > /tmp/vm101.png
|
||||
```
|
||||
*이 엔드포인트는 PNG 직접 반환. 단 PVE 권한 토큰 설정에 따라 동작 여부 다름.*
|
||||
|
||||
---
|
||||
|
||||
## 3. QGA (QEMU Guest Agent)로 명령 실행
|
||||
|
||||
### 전제 조건
|
||||
- VM config에 `agent: 1`
|
||||
- 게스트 OS에 qemu-ga 서비스 설치/실행 중
|
||||
- 확인: `qm agent <vmid> ping` (응답 없으면 = OK)
|
||||
|
||||
### 핵심 명령
|
||||
```bash
|
||||
# 상태 확인
|
||||
qm agent 101 ping
|
||||
qm agent 101 get-osinfo
|
||||
qm agent 101 get-host-name
|
||||
qm agent 101 get-users
|
||||
|
||||
# 명령 실행 (동기 / 결과 회수)
|
||||
qm guest exec 101 --timeout 30 -- cmd.exe /c whoami
|
||||
qm guest exec 101 --timeout 30 -- powershell.exe -NoProfile -Command "<script>"
|
||||
qm guest exec 101 --timeout 30 -- C:\Path\To\program.exe arg1 arg2
|
||||
|
||||
# 비동기 (PID만 받고 나중에 결과)
|
||||
PID=$(qm guest exec 101 --no-wait -- powershell.exe -Command "Start-Sleep 60" | jq -r .pid)
|
||||
qm guest exec-status 101 $PID # 진행 상태/exit code/stdout 회수
|
||||
```
|
||||
|
||||
### 파일 송수신
|
||||
```bash
|
||||
# 게스트로 파일 쓰기 (base64 또는 raw content)
|
||||
qm guest file-write 101 'C:\temp\script.ps1' --content "$(cat local.ps1)"
|
||||
|
||||
# 게스트에서 파일 읽기
|
||||
qm guest file-read 101 'C:\temp\output.txt'
|
||||
```
|
||||
|
||||
### ⚠️ 권한과 세션
|
||||
- QGA로 실행된 프로세스는 **NT AUTHORITY\SYSTEM (Session 0, 비대화형 서비스 세션)** 으로 동작
|
||||
- GUI를 띄워도 **사용자 데스크톱에 안 보임** (Windows 보안상 분리)
|
||||
- 시스템 권한이라 거의 모든 작업 가능 (레지스트리, 서비스, 파일)
|
||||
- 단 사용자 프로필(`%USERPROFILE%`)이 SYSTEM 계정 기준임에 주의
|
||||
|
||||
---
|
||||
|
||||
## 4. qm sendkey로 GUI 조작
|
||||
|
||||
키보드 이벤트를 QEMU에 직접 주입. **현재 포커스 있는 곳(=로그인 사용자 데스크톱)** 에 입력됨.
|
||||
|
||||
### 기본 사용
|
||||
```bash
|
||||
qm sendkey 101 <key>
|
||||
```
|
||||
|
||||
### 주요 키 이름
|
||||
| 키 | 이름 |
|
||||
|---|---|
|
||||
| Enter | `ret` 또는 `kp_enter` |
|
||||
| Esc | `esc` |
|
||||
| 윈도우 키 | `meta_l` / `meta_r` |
|
||||
| Ctrl+Alt+Del | `ctrl-alt-delete` |
|
||||
| 대문자 A | `shift-a` |
|
||||
| 화살표 | `up`, `down`, `left`, `right` |
|
||||
| 특수기호 | `exclam`(!), `at`(@), `minus`(-), `slash`(/), `dot`(.) 등 |
|
||||
|
||||
### 패턴: Win+R → 프로그램 실행
|
||||
```bash
|
||||
sshpass -p "$PVE_PASSWORD" ssh root@<PVE_HOST> '
|
||||
qm sendkey 101 esc # 떠있는 다이얼로그 닫기
|
||||
sleep 0.3
|
||||
qm sendkey 101 meta_l-r # 실행창 열기
|
||||
sleep 0.5
|
||||
for c in n o t e p a d; do qm sendkey 101 $c; sleep 0.05; done
|
||||
qm sendkey 101 ret
|
||||
'
|
||||
```
|
||||
|
||||
### 제약
|
||||
- 키보드 입력만 가능 (마우스 ❌)
|
||||
- 한글/IME 입력 매우 어려움 — 영문 명령어/경로 위주로 설계
|
||||
- 화면 상태 모르고 보내면 의도와 다른 곳에 들어감 → screendump으로 확인 권장
|
||||
- 결과 회수 = screendump 또는 QGA로 프로세스 확인
|
||||
|
||||
---
|
||||
|
||||
## 5. ★ 최강 조합: QGA + schtasks로 사용자 세션에서 실행
|
||||
|
||||
QGA의 결과 회수성 + 사용자 세션에서의 GUI 가시성을 모두 얻는 방법.
|
||||
|
||||
```bash
|
||||
qm guest exec 101 --timeout 30 -- powershell.exe -NoProfile -Command "
|
||||
schtasks /create /tn RunInUser /tr 'C:\path\program.exe arg' /sc once /st 23:59 /it /ru '<windows_user>' /f
|
||||
schtasks /run /tn RunInUser
|
||||
Start-Sleep 1
|
||||
schtasks /delete /tn RunInUser /f
|
||||
"
|
||||
```
|
||||
|
||||
- `/it` = interactive (사용자 데스크톱에 GUI 보임)
|
||||
- `/ru '<windows_user>'` = 지정 사용자의 세션 컨텍스트
|
||||
- `schtasks /run`은 일정 시각과 무관하게 즉시 실행
|
||||
- 결과 파일을 게스트에 쓰게 한 다음 `qm guest file-read`로 회수 → 비동기 + 가시성 + 회수성
|
||||
|
||||
---
|
||||
|
||||
## 6. VM 라이프사이클 명령 (자주 쓰는 것만)
|
||||
|
||||
```bash
|
||||
qm status 101 # 상태 (running/stopped/...)
|
||||
qm start 101 # 시작
|
||||
qm stop 101 # 강제종료 (전원 끊기)
|
||||
qm shutdown 101 # ACPI shutdown (OS에 종료 신호)
|
||||
qm reboot 101 # ACPI 재시작
|
||||
qm reset 101 # 하드 리셋
|
||||
qm config 101 # config 보기
|
||||
qm list # 전체 VM 목록
|
||||
qm set 101 --boot order=sata1;sata0;ide0 # 부팅 순서
|
||||
qm set 101 --sata1 pve-zfs:vm-101-disk-1 # 디스크 attach
|
||||
qm set 101 --delete unused0 # 디스크 detach
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. VHD/디스크 임포트 패턴 (실전: SMB → ZFS raw zvol)
|
||||
|
||||
```bash
|
||||
# 1) SMB 마운트 (pve5에서)
|
||||
mkdir -p /mnt/vhd-src
|
||||
mount -t cifs //<SMB_HOST>/vhd /mnt/vhd-src \
|
||||
-o username=<SMB_USER>,password=$SMB_PASSWORD,ro,vers=3.0,iocharset=utf8
|
||||
|
||||
# 2) vhd 메타데이터 확인
|
||||
qemu-img info /mnt/vhd-src/vm100.vhd
|
||||
|
||||
# 3) qm importdisk 한방 (vhd → raw zvol on pve-zfs)
|
||||
# nohup으로 백그라운드 권장 (106GB 약 30-40분 소요)
|
||||
nohup qm importdisk 101 /mnt/vhd-src/vm100.vhd pve-zfs --format raw \
|
||||
> /tmp/import.log 2>&1 &
|
||||
|
||||
# 4) 완료 후 unused0 → sata1 (또는 원하는 슬롯)
|
||||
qm set 101 --sata1 pve-zfs:vm-101-disk-1
|
||||
|
||||
# 5) 부팅 순서 변경
|
||||
qm set 101 --boot 'order=sata1;sata0;ide0'
|
||||
|
||||
# 6) SMB 정리
|
||||
umount /mnt/vhd-src
|
||||
```
|
||||
|
||||
### 디스크 검증 (부팅 전)
|
||||
```bash
|
||||
fdisk -l /dev/zvol/pve-zfs/vm-101-disk-1
|
||||
# Windows UEFI 정상 = part1(Recovery) + part2(EFI System) + part3(MSR) + part4(NTFS)
|
||||
|
||||
mount -o ro /dev/zvol/pve-zfs/vm-101-disk-1-part2 /mnt/efi
|
||||
ls /mnt/efi/EFI/Microsoft/Boot/bootmgfw.efi # 있으면 부팅 가능
|
||||
umount /mnt/efi
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 흔한 트러블슈팅
|
||||
|
||||
### `WARN: no efidisk configured! Using temporary efivars disk.`
|
||||
OVMF 부팅 VM에 NVRAM 저장 디스크가 없음. 매 부팅 시 EFI 부트 엔트리가 초기화됨. 영구 NVRAM 만들려면 VM 종료 후:
|
||||
```bash
|
||||
qm set 101 --efidisk0 pve-zfs:1,efitype=4m,pre-enrolled-keys=0
|
||||
```
|
||||
fallback boot path(`\EFI\Microsoft\Boot\bootmgfw.efi`, `\EFI\Boot\bootx64.efi`)가 있으면 efidisk 없어도 부팅은 됨.
|
||||
|
||||
### `GPT PMBR size mismatch` 경고
|
||||
zvol 크기가 vhd 가상 크기보다 약간 큰 경우. Windows 부팅에는 영향 없음. 수정하려면 게스트에서 `diskpart`로 GPT 백업 위치 재기록.
|
||||
|
||||
### qm sendkey 입력이 안 먹힘
|
||||
- 화면 잠겨있거나 다른 모달 다이얼로그 떠있는지 screendump으로 확인
|
||||
- 키 사이 간격 너무 짧으면 일부 키 손실 → `sleep 0.05` 삽입
|
||||
- IME가 한글모드라면 영문으로 전환 필요 (`shift` + 한/영 키는 표준 매핑 없음, OS GUI에서 미리 영문으로)
|
||||
|
||||
### qm guest exec가 "guest agent not running"
|
||||
- VM config에 `agent: 1` 있는지 확인 (`qm config 101 | grep agent`)
|
||||
- 게스트 안에서 서비스 확인: `Get-Service QEMU-GA` (Windows) / `systemctl status qemu-guest-agent` (Linux)
|
||||
- VM이 막 부팅됐다면 agent 서비스 시작까지 30~60초 대기
|
||||
|
||||
### qemu-ga가 SYSTEM이라 사용자 환경변수가 다름
|
||||
`%USERPROFILE%`, 매핑 드라이브, 사용자 설치 프로그램 등에 접근 못 함. 사용자 세션 컨텍스트 필요하면 § 5 schtasks 패턴 사용.
|
||||
|
||||
### Windows SATA → VirtIO-SCSI 디스크 컨트롤러 전환 (마스터화)
|
||||
|
||||
가장 흔한 함정: `pnputil /add-driver vioscsi.inf /install`로 등록만 하면 BSOD `0xc0000017` / `0xc0000225` 발생. 이유는 vioscsi 서비스가 **DEMAND_START(=3)** 으로 등록되어 boot critical이 아니기 때문. winload가 vioscsi.sys를 부팅 시점에 로드하지 않아 OS 디스크 접근 실패.
|
||||
|
||||
**해결책**: 게스트 안에서 vioscsi를 BOOT_START(=0)으로 명시 승격.
|
||||
```cmd
|
||||
sc config vioscsi start= boot
|
||||
reg query HKLM\SYSTEM\CurrentControlSet\Services\vioscsi /v Start
|
||||
# 결과가 0x0 이어야 함
|
||||
```
|
||||
|
||||
**검증된 마스터화 절차** (현재 SATA 부팅 → VirtIO-SCSI 단독 마스터):
|
||||
|
||||
1. virtio-win.iso 마운트 + `pnputil /add-driver` 로 vioscsi/viostor/netkvm INF 등록
|
||||
2. **`sc config vioscsi start= boot`** ← 핵심
|
||||
3. Windows ACPI shutdown (NTFS dirty + hive transaction log 정리)
|
||||
4. ZFS 클론 (같은 풀 내):
|
||||
```bash
|
||||
zfs snapshot pve-zfs/vm-<vmid>-disk-0@master
|
||||
zfs send pve-zfs/vm-<vmid>-disk-0@master | zfs recv pve-zfs/vm-<vmid>-disk-NEW
|
||||
zfs destroy pve-zfs/vm-<vmid>-disk-0@master
|
||||
zfs destroy pve-zfs/vm-<vmid>-disk-NEW@master
|
||||
```
|
||||
5. config 교체:
|
||||
```bash
|
||||
qm set <vmid> --delete sata0
|
||||
qm set <vmid> --scsi0 pve-zfs:vm-<vmid>-disk-NEW,iothread=1,discard=on,ssd=1
|
||||
qm set <vmid> --scsihw virtio-scsi-single
|
||||
qm set <vmid> --boot 'order=scsi0'
|
||||
```
|
||||
6. 부팅 검증
|
||||
|
||||
**주의 — 동일 GPT signature 디스크 두 개 동시 attach 시 함정**: SATA 디스크와 그 raw 변환본/클론을 동시에 attach하면 NT namespace 매핑 이상으로 BSOD 발생. 한쪽 detach 후 단독으로 검증.
|
||||
|
||||
### vhd → raw 변환본이 부팅 안 될 때 (sata 원본은 부팅 OK)
|
||||
원인 가능성: `qm importdisk`로 vhd → raw 변환 시 disk size에 1MB 패딩 추가됨 (`vmcfg sata1: ...size=122881M` 같이 +1 표기). 이 padding이 GPT backup header 위치를 미세하게 흔들 수 있음. 또는 우리 작업 경험상 SYSTEM hive 손상 가능성도 있음. 해결책:
|
||||
- **부팅 가능한 sata 원본을 ZFS 클론**해서 그걸 마스터로 사용 (vhd 변환본 폐기)
|
||||
- 또는 sata 원본 자체를 in-place로 virtio-scsi 인터페이스 변경 (drive number는 NT 동적이라 OK)
|
||||
|
||||
---
|
||||
|
||||
## 9. 참고 명령 치트시트
|
||||
|
||||
```bash
|
||||
# 화면 한 번 보기 (pve5에서 + Claude 환경으로 회수)
|
||||
sshpass -p "$PVE_PASSWORD" ssh root@<PVE_HOST> 'echo "screendump /tmp/s.ppm" | qm monitor 101'
|
||||
sshpass -p "$PVE_PASSWORD" scp root@<PVE_HOST>:/tmp/s.ppm /tmp/s.ppm && ffmpeg -y -i /tmp/s.ppm /tmp/s.png
|
||||
|
||||
# 게스트 정보 한 번에
|
||||
sshpass -p "$PVE_PASSWORD" ssh root@<PVE_HOST> '
|
||||
qm agent 101 get-osinfo
|
||||
qm agent 101 get-host-name
|
||||
qm agent 101 get-users
|
||||
'
|
||||
|
||||
# 게스트에서 PowerShell 한 줄
|
||||
sshpass -p "$PVE_PASSWORD" ssh root@<PVE_HOST> \
|
||||
'qm guest exec 101 --timeout 30 -- powershell.exe -NoProfile -Command "Get-Process | Select Name,Id"'
|
||||
|
||||
# 게스트에 Python 스크립트 던지고 실행
|
||||
LOCAL_PY=/tmp/probe.py
|
||||
cat > $LOCAL_PY <<'EOF'
|
||||
import os, json
|
||||
print(json.dumps({"cwd": os.getcwd(), "env_user": os.environ.get("USERNAME")}))
|
||||
EOF
|
||||
sshpass -p "$PVE_PASSWORD" ssh root@<PVE_HOST> "
|
||||
qm guest file-write 101 'C:\\temp\\probe.py' --content \"\$(cat)\" <<< \"\$(cat $LOCAL_PY)\"
|
||||
qm guest exec 101 --timeout 30 -- python.exe 'C:\\temp\\probe.py'
|
||||
"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. DR 이전 (다른 PVE 노드로 옮기기)
|
||||
|
||||
원본 정지 후 다른 노드에서 켜는 시나리오. pve5 ↔ pve7 모두 같은 PBS(`<PBS_STORAGE_A>` / `<PBS_STORAGE_B>`)에 연결돼있어 PBS 경로가 가장 깔끔.
|
||||
|
||||
### 사전 점검 (이전하기 좋은 상태 만들기)
|
||||
- [ ] `efidisk0` 설정됨 (없으면 매 부팅 NVRAM 초기화 — `qm set <vmid> --efidisk0 <stor>:1,efitype=4m,pre-enrolled-keys=0`)
|
||||
- [ ] VirtIO 드라이버 설치 상태 확인 (`Get-PnpDevice | Where Manufacturer -like "*Red Hat*"`)
|
||||
- [ ] 현재 인터페이스(sata/e1000 등)를 대상 PVE도 지원하는지 — 동일 인터페이스 유지가 가장 안전
|
||||
- [ ] `cpu: host`면 대상 노드 CPU 세대가 같은지 확인 (다르면 `cpu: x86-64-v2-AES` 등 호환 모델로 사전 변경)
|
||||
- [ ] 불필요한 디스크 detach (사용 안 하는 zvol/qcow2 정리)
|
||||
|
||||
### 절차 (PBS 백업 → 다른 PVE에서 restore)
|
||||
```bash
|
||||
# 1) 원본 PVE에서 백업 (실행 중에도 가능, snapshot 모드)
|
||||
ssh root@pve5 'vzdump 101 --storage <PBS_STORAGE_A> --mode snapshot --compress zstd'
|
||||
|
||||
# 2) 백업 ID 확인
|
||||
ssh root@pve5 'pvesm list <PBS_STORAGE_A> --vmid 101 | tail -5'
|
||||
|
||||
# 3) 대상 PVE에서 restore (새 VMID 또는 동일 VMID)
|
||||
ssh root@pve7 '
|
||||
pvesm list <PBS_STORAGE_B> --vmid 101 | tail -5 # 같은 PBS면 보임
|
||||
qmrestore <BACKUP_VOLID> <NEW_VMID> --storage local-lvm
|
||||
# 예: qmrestore <PBS_STORAGE_B>:backup/vm/101/2026-05-19T... 201 --storage local-lvm
|
||||
'
|
||||
|
||||
# 4) 원본 정지 + 대상 시작
|
||||
ssh root@pve5 'qm shutdown 101'
|
||||
ssh root@pve7 'qm start <NEW_VMID>'
|
||||
```
|
||||
|
||||
### 절차 (vzdump → scp → qmrestore, PBS 없을 때)
|
||||
```bash
|
||||
ssh root@pve5 'vzdump 101 --dumpdir /var/lib/vz/dump --mode snapshot --compress zstd'
|
||||
scp root@pve5:/var/lib/vz/dump/vzdump-qemu-101-*.vma.zst root@pve7:/var/lib/vz/dump/
|
||||
ssh root@pve7 'qmrestore /var/lib/vz/dump/vzdump-qemu-101-*.vma.zst 201 --storage local-lvm'
|
||||
```
|
||||
|
||||
### 스토리지 차이 주의
|
||||
- pve5 = `pve-zfs` (ZFS zvol, raw)
|
||||
- pve7 = `local-lvm` (LVM-thin, raw)
|
||||
- 둘 다 raw 기반이라 restore 자동 변환됨. qcow2 dir로 가면 qcow2로 변환.
|
||||
|
||||
### MAC/UUID 충돌 (동시 운영 시에만)
|
||||
원본을 *정지*하고 옮기면 충돌 없음. 동시 운영이면:
|
||||
```bash
|
||||
qm set <NEW_VMID> --net0 e1000=AUTO,bridge=vmbr0 # MAC 자동 재생성
|
||||
qm set <NEW_VMID> --vmgenid 1 # vmgenid 새로 (Windows AD/DC 인식 변경)
|
||||
qm set <NEW_VMID> --smbios1 uuid=auto # SMBIOS uuid 새로
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. 보안 메모
|
||||
|
||||
- QGA는 **SYSTEM 권한**이라 게스트 OS 안에서 사실상 할 수 있는 게 무제한. 신뢰되는 게스트에만 사용.
|
||||
- pve5 SSH 키 또는 적어도 ssh-agent 사용을 권장 (현재는 sshpass + 평문 패스워드)
|
||||
- SMB 마운트는 `ro` 기본, 쓰기 작업 필요할 때만 `rw`
|
||||
- qm sendkey로 비밀번호 같은 민감 정보 입력 시 screendump에 남을 수 있음 — 캡처 파일 즉시 삭제
|
||||
381
JOURNEY.md
Normal file
381
JOURNEY.md
Normal file
@@ -0,0 +1,381 @@
|
||||
# 실패의 연대기 (Failure Journal)
|
||||
|
||||
> Windows VM의 디스크 컨트롤러를 **SATA → VirtIO-SCSI**로 마이그레이션하는 과정에서 만난 모든 함정의 기록.
|
||||
> 진짜 원인 — `vioscsi START_TYPE=0 (BOOT_START)` 누락 — 을 찾기까지 수 시간을 소비했다.
|
||||
> 같은 길을 가는 사람이 이 글을 읽고 30분에 끝낼 수 있길.
|
||||
|
||||
작성일: 2026-05-19
|
||||
작업 환경: Proxmox VE 8.1.3 / Windows 10 Pro 19045 / virtio-win-0.1.285
|
||||
|
||||
---
|
||||
|
||||
## 출발점
|
||||
|
||||
목표:
|
||||
- SMB에 보관된 `vm100.vhd` (120GiB virt, 106GiB sparse) Windows 디스크 이미지를 Proxmox VM에 활용
|
||||
- 가능하면 SATA 에뮬레이션 대신 **VirtIO-SCSI 컨트롤러**로 운영해서 성능/효율 확보 (멀티큐, iothread, discard/TRIM)
|
||||
|
||||
도구:
|
||||
- `qm importdisk` (vhd → raw zvol 변환)
|
||||
- ZFS pool `pve-zfs` (vol storage)
|
||||
- `pnputil` (Windows 드라이버 등록)
|
||||
- `qm sendkey`, QEMU monitor screendump (원격 시각 확인)
|
||||
|
||||
---
|
||||
|
||||
## Step 1 — vhd → raw zvol 변환
|
||||
|
||||
```bash
|
||||
qm importdisk <VMID> /mnt/smb/vm100.vhd pve-zfs --format raw
|
||||
```
|
||||
|
||||
결과: `pve-zfs:vm-<VMID>-disk-1` 생성 (REFER 73.4GB sparse). config에 `unused0:`로 자동 등록.
|
||||
|
||||
**관찰**: 변환 후 zvol 크기가 120GiB + ~1MB 패딩. fdisk가 `GPT PMBR size mismatch` 경고. 이때는 대수롭지 않게 넘어감.
|
||||
|
||||
---
|
||||
|
||||
## Step 2 — sata1로 attach + 부팅 시도
|
||||
|
||||
```bash
|
||||
qm set <VMID> --sata1 pve-zfs:vm-<VMID>-disk-1
|
||||
qm set <VMID> --boot 'order=sata1;sata0;ide0'
|
||||
qm start <VMID>
|
||||
```
|
||||
|
||||
**결과**: Windows 10 데스크톱 정상 진입! 사용자도 다 보임. 데이터 모두 살아있음.
|
||||
|
||||
**우리가 잘못 알았던 것**: "vhd 변환이 잘 됐구나" — 사실은 **sata0 (기존에 갖고 있던 vm-101-disk-0 zvol)에서 부팅된 것**이었음. `Get-Disk`로 확인 안 했으니 모름.
|
||||
|
||||
---
|
||||
|
||||
## Step 3 — 안정화: efidisk 추가, VirtIO 드라이버 등록
|
||||
|
||||
부팅이 잘 되니 마스터화 준비. 두 가지 작업 진행.
|
||||
|
||||
### 3-1. efidisk0 추가 (OVMF NVRAM 영구화)
|
||||
|
||||
```bash
|
||||
qm set <VMID> --efidisk0 pve-zfs:1,efitype=4m,pre-enrolled-keys=0
|
||||
```
|
||||
|
||||
이전엔 `WARN: no efidisk configured` 떠서 매 부팅마다 OVMF가 NVRAM 새로 만들고 fallback path로 부팅했음. 영구화하면 부팅 엔트리 저장됨.
|
||||
|
||||
### 3-2. VirtIO 드라이버 사전 설치
|
||||
|
||||
virtio-win.iso를 attach하고 임시 SCSI 디스크도 같이 띄워 게스트가 새 PCI 디바이스 인식하게 만든 다음:
|
||||
|
||||
```cmd
|
||||
pnputil /add-driver F:\vioscsi\w10\amd64\vioscsi.inf /install
|
||||
pnputil /add-driver F:\viostor\w10\amd64\viostor.inf /install
|
||||
pnputil /add-driver F:\NetKVM\w10\amd64\netkvm.inf /install
|
||||
```
|
||||
|
||||
`pnputil`이 INF 파일을 driver store에 등록 + `/install` 옵션이 매칭되는 PnP 디바이스에 즉시 설치. `Get-PnpDevice`에서 "Red Hat VirtIO SCSI pass-through controller" Status=OK 보임. `Get-Service vioscsi` → RUNNING.
|
||||
|
||||
**우리가 잘못 알았던 것**: "드라이버 등록 완료, 이제 부팅 디스크 인터페이스 바꿔도 BSOD 안 나겠지" — **틀렸다**.
|
||||
|
||||
---
|
||||
|
||||
## Step 4 — 인터페이스 교체: sata1 → scsi0
|
||||
|
||||
깨끗한 마스터를 위해 sata1 detach, scsi0로 같은 zvol attach:
|
||||
|
||||
```bash
|
||||
qm set <VMID> --scsi0 pve-zfs:vm-<VMID>-disk-1,iothread=1,discard=on,ssd=1
|
||||
qm set <VMID> --delete sata1
|
||||
qm set <VMID> --boot 'order=scsi0'
|
||||
qm start <VMID>
|
||||
```
|
||||
|
||||
**결과**: **BSOD 0xc0000225** (Recovery / "필요한 장치가 연결되어 있지 않거나 장치에 액세스할 수 없습니다") — `\Windows\system32\config\system` 위치 못 찾음.
|
||||
|
||||
이때 처음으로 뭔가 잘못됐다고 느낌. 그러나 원인을 GPT signature 충돌로 오해.
|
||||
|
||||
---
|
||||
|
||||
## Step 5 — 오해의 시작: "GPT signature 충돌이 원인이다"
|
||||
|
||||
`Get-Disk`로 보니 두 디스크 GUID 완전 동일:
|
||||
|
||||
```
|
||||
Disk 0: SATA, GUID {4bca652d-2f35-4bd7-8175-8951593eb8c1}, 120GB
|
||||
Disk 1: SAS, GUID {4bca652d-2f35-4bd7-8175-8951593eb8c1}, 120GB (1MB padding 더 큼)
|
||||
```
|
||||
|
||||
호스트에서 `fdisk -l /dev/zvol/...`로 검증 — 두 zvol의 Disk identifier 동일, 모든 partition UUID 동일.
|
||||
|
||||
**가설 (틀린 것)**: Windows가 동일 GPT signature 두 디스크 보면 한쪽을 자동 Offline 처리 → sata0 detach 후 scsi0 단독으로는 BCD device path 매칭 실패.
|
||||
|
||||
이 가설로 BCD 수정 시도들이 시작됨.
|
||||
|
||||
---
|
||||
|
||||
## Step 6 — BCD 수정 시도 1: device/osdevice → "boot" 키워드
|
||||
|
||||
```cmd
|
||||
bcdedit /export C:\bcd-backup-20260519.bcd
|
||||
bcdedit /set {bootmgr} device boot # 거부됨 (정상)
|
||||
bcdedit /set {default} device boot # 성공
|
||||
bcdedit /set {default} osdevice boot # 성공
|
||||
```
|
||||
|
||||
`boot` 키워드 의미: "이 BCD가 로드된 partition을 동적으로 추적해서 사용". 매혹적이지만 **잘못된 적용**.
|
||||
|
||||
**검증**: shutdown → sata0 detach → 부팅 → **여전히 BSOD 0xc0000225**.
|
||||
|
||||
**왜 안 먹혔나**: `osdevice = boot`는 사실 잘못된 의미. winload는 "boot device = system partition (EFI 100MB FAT32)"으로 해석해서 거기서 `\Windows\system32\winload.efi` 찾으려고 함. EFI partition에 \Windows 없으니 fail.
|
||||
|
||||
---
|
||||
|
||||
## Step 7 — BCD 수정 시도 2: bcdboot으로 새 BCD 생성
|
||||
|
||||
scsi0의 EFI partition을 마운트해서 BCD 재구성:
|
||||
|
||||
```cmd
|
||||
diskpart 스크립트로 Disk 1 Partition 2에 S: 할당
|
||||
bcdboot C:\Windows /s S: /f UEFI /v
|
||||
```
|
||||
|
||||
bcdboot이 정상 동작:
|
||||
```
|
||||
BFSVC: Creating Recovery directory.
|
||||
BFSVC: Creating OsLoader object.
|
||||
BFSVC: Setting {default} to {bfc003a5-...}
|
||||
부팅 파일을 만들었습니다.
|
||||
```
|
||||
|
||||
새 BCD enum:
|
||||
```
|
||||
{default}.device = partition=\Device\Harddisk0\Partition4
|
||||
{default}.osdevice = partition=\Device\Harddisk0\Partition4
|
||||
```
|
||||
|
||||
**검증**: shutdown → sata0 detach → 부팅 → **다른 BSOD 0xc0000017** (system registry file missing).
|
||||
|
||||
이제 한 단계 더 진행됨: OVMF→boot manager→winload까지 OK, OS partition 도달, 거기서 SYSTEM hive 못 읽음.
|
||||
|
||||
---
|
||||
|
||||
## Step 8 — NTFS 무결성 검사: ntfsfix
|
||||
|
||||
호스트에서 NTFS 마운트:
|
||||
|
||||
```bash
|
||||
ntfs-3g /dev/zvol/pve-zfs/vm-<VMID>-disk-1-part4 /mnt/winc -o ro
|
||||
ls /mnt/winc/Windows/System32/config/SYSTEM # 24.5MB 존재
|
||||
hexdump -C -n 16 /mnt/winc/Windows/System32/config/SYSTEM
|
||||
# 00000000 72 65 67 66 ... ← "regf" 시그니처 OK
|
||||
umount /mnt/winc
|
||||
|
||||
ntfsfix /dev/zvol/pve-zfs/vm-<VMID>-disk-1-part4
|
||||
# Processing of $MFT and $MFTMirr completed successfully.
|
||||
# Checking the alternate boot sector... OK
|
||||
# NTFS partition was processed successfully.
|
||||
```
|
||||
|
||||
**검증**: 부팅 시도 → **BSOD 0xc0000017 그대로**.
|
||||
|
||||
SYSTEM hive 파일은 존재 + 헤더 정상 + NTFS metadata clean. 그러나 부팅 실패.
|
||||
|
||||
---
|
||||
|
||||
## Step 9 — NVRAM 초기화 시도
|
||||
|
||||
가설: OVMF NVRAM에 옛 부트 엔트리(detach된 디스크 가리키는 것)가 캐시되어 fallback 실패.
|
||||
|
||||
```bash
|
||||
qm set <VMID> --delete efidisk0
|
||||
qm set <VMID> --efidisk0 pve-zfs:1,efitype=4m,pre-enrolled-keys=0
|
||||
qm start <VMID>
|
||||
```
|
||||
|
||||
**결과**: 새 NVRAM 만들고 부팅 → **BSOD 0xc0000017 그대로**.
|
||||
|
||||
---
|
||||
|
||||
## Step 10 — WinRE Startup Repair 시도
|
||||
|
||||
BSOD 화면에 "F1 to enter Recovery Environment" 안내가 있음. `qm sendkey <VMID> f1`로 시도.
|
||||
|
||||
**결과**: WinRE 진입 안 됨. vhd 백업본에 WinRE WIM이 비활성/누락 상태. 막다른 길.
|
||||
|
||||
---
|
||||
|
||||
## Step 11 — SSD 마이그레이션식 클론 시도
|
||||
|
||||
> 사용자 제안: "보통은 디스크 두 개 만들고 1:1 복사하는 도구로 옮기잖아, SSD 마이그레이션처럼"
|
||||
|
||||
ZFS send/recv로 vhd 변환본을 새 zvol에 클론:
|
||||
|
||||
```bash
|
||||
zfs snapshot pve-zfs/vm-<VMID>-disk-1@clone-master
|
||||
time (zfs send pve-zfs/vm-<VMID>-disk-1@clone-master | zfs recv pve-zfs/vm-<VMID>-disk-4)
|
||||
# real 10m50.003s
|
||||
```
|
||||
|
||||
config 교체: 기존 vhd 변환본 detach + 클론을 scsi0로 attach → boot order=scsi0 단독.
|
||||
|
||||
**결과**: **BSOD 0xc0000017 — 클론도 동일 증상**.
|
||||
|
||||
이로써 가설이 확정적으로 깨짐: GPT 충돌이 단독 원인이라면 단일 디스크 상태에서 해결됐어야 함. 그런데 안 됨.
|
||||
|
||||
---
|
||||
|
||||
## Step 12 — 결정적 진단: sata0 단독 부팅 검증
|
||||
|
||||
```bash
|
||||
qm set <VMID> --delete scsi0
|
||||
qm set <VMID> --sata0 pve-zfs:vm-<VMID>-disk-0,size=120G
|
||||
qm set <VMID> --boot 'order=sata0'
|
||||
qm start <VMID>
|
||||
```
|
||||
|
||||
**결과**: ✅ **정상 부팅** (Windows 10 잠금화면, 0bin 사용자).
|
||||
|
||||
이게 결정적. **sata0 단독은 부팅 가능 + vhd 변환본 단독은 부팅 불가**. 두 zvol 데이터가 GPT signature는 같지만 어딘가 다르다 — 또는 컨트롤러 차이 자체가 원인.
|
||||
|
||||
게스트 상태 확인:
|
||||
```
|
||||
Get-Disk → Disk 0 SATA Online
|
||||
Get-Partition → DiskNumber=0 IsBoot=True
|
||||
Get-Service vioscsi → RUNNING
|
||||
sc qc vioscsi → START_TYPE: 3 DEMAND_START ← 🔥 발견!
|
||||
```
|
||||
|
||||
**진짜 원인 발견**: vioscsi 서비스가 등록은 되어 있지만 **boot critical(=0)이 아니라 수동 시작(=3)**. winload가 부팅 시점에 vioscsi.sys를 로드하지 않음 → VirtIO-SCSI 디스크에서 부팅 시 디스크 접근 못 함 → BSOD.
|
||||
|
||||
`pnputil /add-driver vioscsi.inf /install`은 드라이버 파일과 PnP 매칭만 등록. **서비스의 Start 값을 자동으로 boot critical로 승격하지 않는다**.
|
||||
|
||||
---
|
||||
|
||||
## Step 13 — 진짜 해결: vioscsi boot critical 승격
|
||||
|
||||
```cmd
|
||||
sc config vioscsi start= boot
|
||||
```
|
||||
|
||||
검증:
|
||||
```
|
||||
sc qc vioscsi → START_TYPE: 0 BOOT_START
|
||||
reg query HKLM\SYSTEM\CurrentControlSet\Services\vioscsi /v Start
|
||||
→ Start REG_DWORD 0x0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 14 — Windows 정상 종료 + ZFS 클론 + 마스터화
|
||||
|
||||
```bash
|
||||
# Windows ACPI shutdown
|
||||
qm shutdown <VMID> --timeout 180
|
||||
|
||||
# 검증된 sata0 디스크를 새 zvol로 클론
|
||||
zfs snapshot pve-zfs/vm-<VMID>-disk-0@master-final
|
||||
time (zfs send pve-zfs/vm-<VMID>-disk-0@master-final | zfs recv pve-zfs/vm-<VMID>-disk-5)
|
||||
# real 28m43.568s
|
||||
|
||||
# config 교체
|
||||
qm set <VMID> --delete sata0
|
||||
qm set <VMID> --scsi0 pve-zfs:vm-<VMID>-disk-5,iothread=1,discard=on,ssd=1
|
||||
qm set <VMID> --scsihw virtio-scsi-single
|
||||
qm set <VMID> --boot 'order=scsi0'
|
||||
qm start <VMID>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 15 — 검증: 진짜 마스터 완성
|
||||
|
||||
```
|
||||
Get-Disk → Disk 0 QEMU QEMU HARDDISK BusType=SAS 120GB Online
|
||||
Get-Partition → DiskNumber=0 IsBoot=True
|
||||
sc query vioscsi → RUNNING
|
||||
sc qc vioscsi → START_TYPE: 0 BOOT_START
|
||||
```
|
||||
|
||||
**단일 디스크 + virtio-scsi-single + iothread + discard + boot critical** = 마스터 완성. Windows 10 잠금화면 정상 진입.
|
||||
|
||||
---
|
||||
|
||||
## 교훈 (lessons learned)
|
||||
|
||||
### 진짜 원인은 vioscsi의 START_TYPE
|
||||
|
||||
다른 모든 가설(GPT signature 충돌, BCD 손상, NVRAM 캐시, vhd 변환 미세 손상)은 부분적으로 그럴듯했지만 **단독 원인이 아니었다**. 진짜 원인은:
|
||||
|
||||
```
|
||||
vioscsi Service Start=3 (DEMAND_START)
|
||||
↓
|
||||
winload가 부팅 시점에 vioscsi.sys 안 로드
|
||||
↓
|
||||
virtio-scsi 디스크에서 부팅 시 디스크 IO 핸들러 부재
|
||||
↓
|
||||
INACCESSIBLE_BOOT_DEVICE → BSOD 0xc0000017 또는 0xc0000225
|
||||
```
|
||||
|
||||
### pnputil의 한계
|
||||
|
||||
- `pnputil /add-driver vioscsi.inf /install`
|
||||
- 드라이버 파일과 PnP 디바이스 매칭은 잘 한다
|
||||
- 그러나 **서비스의 boot priority는 건드리지 않는다**
|
||||
- 그래서 매뉴얼하게 `sc config vioscsi start= boot` 또는 레지스트리 직접 수정 필요
|
||||
|
||||
### "vhd → raw 변환본"은 부팅 보증 안 된다
|
||||
|
||||
- `qm importdisk`로 vhd → raw 변환 시 사이즈에 패딩 추가, GPT backup 위치 미세 차이
|
||||
- 검증된 sata 원본을 ZFS 클론하는 게 더 안전
|
||||
- vhd는 "백업본"이지 "라이브 부팅 가능 디스크"가 아닐 수 있음
|
||||
|
||||
### 동일 GPT signature 디스크 두 개를 동시 attach하지 말 것
|
||||
|
||||
- Windows가 한쪽을 자동 Offline 처리하지만 NT namespace 매핑/BCD path 종속성으로 detach 시 BSOD
|
||||
- 마이그레이션 작업은 단계별로 단독 attach 검증 권장
|
||||
|
||||
### bcdedit `osdevice = boot`은 함정
|
||||
|
||||
- "boot manager가 로드된 partition을 동적 추적"이라는 매혹적인 표현
|
||||
- 그러나 winload는 그걸 "system partition (EFI)"으로 해석 → \Windows 못 찾음 → BSOD
|
||||
- 잘못된 BCD 수정 패턴. **사용하지 말 것**.
|
||||
|
||||
### bcdboot은 깔끔하지만 만능 아님
|
||||
|
||||
- BCD store 새로 생성 + 자기 자신 가리키도록 설정
|
||||
- 그러나 partition UUID는 정확히 같은 zvol이라야 매칭됨
|
||||
- 동일 GPT signature 디스크가 같이 있을 때는 효과 제한적
|
||||
|
||||
---
|
||||
|
||||
## 부록: 알아두면 좋은 진단 명령
|
||||
|
||||
```cmd
|
||||
:: 서비스 시작 유형
|
||||
sc qc vioscsi | findstr START_TYPE
|
||||
reg query HKLM\SYSTEM\CurrentControlSet\Services\vioscsi /v Start
|
||||
|
||||
:: VirtIO 디바이스 인식
|
||||
powershell "Get-PnpDevice | Where Manufacturer -like '*Red Hat*' | Format-Table -AutoSize"
|
||||
|
||||
:: 부팅 디스크
|
||||
powershell "Get-Disk | Format-Table -AutoSize Number,FriendlyName,BusType,Size"
|
||||
powershell "Get-Partition | Where IsBoot -eq \$true | Format-List"
|
||||
|
||||
:: BCD 진단
|
||||
bcdedit /enum {bootmgr}
|
||||
bcdedit /enum {default}
|
||||
|
||||
:: driverstore의 OEM INF 등록 상태
|
||||
pnputil /enum-drivers | findstr /i /c:vioscsi /c:viostor /c:netkvm
|
||||
```
|
||||
|
||||
```bash
|
||||
# 호스트 (PVE)에서 게스트 디스크 NTFS 검증
|
||||
mount -t ntfs-3g -o ro /dev/zvol/<pool>/vm-<VMID>-disk-N-part4 /mnt/winc
|
||||
ls /mnt/winc/Windows/System32/config/SYSTEM
|
||||
hexdump -C -n 16 /mnt/winc/Windows/System32/config/SYSTEM # "regf" 시그니처
|
||||
umount /mnt/winc
|
||||
ntfsfix /dev/zvol/<pool>/vm-<VMID>-disk-N-part4
|
||||
|
||||
# 두 zvol 비교
|
||||
fdisk -l /dev/zvol/<pool>/vm-<VMID>-disk-N
|
||||
```
|
||||
12
LICENSE
Normal file
12
LICENSE
Normal file
@@ -0,0 +1,12 @@
|
||||
Attribution 4.0 International (CC BY 4.0)
|
||||
|
||||
You are free to:
|
||||
Share — copy and redistribute the material in any medium or format
|
||||
Adapt — remix, transform, and build upon the material for any purpose, even commercially.
|
||||
|
||||
Under the following terms:
|
||||
Attribution — You must give appropriate credit, provide a link to the license,
|
||||
and indicate if changes were made. You may do so in any reasonable manner,
|
||||
but not in any way that suggests the licensor endorses you or your use.
|
||||
|
||||
Full license text: https://creativecommons.org/licenses/by/4.0/legalcode
|
||||
82
README.md
Normal file
82
README.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# pve-vm-ops-guide
|
||||
|
||||
Proxmox VE에서 Windows/Linux VM을 **원격으로 다루는 실전 가이드** + **SATA → VirtIO-SCSI 디스크 컨트롤러 마이그레이션 함정** 분석.
|
||||
|
||||
## ⭐ 이 리포의 핵심 발견
|
||||
|
||||
Windows VM의 디스크 컨트롤러를 SATA에서 VirtIO-SCSI로 옮길 때 흔히 부딪치는 BSOD (`0xc0000017` / `0xc0000225`)의 진짜 원인:
|
||||
|
||||
```cmd
|
||||
sc qc vioscsi
|
||||
> START_TYPE: 3 DEMAND_START ← 이게 문제. boot critical 아님.
|
||||
```
|
||||
|
||||
해결:
|
||||
|
||||
```cmd
|
||||
sc config vioscsi start= boot
|
||||
```
|
||||
|
||||
`pnputil /add-driver`로 드라이버 등록만으로는 **부족**. 서비스를 BOOT_START(0)로 명시 승격해야 winload가 부팅 시점에 vioscsi.sys를 로드한다.
|
||||
|
||||
자세한 진단 과정과 다른 잘못된 해결책들의 기록은 [JOURNEY.md](JOURNEY.md) 참조.
|
||||
|
||||
---
|
||||
|
||||
## 📁 구성
|
||||
|
||||
| 파일 | 내용 |
|
||||
|---|---|
|
||||
| [GUIDE.ko.md](GUIDE.ko.md) | **본 가이드** — VM 화면 캡처, QGA, qm sendkey, vhd 임포트, virtio-scsi 마이그레이션, DR 이전 |
|
||||
| [JOURNEY.md](JOURNEY.md) | **실패의 연대기** — 진짜 원인 찾기까지 거친 15단계 |
|
||||
| [screenshots/](screenshots/) | 부팅 검증 화면 캡처 |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 가이드가 다루는 것
|
||||
|
||||
1. **VM 원격 제어** (Proxmox 호스트 SSH + QEMU monitor + QGA)
|
||||
- 화면 캡처 (PPM → PNG)
|
||||
- 게스트 안에서 명령 실행 (`qm guest exec`)
|
||||
- GUI 키 입력 (`qm sendkey`)
|
||||
- 사용자 세션 컨텍스트 실행 (QGA + schtasks)
|
||||
2. **VHD → ZFS raw zvol 변환 + attach**
|
||||
3. **VirtIO 드라이버 사전 설치 + SATA→SCSI 인터페이스 전환**
|
||||
4. **VM DR (Disaster Recovery) 이전** — PBS 백업 + 다른 노드 restore
|
||||
5. **트러블슈팅**
|
||||
- `WARN: no efidisk configured`
|
||||
- `GPT PMBR size mismatch`
|
||||
- BSOD `0xc0000017` / `0xc0000225` (vioscsi boot critical 미설정)
|
||||
|
||||
---
|
||||
|
||||
## 🛠 검증 환경
|
||||
|
||||
- Proxmox VE 8.1.3
|
||||
- ZFS pool 기반 storage (raw zvol)
|
||||
- Windows 10 Pro (build 19045)
|
||||
- virtio-win-0.1.285
|
||||
- OVMF (UEFI) + machine: pc-i440fx-7.1
|
||||
|
||||
---
|
||||
|
||||
## 📋 표기 규약
|
||||
|
||||
가이드 안 placeholder:
|
||||
|
||||
- `<PVE_HOST>` `<PVE_PASSWORD>`: Proxmox 노드 root 접속
|
||||
- `<SMB_HOST>` `<SMB_USER>` `<SMB_PASSWORD>`: SMB/CIFS 파일 서버
|
||||
- `<windows_user>`: Windows 게스트 사용자
|
||||
- VMID 예시는 `101`, zvol 예시는 `vm-101-disk-N` — 본인 환경 값으로 치환
|
||||
|
||||
---
|
||||
|
||||
## 🤝 기여
|
||||
|
||||
같은 함정에 빠진 적 있거나 다른 환경(machine: q35, viostor 기반 부팅, sysprep 이미지 등)에서의 케이스를 추가하고 싶다면 PR/issue 환영.
|
||||
|
||||
---
|
||||
|
||||
## 📄 라이선스
|
||||
|
||||
CC BY 4.0
|
||||
BIN
screenshots/01-windows-desktop-sata-boot.png
Normal file
BIN
screenshots/01-windows-desktop-sata-boot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 MiB |
BIN
screenshots/02-windows-virtio-scsi-master-boot.png
Normal file
BIN
screenshots/02-windows-virtio-scsi-master-boot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 MiB |
Reference in New Issue
Block a user