[Proxmox 시리즈 4편] Ubuntu/Debian 표준 Linux VM을 어떻게 설계하고 템플릿화할 것인가

English version

VM과 LXC를 구분할 기준을 잡았다면, 다음 단계는 "표준 Linux VM"을 정의하는 일입니다. 템플릿이 준비되어 있으면 새로운 워크로드를 만들 때마다 CPU 타입, 디스크 버스, 클라우드-이닛 설정을 다시 고민할 필요가 없습니다. 이번 글은 Ubuntu/Debian 기반 VM을 대상으로, 초보자가 실수하기 쉬운 옵션을 하나씩 짚고 안전한 기본값과 "왜" 그래야 하는지를 설명합니다.

이 글의 흐름

  1. CPU 타입과 코어 매핑
  2. 메모리·Ballooning·HugePages 기본값
  3. 디스크 버스, 캐시, VirtIO 매개변수
  4. 네트워크 디바이스와 QEMU Guest Agent
  5. Cloud-Init과 템플릿 제작 절차
  6. 흔한 실수와 점검 체크리스트

이번 글에서 새로 나오는 용어

  1. x86-64-v2/v3: 최신 CPU 명령어 지원 수준을 묶은 가상 CPU 프로파일입니다.
  2. Ballooning: 게스트 메모리를 동적으로 조정하는 기능으로, 오버커밋에 도움을 줍니다.
  3. VirtIO SCSI Single: 디스크 성능과 기능을 모두 확보하는 기본 디스크 컨트롤러 옵션입니다.
  4. Discard/Trim: 게스트가 사용하지 않는 블록을 호스트에 반환해 LVM-Thin 공간을 회수하는 기능입니다.
  5. Cloud-Init: VM 부팅 시 사용자·SSH키·네트워크 설정을 자동 적용하는 초기화 프레임워크입니다.

읽기 카드

  • 예상 소요 시간: 24분
  • 사전 준비: Ubuntu 또는 Debian ISO, Proxmox 8.x, local 혹은 별도 ISO 스토리지
  • 읽고 나면: 반복 가능한 표준 Linux VM 템플릿을 만들고 새 워크로드에 적용하는 방법을 설명할 수 있습니다.

CPU 타입과 코어 매핑

CPU 타입 특징 권장 환경
kvm64 가장 호환성 높지만 AVX 등 최신 명령어 없음 10년 이상 된 OS만 필요할 때
x86-64-v2-AES Proxmox 8.x 기본, AVX/_AES 지원 대부분의 홈랩 기본값
x86-64-v3 AVX2/VAES 포함, Zen 3·11세대 Core 이상 필요 최신 CPU에서만 사용
host 호스트 CPU와 동일, 성능 최대 라이브 마이그레이션 계획이 전혀 없을 때
  1. CPU 타입 결정 절차: lscpu | grep Flags로 호스트가 avx2를 지원하는지 확인합니다. Zen 2 이하나 10세대 이전 Intel이라면 x86-64-v2-AES로 고정하고, Zen 3 이상(예: Ryzen 5000)에서만 x86-64-v3 옵션을 고려합니다.
  2. 코어 수: 기본 템플릿은 2 vCPU(1 소켓, 2 코어)로 두고, 클론 이후 워크로드 맞춤으로 늘립니다. SMT를 켤 때는 VM의 코어
    비율을 호스트와 맞춰 NUMA 바운딩을 단순화합니다. numactl -H 출력을 확인해 멀티소켓임이 드러나면 qm set <ID> --numa 1--cpuaffinity 0-3 같은 옵션으로 특정 소켓에 고정하고, 단일 소켓 홈랩이면 이 단계를 건너뜁니다.
  3. Type 변경 시 주의: 이미 만들어 둔 VM은 CPU 타입을 바꾸면 커널이 새 하드웨어로 인식합니다. 마이그레이션 전 템플릿 단계에서 타입을 확정하고 문서화하십시오.
  4. 중첩 가상화 주의점: 게스트 안에서 다시 KVM이나 Docker를 돌릴 계획이 있다면 grep vmx /proc/cpuinfo 또는 grep svm /proc/cpuinfo로 플래그가 실제로 보이는지 확인합니다. 일부 CPU 타입은 이 플래그를 숨기므로, 중첩 가상화가 정말 필요할 때만 host 같은 설정을 검토하십시오.

메모리와 Ballooning

  1. 고정 메모리: 템플릿에는 2GB 고정값을 넣어 두고, 클론 직후 서비스 필요량 + 1~2GB 여유를 배정합니다. 예) 웹 프런트엔드(필요 1GB) -> 2GB, PostgreSQL(필요 4GB) -> 6GB.
  2. Ballooning 정책: Ballooning을 켜면 게스트가 요청하지 않은 메모리를 호스트가 회수해 다른 VM에 배분합니다. 초보자는 메모리 압박을 눈치채기 어렵기 때문에 기본 템플릿에서는 Ballooning 비활성화balloon_min = memory 구성을 권장합니다. lsmod | grep virtio_balloon으로 게스트 드라이버를 확인하고, 최대 Balloon 용량의 50% 이상을 swap으로 확보한 뒤에만 켜십시오. 알람을 만들어 balloon 값이 최대치의 70% 아래로 떨어지면 즉시 통보 받도록 합니다.
  3. HugePages: 휘발성 워크로드라면 비활성화로 두고, DB/게임 서버처럼 TLB miss가 빈번한 VM에 한해 qm set <ID> --hugepages 1024로 지정합니다. 호스트에서는 default_hugepagesz 커널 인자를 주고, transparent hugepageecho never > /sys/kernel/mm/transparent_hugepage/enabled로 끄는 것이 안전합니다.

디스크 버스, 캐시, VirtIO

컨트롤러 장점 사용 시점
SATA 호환성 구형 게스트, Windows 복구용
VirtIO Block 구성이 단순 단일 디스크 VM
VirtIO SCSI TRIM·멀티큐 지원, 고성능 표준 템플릿 기본값
  1. 버스 선택 절차: Proxmox UI -> VM -> Hardware -> SCSI Controller 항목을 VirtIO SCSI로 지정합니다. 대부분은 single로 충분하고, 4 vCPU 이상이거나 고IOPS VM일 때만 멀티큐 + iothread=1을 고려합니다. 이후 모든 디스크의 Bus/Device를 SCSI로 맞춥니다.
  2. 스토리지별 캐시 모드:
    • 로컬 SSD 또는 Ceph RBD: UPS나 배터리 백업 RAID 캐시가 있을 때만 Write back을 사용합니다.
    • 로컬 HDD 또는 NFS: Write through로 안전성을 확보합니다.
    • 벤치마크 전용: Write back (unsafe)Directsync는 벤치마크용으로만 쓰고, 전원 장애 시 데이터가 유실된다는 점을 명시하십시오.
  3. Discard를 위한 호스트 조건: 게스트 쪽에서 Discard를 켜도, 호스트의 LVM-Thin 풀이 discard를 실제로 발행하지 않으면 효과가 없습니다. Datacenter -> Storage -> (스토리지) -> Edit -> Advanced에서 Issue discard를 켠 뒤, 게스트에서
    fallocate -l 100M /tmp/trim-test && rm /tmp/trim-test
    sudo fstrim -v /
    
    를 실행하고 호스트에서 lvs -o lv_name,data_percent <vg> 값이 감소하는지 확인해야 합니다.
  4. VirtIO 드라이버: Ubuntu/Debian은 기본 내장입니다. Windows 게스트를 위한 virtio-win.isolocal 스토리지에 업로드해 두고, 템플릿 작성 플레이북에 "필수 ISO" 목록으로 남깁니다.

네트워크와 QEMU Guest Agent

  1. 브릿지 설계: 기본 브릿지는 vmbr0(LAN)입니다. VLAN 격리가 필요하면 vmbr0.10 같은 태그 인터페이스를 만들어 템플릿 문서에 어떤 브릿지를 쓰는지 명시합니다.
  2. NIC 모델: 모든 템플릿은 VirtIO (paravirtualized)로 설정합니다. Multiqueuemin(vCPU 수, 4) 정도로 두고, 실제 게스트 안에서 ethtool -l ens18로 확인합니다.
  3. QEMU Guest Agent 활성화:
    • 호스트: qm set <ID> --agent enabled=1
    • 게스트 (Ubuntu/Debian): sudo apt install -y qemu-guest-agent && sudo systemctl enable --now qemu-guest-agent
    • 동작 확인: qm agent <ID> ping
  4. 방화벽 기본값: 템플릿 구조에 Proxmox VM 방화벽을 기본적으로 켤지 끌지 기록해 새 워크로드에도 일관되게 적용합니다.

Cloud-Init과 템플릿 절차

  1. 기본 설치: Ubuntu Server ISO 또는 Cloud 이미지로 설치한 후 sudo apt update && sudo apt dist-upgrade를 실행하고 필요한 패키지를 설치합니다.
  2. 고유 정보 정리:
    sudo truncate -s0 /etc/machine-id
    sudo rm -f /var/lib/dbus/machine-id
    sudo rm -rf /var/lib/cloud/instances/* /var/lib/cloud/instance
    sudo rm /etc/ssh/ssh_host_*      # 클론 시 새 키 생성
    sudo cloud-init clean --seed --logs --all
    
    이 과정을 문서화해 템플릿 스크립트로 자동화하면 실수를 줄일 수 있습니다.
  3. Cloud-Init 드라이브 추가: Proxmox UI → VM → Hardware → Add -> Cloud-Init Drive가능하면 공유 스토리지를 선택합니다. 클라우드-이닛 ISO가 local-lvm에 있으면 qm migrate가 실패하거나 새 노드에서 드라이브를 찾지 못합니다. 단일 노드 홈랩이라도 이 제약을 감수할 때만 로컬 스토리지를 사용하십시오. 게스트에서 cloud-init query --format '%(datasource)s'ConfigDrive인지 확인하고, 실패하면 /dev/sr0 존재 여부를 먼저 점검합니다.
  4. 템플릿 변환:
    qm shutdown <ID>
    qm template <ID>
    
  5. 클론과 초기 매개변수 입력:
    qm clone <TEMPLATE-ID> <NEW-ID> --name <hostname>
    qm set <NEW-ID> --cores 4 --memory 4096 --ipconfig0 "ip=192.168.1.20/24,gw=192.168.1.1"
    
    SSH 키는 CLI 인자 대신 Cloud-Init 탭이나 사용자 데이터 스니펫(cicustom)으로 넣어 로그에 남지 않도록 합니다. 값을 채운 뒤 부팅하고 cloud-init status --wait --timeout 15, hostnamectl, /var/log/cloud-init-output.log로 적용 결과를 검증합니다. 명령이 멈추면 cloud-init query --format '%(datasource)s'를 다시 확인하십시오.

흔한 실수와 체크리스트

  • CPU 타입을 host로 고정: 하드웨어 교체 시 부팅 실패. → 템플릿 기본값을 x86-64-v2-AES로 문서에 고정.
  • Ballooning 남용: 메모리 부족이 늦게 나타남. → 모니터링 알람과 함께 켜거나 기본값은 비활성화.
  • Guest Agent 미설치: IP/상태 조회 불가. → 클라우드-이닛 스크립트로 qemu-guest-agent 자동 설치.
  • Cloud-Init 드라이브 누락: 자동 사용자/네트워크 구성이 동작하지 않음. → 템플릿 변환 전 하드웨어 목록 점검.
  • TRIM 미구성: LVM-Thin이 가득 차면 VM 전체가 멈춤. → 주간 fstrim -av 크론 작업까지 포함.

체크리스트

  • x86-64-v2-AES 또는 CPU 세대에 맞는 타입으로 템플릿이 설정되어 있는가
  • 기본 메모리/balloon 정책과 NUMA 옵션이 문서화되어 있는가
  • 디스크 컨트롤러, 캐시, Discard 설정이 항목별로 기록되어 있는가
  • vmbr/VLAN, NIC 모델, Guest Agent 설치 커맨드가 플레이북에 포함되어 있는가
  • Cloud-Init 드라이브 추가, machine-id 초기화, qm template/clone 명령이 검증되었는가
  • 클론 후 cloud-init status --wait와 SSH 호스트 키 재생성을 확인하는 절차가 있는가

마무리

표준 Linux VM은 워크로드 추가 속도를 높이고, 여러 사람이 같은 방식으로 VM을 운영하도록 만드는 안전장치입니다. CPU·메모리·디스크·네트워크를 한 번 정의해 두면 이후에는 워크로드 특성에 맞춰 조정만 하면 됩니다. 템플릿을 만들어 두면 실수로 잘못된 드라이버를 고르는 일도 줄어듭니다.

다음 글에서는 이 표준 VM과 LXC 구성을 백업·복구 루틴에 연결하는 방법을 다룰 예정입니다.

💬 댓글

이 글에 대한 의견을 남겨주세요