Izgradite produkcijski KVM virtualni laboratorij s premoštenim umrežavanjem i Cloud-Initom
Korisni virtualni laboratorij trebao bi se ponašati kao infrastruktura, a ne kao zbirka jednokratnih stolnih VM-ova. Potrebni su mu predvidivo adresiranje, ograničena potrošnja resursa, ponovljivo provisioniranje, vidljivi neuspjesi pri podizanju sustava i put oporavka koji i dalje radi nakon što vas disk hosta iznevjeri.
Ovaj vodič izgrađuje takav sustav na Ubuntu Server KVM hostu. Rezultat je Ubuntu gost s dva vCPU-a naziva lab01, izravno povezan s fizičkim LAN-om putem br0, provisioniran s pomoću cloud-inita, zaštićen ograničenjima resursa te pokriven urednim snimkama i neovisno obnovivim sigurnosnim kopijama.
Arhitektura, pretpostavke i kompromisi
Primjer LAN-a je 192.168.50.0/24. Njegov pristupnik i DNS razrješivač su 192.168.50.1; host koristi 192.168.50.2; a lab01 koristi 192.168.50.10. Prije nastavka potvrdite da su te adrese izvan vašeg DHCP raspona i da se ne koriste.
Host ima jedno žično sučelje, enp3s0. Ono postaje port sučelja br0, pa se adresa hosta premješta s fizičkog sučelja na most. Tu promjenu izvršite iz lokalne ili izvanpojasne konzole: čak i ispravna migracija mreže može prekinuti SSH sesiju.
Fizički most gostima daje prvoklasnu prisutnost u LAN-u i izbjegava NAT ili prosljeđivanje portova hosta. Cijena je izloženost: uzvodni preklopnik vidi dodatnu MAC adresu, a gost mora biti zaštićen kao svaki fizički poslužitelj. Uobičajena Wi-Fi klijentska sučelja općenito ne mogu pružiti ovaj oblik transparentnog premošćivanja jer pristupne točke često odbijaju dodatne izvorne MAC adrese.
Raspored pohrane koristi nepromjenjivu Ubuntu cloud sliku kao qcow2 pozadinsku datoteku i tanki sloj za VM. Time se štedi prostor, ali pozadinska slika postaje dio lanca pokrenutog diska i nikada se ne smije zamijeniti na mjestu. Sigurnosne kopije stoga će izravnati lanac u samostalne qcow2 slike.
Preduvjeti i struktura projekta
Upotrijebite Ubuntu Server host s omogućenim hardverskim virtualiziranjem, žičnom Ethernet vezom i dovoljno rezerviranog kapaciteta za sam host. Administrativni račun treba sudo pristup i postojeći javni Ed25519 SSH ključ.
Instalirajte KVM, libvirt, pomoćne programe za slike, cloud-init alate i instalacijski program za VM. Dodavanje računa grupama libvirt i kvm stupa na snagu nakon odjave i ponovne prijave.
sudo apt update
sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients \
virtinst qemu-utils cloud-image-utils
sudo systemctl enable --now libvirtd
sudo usermod -aG libvirt,kvm "$USER"
sudo virt-host-validate qemu
sudo virsh --connect qemu:///system list --all
Laboratorij čuva trajne artefakte pod jednom izričitom putanjom:
/srv/kvm-lab/
├── cloud-init/
│ ├── lab01-meta-data
│ ├── lab01-network-config
│ └── lab01-user-data
├── images/
│ ├── noble-server-cloudimg-amd64.img
│ └── lab01.qcow2
├── seeds/
│ └── lab01-seed.img
├── backups/
└── scripts/
└── backup-lab01.sh
Stvorite ga s dozvolama koje omogućuju sistemskom libvirt procesu prolazak kroz pohranu i čitanje iz nje:
sudo install -d -o "$USER" -g kvm -m 0770 \
/srv/kvm-lab/{cloud-init,images,seeds,backups,scripts}
Sigurno izgradite most hosta
Sljedeća Netplan konfiguracija pretpostavlja Ubuntu Serverov renderer systemd-networkd. Spremite je kao /etc/netplan/60-kvm-bridge.yaml, ali najprije uskladite svaku postojeću Netplan datoteku koja konfigurira enp3s0. Sučelje ne smije dobivati sukobljene definicije iz više datoteka.
network:
version: 2
renderer: networkd
ethernets:
enp3s0:
dhcp4: false
dhcp6: false
bridges:
br0:
interfaces:
- enp3s0
addresses:
- 192.168.50.2/24
routes:
- to: default
via: 192.168.50.1
nameservers:
addresses:
- 192.168.50.1
parameters:
stp: false
forward-delay: 0
dhcp4: false
dhcp6: false
Upotrijebite netplan try iz konzole hosta. Konfiguracija se automatski vraća osim ako ne potvrdite da radna konfiguracija ispravno funkcionira:
sudo chmod 0600 /etc/netplan/60-kvm-bridge.yaml
sudo netplan generate
sudo netplan try
ip -brief address show br0
ip route
bridge link show
Ne konfigurirajte adresu hosta istodobno na enp3s0 i br0. Fizičko sučelje nakon migracije ne bi smjelo imati adresu trećeg sloja.
Stvorite osnovnu sliku i sloj
Preuzmite trenutnu Ubuntu 24.04 LTS cloud sliku i provjerite je prema kontrolnom zbroju objavljenom uz nju. Kontrolni zbroj preuzet s istog HTTPS izvora otkriva oštećenje; okruženja koja zahtijevaju snažnije jamstvo izvornosti trebala bi dodatno provjeriti Ubuntuovu potpisanu datoteku kontrolnih zbrojeva u skladu sa svojom politikom povjerenja.
cd /srv/kvm-lab/images
curl --fail --location --remote-name \
https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
curl --fail --location --remote-name \
https://cloud-images.ubuntu.com/noble/current/SHA256SUMS
sha256sum --check --ignore-missing SHA256SUMS
qemu-img info noble-server-cloudimg-amd64.img
qemu-img create -f qcow2 -F qcow2 \
-b /srv/kvm-lab/images/noble-server-cloudimg-amd64.img \
/srv/kvm-lab/images/lab01.qcow2 40G
sudo chgrp kvm noble-server-cloudimg-amd64.img lab01.qcow2
sudo chmod 0660 noble-server-cloudimg-amd64.img lab01.qcow2
Veličina od 40 GB je najveća veličina vidljiva gostu, a ne trenutačna dodjela. Nadzirite datotečni sustav hosta jer qcow2 ne može zaštititi VM od iscrpljenog volumena hosta.
Provisionirajte gosta s pomoću cloud-inita
Generirajte korisničke podatke iz postojećeg javnog Ed25519 ključa administratora. Uklanjanjem neobaveznog komentara ključa izbjegavaju se nezgodni YAML znakovi uz očuvanje cijelog ključa.
cd /srv/kvm-lab
key_file="${HOME}/.ssh/id_ed25519.pub"
test -s "$key_file" || {
echo "Missing SSH public key: $key_file" >&2
exit 1
}
public_key=$(awk 'NR == 1 { print $1 " " $2 }' "$key_file")
cat > cloud-init/lab01-user-data <<EOF
#cloud-config
hostname: lab01
fqdn: lab01.lab.internal
manage_etc_hosts: true
ssh_pwauth: false
disable_root: true
users:
- name: ops
groups:
- sudo
shell: /bin/bash
lock_passwd: true
sudo:
- ALL=(ALL) NOPASSWD:ALL
ssh_authorized_keys:
- ${public_key}
package_update: true
packages:
- qemu-guest-agent
runcmd:
- [systemctl, enable, --now, qemu-guest-agent]
EOF
cat > cloud-init/lab01-meta-data <<'EOF'
instance-id: lab01-001
local-hostname: lab01
EOF
cat > cloud-init/lab01-network-config <<'EOF'
version: 2
ethernets:
ens3:
match:
driver: virtio_net
set-name: ens3
addresses:
- 192.168.50.10/24
routes:
- to: default
via: 192.168.50.1
nameservers:
addresses:
- 192.168.50.1
EOF
cloud-localds \
--network-config=cloud-init/lab01-network-config \
seeds/lab01-seed.img \
cloud-init/lab01-user-data \
cloud-init/lab01-meta-data
sudo chgrp kvm seeds/lab01-seed.img
sudo chmod 0660 seeds/lab01-seed.img
Cloud-init obično primjenjuje određeni ID instance samo jednom. Ako namjerno ponovno izgradite sloj, promijenite instance-id ili očistite stanje cloud-inita unutar odbačenog gosta prije snimanja predloška.
Postavite VM s izričitim ograničenjima
Stvorite domenu s fiksna dva vCPU-a i gornjom granicom od 2 GB, virtio uređajima, serijskim pristupom i kanalom za agenta gosta. Prosljeđivanje CPU-a hosta poboljšava dostupnost značajki, ali VM čvršće veže uz ovu obitelj procesora, čineći migraciju na različit hardver manje pouzdanom.
sudo virt-install \
--connect qemu:///system \
--name lab01 \
--import \
--os-variant ubuntu24.04 \
--memory 2048,maxmemory=2048 \
--vcpus 2,maxvcpus=2 \
--cpu host-passthrough \
--disk path=/srv/kvm-lab/images/lab01.qcow2,format=qcow2,bus=virtio,cache=none,discard=unmap \
--disk path=/srv/kvm-lab/seeds/lab01-seed.img,device=cdrom,readonly=on \
--network bridge=br0,model=virtio,mac=52:54:00:50:00:10 \
--channel unix,target_type=virtio,name=org.qemu.guest_agent.0 \
--graphics none \
--console pty,target_type=serial \
--noautoconsole
sudo virsh autostart lab01
sudo virsh schedinfo lab01 \
--set vcpu_period=100000 \
--set vcpu_quota=100000 \
--live --config
sudo virsh blkdeviotune lab01 vda \
--total-bytes-sec 52428800 \
--live --config
CPU kvota dopušta približno jedan CPU hosta ukupnog izvršavanja na dva virtualna CPU-a; radna opterećenja i dalje mogu koristiti dvosmjernu konkurentnost u kratkim naletima. Pravilo za disk ograničava kombinirani protok na 50 MiB/s. Oba ograničenja prilagodite izmjerenom opterećenju hosta, umjesto da ove vrijednosti smatrate univerzalnima.
Testirajte, učvrstite i nadzirite
Pričekajte cloud-init prije procjene provisioniranja. S hosta provjerite povezivost, agenta, ograničenja uređaja i stanje automatskog pokretanja:
ping -c 3 192.168.50.10
ssh [email protected] 'cloud-init status --wait'
ssh [email protected] 'systemctl is-active qemu-guest-agent'
sudo virsh qemu-agent-command lab01 '{"execute":"guest-ping"}'
sudo virsh dominfo lab01
sudo virsh domblklist lab01 --details
sudo virsh schedinfo lab01
sudo virsh blkdeviotune lab01 vda
sudo virsh domstats lab01 --vcpu --balloon --block --interface
Unutar gosta omogućite vatrozid koji prema zadanim postavkama sve odbija, uz zadržavanje SSH pristupa s administrativnog LAN-a:
sudo apt install ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from 192.168.50.0/24 to any port 22 proto tcp
sudo ufw enable
sudo ufw status verbose
Vatrozid hosta ne štiti automatski promet premošćenog gosta; ponašanje ovisi o konfiguraciji bridge netfiltera hosta. Primijenite pravila na gostu i, gdje je prikladno, na fizičkom preklopniku ili uzvodnom vatrozidu. Zadržite upravljanje libvirtom lokalnim osim ako je autentificirana udaljena administracija izričit zahtjev.
Za neuspjehe na strani hosta upotrijebite journalctl -u libvirtd, za rano podizanje sustava virsh console lab01, a za pogreške provisioniranja unutar gosta /var/log/cloud-init-output.log. Pratite dodjelu diska pomoću qemu-img info samo dok je slika neaktivna; za pokrenuti VM upotrijebite statistike libvirt blokova.
Nakon uspješnog provisioniranja odvojite seed od trajne konfiguracije kako buduće sigurnosne kopije ne bi ovisile o njemu:
sudo virsh detach-disk lab01 \
/srv/kvm-lab/seeds/lab01-seed.img \
--config
Upotrijebite snimke kao točke vraćanja
Snimke su praktične prije rizičnog održavanja, ali nisu sigurnosne kopije: dijele isti host, pohranu i domenu kvara. Za čistu internu snimku zaustavite gosta i pričekajte da libvirt prijavi shut off.
sudo virsh shutdown lab01
until test "$(sudo virsh domstate lab01)" = "shut off"; do
sleep 2
done
sudo virsh snapshot-create-as lab01 pre-upgrade \
--description "Clean checkpoint before package upgrade" \
--atomic
sudo virsh snapshot-list lab01
sudo virsh start lab01
Za vraćanje zaustavite gosta na uredan način, pokrenite sudo virsh snapshot-revert lab01 pre-upgrade i ponovno ga pokrenite. Vraćanje odbacuje sve promjene napravljene nakon kontrolne točke. Zastarjele snimke brišite namjerno jer nakupljene interne snimke povećavaju qcow2 metapodatke i operativnu složenost.
Stvorite obnovivu izvanmrežnu sigurnosnu kopiju
Spremite sljedeću skriptu kao /srv/kvm-lab/scripts/backup-lab01.sh i učinite je izvršnom. Ona zahtijeva uredno gašenje, čeka najviše dvije minute, izravnava pozadinski lanac, bilježi XML domene, izračunava kontrolne zbrojeve rezultata i ponovno pokreće samo VM koji je izvorno bio pokrenut. Neuspješna konverzija ne ostavlja valjani manifest kontrolnih zbrojeva, pa će oporavak odbiti nepotpuni direktorij.
#!/usr/bin/env bash
set -Eeuo pipefail
vm="lab01"
disk="/srv/kvm-lab/images/lab01.qcow2"
stamp=$(date -u +%Y%m%dT%H%M%SZ)
dest="/srv/kvm-lab/backups/${vm}-${stamp}"
restart=0
cleanup() {
if (( restart )); then
state=$(sudo virsh domstate "$vm" 2>/dev/null || true)
if [[ "$state" == "shut off" ]]; then
sudo virsh start "$vm"
fi
fi
}
trap cleanup EXIT
state=$(sudo virsh domstate "$vm")
if [[ "$state" == "running" ]]; then
restart=1
sudo virsh shutdown "$vm"
for ((attempt = 1; attempt <= 60; attempt++)); do
[[ "$(sudo virsh domstate "$vm")" == "shut off" ]] && break
sleep 2
done
fi
[[ "$(sudo virsh domstate "$vm")" == "shut off" ]] || {
echo "Guest did not shut down; backup aborted" >&2
exit 1
}
sudo install -d -o root -g root -m 0700 "$dest"
sudo virsh dumpxml "$vm" | sudo tee "$dest/lab01.xml" >/dev/null
sudo qemu-img convert -p -O qcow2 \
-o compat=1.1,lazy_refcounts=on \
"$disk" "$dest/lab01.qcow2"
sudo qemu-img check "$dest/lab01.qcow2"
cd "$dest"
sudo sha256sum lab01.xml lab01.qcow2 |
sudo tee SHA256SUMS >/dev/null
Pokrenite je s chmod 0750 /srv/kvm-lab/scripts/backup-lab01.sh, a zatim s putanjom skripte. Dovršene direktorije sigurnosnih kopija kopirajte na zasebnu pohranu s neovisnim zadržavanjem. Gašenje osigurava čisto stanje datotečnog sustava; baze podataka i vanjske usluge ipak mogu zahtijevati postupke sigurnosnog kopiranja svjesne aplikacije.
Dokažite oporavak prije nego što mu vjerujete
Odaberite dovršenu sigurnosnu kopiju, provjerite njezin manifest i najprije pokrenite qemu-img check te provjerite direktorije pohrane, vratite disk na istu apsolutnu putanju, a zatim definirajte spremljeni XML. Ne pokrećite oporavljeni VM uz originalni jer dijele IP adresu, MAC adresu, identitet stroja i SSH ključeve hosta.
Završni kontrolni popis za provjeru
- Host posjeduje
192.168.50.2nabr0, a ne naenp3s0. lab01doseže pristupnik i dostupan je samo putem predviđenih pravila vatrozida.- Cloud-init je dovršen bez pogrešaka, a agent gosta odgovara putem libvirta.
- Ograničenja memorije, vCPU-a, CPU kvote i propusnosti bloka ostaju nakon ponovnog pokretanja.
- VM se automatski pokreće, dok host zadržava dovoljno nedodijeljene memorije i pohrane.
- Čista snimka može se stvoriti, popisati, vratiti i ukloniti.
- Najnovija sigurnosna kopija prolazi i SHA-256 provjeru i
qemu-img check. - Oporavak je uvježban bez istodobnog dopuštanja originalnog i vraćenog identiteta na LAN-u.
Laboratorij produkcijske razine nije određen brzinom podizanja prvog VM-a. Određen je predvidivošću ponašanja desetog VM-a, jasnoćom kojom se kvarovi prikazuju i mirnoćom s kojom se sustav može vratiti. Premošćivanje, cloud-init, kvote, snimke i provjerene sigurnosne kopije pretvaraju KVM iz praktičnog hipervizora u infrastrukturu o kojoj možete razumno promišljati.