Dodici build

Proxmox su bare metal, con macchine virtuali annidate che funzionano

Una macchina EPYC single-tenant che esegue Proxmox VE su NVMe mirrorato, un bridge instradato per gli ospiti e virtualizzazione annidata dimostrata dall'interno di un ospite.

Cosa si realizza

Una macchina bare metal che esegue Proxmox VE come proprio hypervisor, con un mirror ZFS sui drive NVMe, un bridge che assegna indirizzi reali alle VM e virtualizzazione annidata attivata e verificata — il che significa che una VM su questa macchina può a sua volta eseguire VM.

L'annidamento è il motivo per farlo su metallo piuttosto che su un'istanza virtuale. Non puoi annidare dentro l'hypervisor di qualcun altro con risultati prevedibili, e su un BM-E non c'è un nostro hypervisor in mezzo: hai IPMI, un pulsante di accensione e la scheda madre. Ciò che ci gira è una tua decisione.

Prima di iniziare

  • Un BM-E: trentadue core Zen 4, 256 GB di ECC, quattro drive NVMe e otto indirizzi IPv4. L'IPMI è raggiungibile tramite VPN, che il supporto configura quando la macchina viene consegnata.
  • Proxmox VE 8 selezionato al momento dell'ordine, oppure un'ISO personalizzata caricata tramite il pannello. Entrambe le strade portano allo stesso installer.
  • Mezz'ora in cui nessuno ha bisogno della macchina, perché il primo passaggio la riavvia diverse volte.

1. Installazione

Connettiti alla console tramite la VPN di gestione, monta l'ISO e avviala. Nella schermata di selezione dei dischi scegli tutti e quattro i device NVMe, seleziona zfs (RAID10) e apri le opzioni avanzate:

  • ashift a 12, che è il valore corretto per settori da quattro kilobyte e non può essere modificato in seguito senza ricostruire il pool.
  • compress su lz4. Costa una frazione di core e tipicamente restituisce un terzo dello spazio.
  • hdsize ridotto per lasciare il resto allo storage delle VM, a meno che tu non voglia che il pool di root possieda tutto.

Imposta l'indirizzo di gestione e il gateway dai dettagli del pannello e usa il nome completo della macchina come hostname. Dopo due riavvii hai un prompt di login e un'interfaccia web sulla porta 8006.

2. Repository e pacchetti

Il repository enterprise fallirà senza abbonamento e riempirà ogni apt update finché non lo risolvi:

rm -f /etc/apt/sources.list.d/pve-enterprise.sources
echo "deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription" > /etc/apt/sources.list.d/pve-community.list
apt update && apt full-upgrade -y
apt install -y ifupdown2 chrony zfsutils-linux
reboot

3. Memoria per ZFS

L'ARC altrimenti crescerà fino a metà della RAM, e su una macchina il cui intero lavoro è eseguire VM, quella memoria ha un uso migliore:

echo "options zfs zfs_arc_max=34359738368" > /etc/modprobe.d/zfs.conf
update-initramfs -u -k all

Trentadue gigabyte di ARC su una macchina da 256 GB lasciano molto spazio per la cache senza far morire di fame le VM. Riavvia per applicarlo, oppure impostalo dal vivo con echo in /sys/module/zfs/parameters/zfs_arc_max se non puoi.

4. Rete

Otto indirizzi non sono molti, quindi le VM stanno su un bridge privato e solo quelle che necessitano di un indirizzo pubblico ne ricevono uno instradato. Modifica /etc/network/interfaces:

auto lo
iface lo inet loopback

auto enp1s0f0
iface enp1s0f0 inet static
  address <public address>/24
  gateway <gateway>

auto vmbr0
iface vmbr0 inet static
  address 10.20.0.1/24
  bridge-ports none
  bridge-stp off
  bridge-fd 0
  post-up   iptables -t nat -A POSTROUTING -s 10.20.0.0/24 -o enp1s0f0 -j MASQUERADE
  post-down iptables -t nat -D POSTROUTING -s 10.20.0.0/24 -o enp1s0f0 -j MASQUERADE

iface vmbr0 inet6 static
  address 2001:db8:1a2b:20::1/64

IPv6 non necessita di traduzione di indirizzi, perché il /64 instradato alla macchina è realmente instradato: assegna indirizzi da quello alle VM sul bridge e raggiungono internet direttamente. Quell'asimmetria tra le due famiglie non è elegante, ma è la forma onesta dello spazio degli indirizzi in cui viviamo.

sysctl -w net.ipv4.ip_forward=1
echo "net.ipv4.ip_forward = 1" > /etc/sysctl.d/80-pve.conf
echo "net.ipv6.conf.all.forwarding = 1" >> /etc/sysctl.d/80-pve.conf
ifreload -a

5. Virtualizzazione annidata

cat /sys/module/kvm_amd/parameters/nested

Sui kernel attuali questo stampa già 1. Se stampa 0:

echo "options kvm-amd nested=1" > /etc/modprobe.d/kvm-amd.conf
update-initramfs -u && reboot

L'annidamento richiede anche che la VM veda una CPU che ammette di avere la funzionalità, il che significa che il tipo di processore deve essere host. Qualsiasi altra cosa presenta un modello di CPU sintetico con le estensioni di virtualizzazione mascherate, e l'hypervisor interno rifiuta di avviarsi con un errore che non menziona nulla di tutto ciò.

6. Una VM

cd /var/lib/vz/template/iso
wget https://cloud.debian.org/images/cloud/trixie/latest/debian-13-genericcloud-amd64.qcow2

qm create 100 --name inner --memory 16384 --cores 8 --cpu host \
  --net0 virtio,bridge=vmbr0 --scsihw virtio-scsi-single --ostype l26 \
  --agent enabled=1 --machine q35 --bios ovmf
qm set 100 --efidisk0 local-zfs:1
qm importdisk 100 debian-13-genericcloud-amd64.qcow2 local-zfs
qm set 100 --scsi0 local-zfs:vm-100-disk-1,discard=on,ssd=1
qm set 100 --boot order=scsi0
qm set 100 --ipconfig0 ip=10.20.0.100/24,gw=10.20.0.1
qm set 100 --sshkeys /root/.ssh/authorized_keys
qm set 100 --ciuser admin
qm start 100

discard=on con ssd=1 significa che le eliminazioni all'interno della VM vengono restituite al pool invece di accumularsi come spazio di cui hai perso traccia.

7. Firewall

L'interfaccia web sulla porta 8006 non ha motivo di essere pubblicamente raggiungibile. Restringila a livello di datacenter all'indirizzo da cui amministri — l'endpoint del tunnel dalla guida WireGuard è il candidato ovvio:

cat > /etc/pve/firewall/cluster.fw <<EOF
[OPTIONS]
enable: 1
policy_in: DROP

[RULES]
IN SSH(ACCEPT) -source 10.7.0.0/24
IN ACCEPT -source 10.7.0.0/24 -dport 8006 -proto tcp
IN ACCEPT -p icmp
EOF
systemctl restart pve-firewall

Verifica

Prima l'host:

pveversion -v | head -3
zpool status rpool
zpool list -o name,size,alloc,free,frag,cap
arc_summary | head -12

Il pool riporta ONLINE con due coppie mirror e il target dell'ARC è sui trentadue gigabyte che hai impostato, non a metà della macchina.

Ora il vero scopo di questa configurazione. Accedi alla VM e controlla il processore che gli è stato assegnato:

ssh [email protected]
lscpu | grep -E "Model name|Virtuali"
grep -c svm /proc/cpuinfo

Il nome del modello dovrebbe essere la vera parte EPYC e la riga di virtualizzazione dovrebbe riportare AMD-V. Uno zero dal terzo comando significa che il tipo di processore non è host e tutto ciò che segue fallirà.

Poi esegui una macchina dentro la macchina:

apt install -y qemu-system-x86 qemu-utils cpu-checker
kvm-ok
wget https://dl-cdn.alpinelinux.org/alpine/v3.22/releases/x86_64/alpine-virt-3.22.0-x86_64.iso
qemu-system-x86_64 -enable-kvm -m 2048 -cdrom alpine-virt-3.22.0-x86_64.iso -nographic

kvm-ok che stampa che l'accelerazione può essere usata, seguito da un boot Alpine che raggiunge un prompt di login in un paio di secondi invece di strisciare, è la verifica. Senza annidamento, quello stesso comando o rifiuta del tutto o emula via software a circa un ventesimo della velocità, il che è inconfondibile.

Infine, conferma che l'interfaccia sia chiusa dall'esterno:

curl -m5 -k https://<public address>:8006/ ; echo "exit $?"

Un timeout di connessione è la risposta corretta.

Dopo

Gli snapshot su ZFS sono gratuiti finché non divergono, quindi una pianificazione notturna con zfs-auto-snapshot costa quasi nulla e ha salvato più macchine di qualsiasi policy di backup. I rebuild su metallo sono nello stesso giorno, ma un rebuild ti restituisce una macchina vuota, che è una cosa diversa dal restituirti la tua macchina.

Pronto quando lo sei

Scegli una città. Scegli una dimensione. Paga in criptovaluta.

Nessun modulo su chi sei, nessuna attesa per l'approvazione di una persona, nessuna chiamata per verificare nulla. La fattura viene saldata e le credenziali arrivano nella tua casella di posta.