El curs fa quatre mòduls que troba a faltar el mateix. Al Mòdul 4, el release 3.3.0 no va arrencar i desplegar.sh va fer una reversió automàtica —correcte— però ningú no va arribar a diagnosticar per què no arrencava, perquè no hi havia on reproduir-ho. A 07-01 vas practicar la recuperació de l'arrencada trencant el fstab del servidor real, amb instantània prèvia i creuant els dits. A 07-03, l'últim exercici demanava buidar la memòria cau de pàgina, treure l'ionice i aturar l'aplicació per mesurar el planificador d'E/S: tres coses que no es fan en producció. I va quedar pendent comprovar si la CPU exposa AES-NI a l'hoste, que és un canvi de configuració de la màquina virtual.
Tot això apunta a la mateixa mancança: falta un entorn de proves. Aquesta lliçó el construeix, i pel camí t'ensenya la pila de virtualització des de dins — que és el que farà que la lliçó següent, contenidors, s'entengui per contrast i no per analogia equivocada.
Contingut
- Què és virtualitzar: els tres models
- Hipervisors de tipus 1 i de tipus 2
- Virtualització davant de contenidors
- KVM, QEMU i libvirt: qui fa què
- Instal·lació i comprovació del suport
- virsh: gestionar màquines des de la línia d'ordres
- Crear una màquina amb virt-install
- Aprovisionament desatès amb cloud-init
- Emmagatzematge: formats, pools i instantànies
- Xarxa: NAT, aïllada i pont
- Rendiment: virtio i configuració de CPU
- Clonar i crear srv-tramontana-proves
Què és virtualitzar: els tres models
Virtualitzar és executar un sistema operatiu complet dins d'un altre, fent-li creure que té el seu propi maquinari. El problema tècnic de fons: certes instruccions de la CPU són privilegiades i només les pot executar el nucli. Si el sistema hoste es pensa que és el nucli i n'executa una, cal interceptar-la i fer-hi alguna cosa. Les tres maneres de resoldre-ho defineixen els tres models:
| Model | Com maneja les instruccions privilegiades | Rendiment | Requereix modificar l'hoste |
|---|---|---|---|
| Emulació | Tradueix cada instrucció per programari | 10-100 vegades més lent | No |
| Paravirtualització | L'hoste sap que està virtualitzat i demana els serveis a l'hipervisor per una API | 90-95 % del natiu | Sí |
| Assistida per maquinari | La CPU té un mode específic (VT-x/AMD-V) que les intercepta tota sola | 95-99 % del natiu | No |
L'emulació encara té el seu ús: és el que permet executar ARM sobre x86 (qemu-system-aarch64) o un sistema de 1985. Per virtualitzar Linux sobre Linux a la mateixa arquitectura, és absurdament lenta.
La paravirtualització va ser la tècnica dominant abans del 2006 (Xen la va popularitzar) i exigia un nucli modificat. Avui sobreviu en una cosa molt més important del que sembla: els controladors paravirtualitzats, virtio, que veuràs més endavant i que són la diferència entre una VM lenta i una de ràpida.
La virtualització assistida per maquinari és la que fa servir srv-tramontana i la que es fa servir arreu avui. Intel l'anomena VT-x i AMD, AMD-V; totes dues afegeixen un nivell de privilegi per sota del nucli on viu l'hipervisor.
Hipervisors de tipus 1 i de tipus 2
| Tipus 1 (natiu) | Tipus 2 (allotjat) | |
|---|---|---|
| On corre | Directament sobre el maquinari | Com a aplicació sobre un SO |
| Exemples | VMware ESXi, Xen, Hyper-V | VirtualBox, VMware Workstation |
| Rendiment | Major: sense SO intermedi | Menor, encara que poc amb VT-x |
| Ús típic | Centres de dades, núvol | Escriptori, desenvolupament, laboratori |
I KVM desafia aquella classificació, que és l'interessant: és un mòdul del nucli de Linux, així que tècnicament hi ha un sistema operatiu a sota (tipus 2), però aquell sistema operatiu es converteix en l'hipervisor en carregar-lo, amb accés directe a les extensions de virtualització (tipus 1). La resposta honesta és que és un híbrid, i a la pràctica rendeix com un tipus 1.
El teu portàtil està executant VirtualBox, que és de tipus 2. srv-tramontana és una VM a dins seu. I en aquesta lliçó crearàs una VM dins de srv-tramontana, cosa que s'anomena virtualització imbricada i requereix que VirtualBox exposi les extensions de CPU a l'hoste. Hi tornarem a l'apartat d'instal·lació.
Virtualització davant de contenidors
Aquesta comparació és el pont cap a la lliçó següent, i convé veure-la abans de tocar contenidors per no adquirir l'analogia equivocada:
graph TB
subgraph VM["Maquina virtual"]
H1["Maquinari fisic"] --> K1["Nucli amfitrio + KVM"]
K1 --> Q1["QEMU"] & Q2["QEMU"]
Q1 --> KG1["Nucli hoste 1"] --> A1["Biblioteques + app"]
Q2 --> KG2["Nucli hoste 2"] --> A2["Biblioteques + app"]
end
subgraph CT["Contenidors"]
H2["Maquinari fisic"] --> K2["Nucli amfitrio UNIC"]
K2 --> N1["namespace + cgroup"] --> B1["Biblioteques + app"]
K2 --> N2["namespace + cgroup"] --> B2["Biblioteques + app"]
end
La diferència estructural és en una sola fila del diagrama: cada VM té el seu propi nucli; els contenidors comparteixen el de l'amfitrió. D'aquí se'n deriven totes les altres diferències:
| Màquina virtual | Contenidor | |
|---|---|---|
| Nucli | Propi | Compartit amb l'amfitrió |
| Arrencada | 10-60 segons | Mil·lisegons |
| Pes al disc | GB (sistema complet) | MB (només l'aplicació i les seves biblioteques) |
| Sobrecàrrega de memòria | 200 MB - 1 GB per VM | Pràcticament nul·la |
| Aïllament | Fort: frontera de maquinari virtual | Més feble: frontera de nucli |
| Pot executar un altre SO | Sí (Windows, BSD, un altre nucli Linux) | No: només Linux, i el de l'amfitrió |
| Densitat típica | Desenes per amfitrió | Centenars o milers |
I les dues conseqüències que cal retenir:
- Per a aïllament de seguretat, la VM és superior. Una fuga de contenidor és una fallada del nucli compartit i dona accés a l'amfitrió. Una fuga de VM requereix vulnerar l'hipervisor, que és una superfície molt menor. Per això els proveïdors de núvol executen càrregues de clients diferents en VM separades, no en contenidors del mateix nucli.
- Per a densitat i velocitat, el contenidor guanya per ordres de magnitud. Arrencar cent contenidors és qüestió de segons; cent VM són cent nuclis.
No són alternatives: es combinen. L'habitual avui és executar contenidors dins de màquines virtuals, aprofitant l'aïllament de la VM entre inquilins i la densitat del contenidor dins de cadascuna.
KVM, QEMU i libvirt: qui fa què
Tres peces que es confonen constantment. Cadascuna resol un problema diferent:
| Peça | Què és | Què resol |
|---|---|---|
| KVM | Un mòdul del nucli (/dev/kvm) |
Donar accés a VT-x/AMD-V: executar la CPU virtual a velocitat nativa |
| QEMU | Un programa d'espai d'usuari | Emular tota la resta: disc, xarxa, teclat, gràfics, BIOS |
| libvirt | Un dimoni i una biblioteca | Gestió: definir, arrencar, aturar, xarxa, emmagatzematge, API estable |
La divisió de feina entre les dues primeres és la clau: KVM s'encarrega de la CPU i la memòria, que és on el rendiment importa; QEMU emula els dispositius, als quals s'accedeix molt menys. Sense KVM, QEMU emularia també la CPU i tindries el model lent del primer apartat. La combinació se sol escriure «QEMU/KVM».
I libvirt aporta una cosa que no és òbvia fins que gestiones més de dues màquines: una capa d'abstracció estable. La línia d'ordres de QEMU és llarguíssima i canvia entre versions; libvirt defineix la màquina en XML, i virsh parla sempre igual. A més gestiona xarxes virtuals, pools d'emmagatzematge i permisos, i és l'API que fan servir virt-manager, Vagrant, OpenStack i Terraform.
Instal·lació i comprovació del suport
Primer, comprovar que hi ha suport de maquinari. I aquí apareix la complicació de la virtualització imbricada:
$ sudo apt install cpu-checker
$ kvm-ok
INFO: /dev/kvm does not exist
HINT: sudo modprobe kvm_intel
INFO: Your CPU supports KVM extensions
INFO: KVM (vmx) is disabled by your BIOSsrv-tramontana és una VM de VirtualBox, i per defecte VirtualBox no exposa les extensions de virtualització a l'hoste. Cal activar-ho des de l'amfitrió, amb la màquina apagada:
# Al portatil amfitrio, amb srv-tramontana APAGADA
$ VBoxManage modifyvm srv-tramontana --nested-hw-virt on
$ VBoxManage showvm srv-tramontana --machinereadable | grep -i nested
nestedHWVirt="on"A VMware l'opció equivalent és Virtualize Intel VT-x/EPT, i en un servidor físic n'hi ha prou d'activar VT-x/AMD-V a la UEFI. Després d'encendre de nou:
$ kvm-ok
INFO: /dev/kvm exists
KVM acceleration can be used
$ grep -o -m1 -E 'vmx|svm' /proc/cpuinfo
vmx
$ lsmod | grep kvm
kvm_intel 376832 0
kvm 1146880 1 kvm_intel
irqbypass 12288 1 kvmSi kvm-ok continua fallant, la virtualització funcionarà per emulació pura: utilitzable per provar la mecànica d'aquesta lliçó, inutilitzable per treballar de debò.
$ sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients \
virtinst bridge-utils libguestfs-tools cloud-image-utils
$ systemctl is-active libvirtd
active
# El grup libvirt permet gestionar VM sense sudo.
# AVIS de seguretat: qui pot definir una VM pot muntar qualsevol disc
# de l amfitrio dins seu i llegir-lo. Pertanyer a aquest grup es
# equivalent a root a la practica. Es el mateix advertiment que caldra
# amb el grup docker a 07-05.
$ sudo usermod -aG libvirt operador
$ newgrp libvirt
$ virsh --connect qemu:///system version
Compiled against library: libvirt 10.0.0
Using library: libvirt 10.0.0
Using API: QEMU 10.0.0
Running hypervisor: QEMU 8.2.2Fixa't en qemu:///system davant de qemu:///session: el primer són màquines del sistema, gestionades pel dimoni com a root, amb accés a les xarxes i pools compartits. El segon són màquines de l'usuari, sense privilegis, amb xarxa limitada. Per a un servidor, sempre system, i convé fixar-ho per no haver-ho d'escriure:
I una comprovació important que tanca el cercle amb 07-01: en instal·lar libvirt apareix virbr0, la interfície de la xarxa NAT per defecte, i és exactament la que costava 35 segons d'arrencada perquè systemd-networkd-wait-online esperava que tingués enllaç:
$ ip -brief addr show virbr0
virbr0 DOWN 192.168.122.1/24
$ systemd-analyze | tail -1
Startup finished in 3.402s (kernel) + 9.118s (userspace) = 12.520sContinua en 12 segons perquè a l'exercici de 07-01 vas limitar systemd-networkd-wait-online a enp0s3 amb un drop-in. Sense aquell arranjament, instal·lar libvirt hauria tornat a afegir 35 segons a l'arrencada, i probablement ningú no hauria relacionat les dues coses.
virsh: gestionar màquines des de la línia d'ordres
virsh és l'eina principal. Les seves operacions essencials:
$ virsh list --all
Id Name State
--------------------
$ virsh net-list --all
Name State Autostart Persistent
------------------------------------------------
default active yes yes
$ virsh pool-list --all
Name State Autostart
-------------------------------
default active yes| Ordre | Què fa |
|---|---|
virsh list --all |
Totes les màquines definides, amb el seu estat |
virsh dominfo <vm> |
CPU, memòria, autoarrencada, seguretat |
virsh start <vm> |
Arrenca |
virsh shutdown <vm> |
Aturada ordenada: demana a l'hoste que s'apagui (ACPI) |
virsh destroy <vm> |
Tall de corrent: immediat i sense avisar l'hoste |
virsh reboot <vm> |
Reinici ordenat |
virsh autostart <vm> |
Arrenca en iniciar l'amfitrió |
virsh console <vm> |
Consola sèrie: la via quan no hi ha xarxa |
virsh edit <vm> |
Edita l'XML amb validació |
virsh dumpxml <vm> |
Aboca la definició |
virsh undefine <vm> |
Esborra la definició (no els discos, llevat de --remove-all-storage) |
virsh domifaddr <vm> |
Adreces IP de la màquina |
La distinció entre shutdown i destroy mereix èmfasi perquè el nom enganya: destroy no esborra res, és l'equivalent a estirar el cable. No destrueix la definició ni els discos, però sí que pot deixar el sistema de fitxers de l'hoste inconsistent. És la mateixa lògica del shutdown davant d'estirar el cable de 01-05, i l'ordre correcte és sempre intentar shutdown primer i esperar:
$ virsh shutdown srv-tramontana-proves
Domain 'srv-tramontana-proves' is being shutdown
$ for i in {1..30}; do
[[ "$(virsh domstate srv-tramontana-proves)" == "shut off" ]] && break
sleep 2
done
$ virsh domstate srv-tramontana-proves
shut offÉs exactament el patró SIGTERM → esperar → verificar → SIGKILL que vas aprendre a 03-06, aplicat a màquines senceres.
I virsh console és l'eina que fa practicable tot el de 07-01: dona accés a la consola sèrie de l'hoste, així que pots veure el menú de GRUB, entrar en mode emergència i recuperar un fstab trencat sense necessitat d'interfície gràfica. Se'n surt amb Ctrl+].
Crear una màquina amb virt-install
virt-install és la manera no interactiva de definir i arrencar una màquina. L'exemple complet, comentat línia a línia:
$ sudo virt-install \
--name srv-tramontana-proves \
--memory 2048 \
--vcpus 2 \
--cpu host-passthrough \
--disk path=/var/lib/libvirt/images/proves.qcow2,size=20,format=qcow2,bus=virtio \
--network network=default,model=virtio \
--os-variant ubuntu24.04 \
--graphics none \
--console pty,target_type=serial \
--location 'http://archive.ubuntu.com/ubuntu/dists/noble/main/installer-amd64/' \
--extra-args 'console=ttyS0,115200n8'| Opció | Per què aquell valor |
|---|---|
--cpu host-passthrough |
Exposa la CPU real a l'hoste, inclòs AES-NI — el pendent de 07-03 |
bus=virtio |
Controlador paravirtualitzat de disc: imprescindible per al rendiment |
model=virtio |
El mateix per a la xarxa |
--os-variant |
Permet a libvirt triar els valors òptims per a aquell sistema |
--graphics none |
Un servidor no necessita pantalla virtual |
--console pty,target_type=serial |
Consola sèrie, que és el que fa servir virsh console |
console=ttyS0,115200n8 |
Diu al nucli de l'hoste que parli pel port sèrie |
Els dos últims van junts i són la parella que fa que virsh console funcioni: sense console=ttyS0 a la línia d'ordres del nucli, l'hoste escriuria en una pantalla virtual que ningú no mira, i veuries una consola en blanc. És una fallada desconcertant i molt comuna.
Una instal·lació interactiva des de l'instal·lador d'Ubuntu triga vint minuts i cal respondre preguntes. Per a un entorn de proves que vols poder recrear, allò no serveix. L'alternativa és la secció següent.
Aprovisionament desatès amb cloud-init
Les distribucions publiquen imatges de núvol: discos ja instal·lats, amb cloud-init a dins, que es configuren sols en la primera arrencada a partir d'unes dades que els lliures.
$ cd /var/lib/libvirt/images
$ sudo wget -q https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
$ sudo qemu-img info noble-server-cloudimg-amd64.img
image: noble-server-cloudimg-amd64.img
file format: qcow2
virtual size: 3.5 GiB (3758096384 bytes)
disk size: 588 MiBFixa't en la diferència entre virtual size i disk size: 3,5 GiB declarats, 588 MiB ocupats. És l'aprovisionament fi de qcow2, que s'explica a l'apartat següent.
Les dades de configuració es lliuren en dos fitxers YAML:
$ mkdir -p ~/cloud-init && cd ~/cloud-init
$ cat > user-data <<'EOF'
#cloud-config
hostname: srv-tramontana-proves
fqdn: srv-tramontana-proves.tramontana.example
manage_etc_hosts: true
users:
- name: operador
groups: [sudo, adm]
shell: /bin/bash
sudo: 'ALL=(ALL) NOPASSWD:ALL'
lock_passwd: false
ssh_authorized_keys:
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... operador@portatil-alumne
# Coherent amb el que vas aprendre a 06-02: res de contrasenyes per SSH
ssh_pwauth: false
disable_root: true
package_update: true
package_upgrade: true
packages:
- postgresql-16
- restic
- ufw
- auditd
- libpam-pwquality
- sysstat
- linux-tools-generic
write_files:
- path: /etc/tramontana/app.conf
owner: root:root
permissions: '0640'
content: |
db_host=127.0.0.1
db_port=5432
db_name=tramontana_reserves
max_connexions=80
timeout_consulta=30
log_nivell=debug
escolta=127.0.0.1
- path: /etc/sysctl.d/70-rendiment.conf
owner: root:root
permissions: '0644'
content: |
# Copiat de produccio perque les proves siguin representatives
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
vm.swappiness = 10
vm.dirty_background_ratio = 5
vm.dirty_ratio = 10
runcmd:
- [ install, -d, -m, '0750', -o, root, -g, root, /opt/tramontana ]
- [ install, -d, -m, '2770', /srv/tramontana/backups ]
- [ sysctl, --system ]
- [ systemctl, enable, --now, sysstat ]
final_message: "srv-tramontana-proves llest despres de $UPTIME segons"
EOF
$ cat > network-config <<'EOF'
version: 2
ethernets:
enp1s0:
dhcp4: true
EOFEls dos fitxers s'empaqueten en una imatge ISO minúscula que la màquina llegeix com si fos un CD:
$ cloud-localds -N network-config llavor.iso user-data
$ ls -lh llavor.iso
-rw-rw-r-- 1 operador operador 366K ago 18 18:04 llavor.iso
$ sudo mv llavor.iso /var/lib/libvirt/images/I ara es crea la màquina, amb un detall important: la imatge descarregada no es fa servir directament, es crea un disc nou que la fa servir com a suport:
$ cd /var/lib/libvirt/images
# El disc de la VM te com a suport la imatge base, que queda intacta
$ sudo qemu-img create -f qcow2 -F qcow2 \
-b noble-server-cloudimg-amd64.img proves.qcow2 20G
Formatting 'proves.qcow2', fmt=qcow2 cluster_size=65536 ...
$ sudo virt-install \
--name srv-tramontana-proves \
--memory 2048 --vcpus 2 --cpu host-passthrough \
--disk path=/var/lib/libvirt/images/proves.qcow2,device=disk,bus=virtio \
--disk path=/var/lib/libvirt/images/llavor.iso,device=cdrom \
--network network=default,model=virtio \
--os-variant ubuntu24.04 \
--graphics none --console pty,target_type=serial \
--import --noautoconsole
Domain creation completed.
$ virsh list
Id Name State
---------------------------------------
1 srv-tramontana-proves running
$ sleep 60 && virsh domifaddr srv-tramontana-proves
Name MAC address Protocol Address
-------------------------------------------------------------------------------
vnet0 52:54:00:8a:c1:f2 ipv4 192.168.122.104/24
$ ssh [email protected] 'hostname; sysctl -n net.ipv4.tcp_congestion_control'
srv-tramontana-proves
bbrMenys de dos minuts, sense ni una sola pregunta, i amb la configuració de producció ja aplicada. I —això és el que fa valuós el mètode— el user-data és un fitxer de text que es versiona a git: la màquina de proves és reproduïble. És la mateixa idea d'infraestructura com a codi que veuràs amb Ansible a 07-06, en la seva forma més simple.
Emmagatzematge: formats, pools i instantànies
raw davant de qcow2
$ sudo qemu-img create -f raw prova.raw 10G
$ sudo qemu-img create -f qcow2 prova.qcow2 10G
$ ls -lh prova.raw prova.qcow2
-rw-r--r-- 1 root root 10G ago 18 18:12 prova.raw
-rw-r--r-- 1 root root 193K ago 18 18:12 prova.qcow2
$ du -h prova.raw prova.qcow2
0 prova.raw
196K prova.qcow2Fixa't en la diferència entre ls i du per a prova.raw: ls diu 10 GB, du diu 0. És un fitxer dispers (sparse), així que raw també fa aprovisionament fi en sistemes de fitxers que ho admeten. La diferència real entre els formats és en una altra banda:
raw |
qcow2 |
|
|---|---|---|
| Rendiment | El màxim possible | 95-98 % del de raw |
| Aprovisionament fi | Sí, amb fitxers dispersos | Sí, natiu |
| Instantànies internes | No | Sí |
| Discos de suport | No | Sí |
| Compressió i xifratge | No | Sí |
| Es pot muntar a l'amfitrió | Directament amb losetup |
Requereix qemu-nbd |
La decisió pràctica: qcow2 llevat que mesuris que el 2-5 % de rendiment importa. Les instantànies i els discos de suport valen molt més que aquell marge en un entorn de proves, i per a producció hi ha alternatives millors que totes dues (un volum LVM directe, que és el que fan servir molts hipervisors).
$ sudo qemu-img info proves.qcow2
image: proves.qcow2
file format: qcow2
virtual size: 20 GiB (21474836480 bytes)
disk size: 1.24 GiB
backing file: noble-server-cloudimg-amd64.img
backing file format: qcow2
# Ampliar un disc: primer el fitxer, DESPRES el sistema de fitxers de dins
$ sudo qemu-img resize proves.qcow2 +10G
Image resized.
# I dins de l hoste, amb el que vas aprendre a 05-04:
$ ssh [email protected] 'sudo growpart /dev/vda 1 && sudo resize2fs /dev/vda1'
# Convertir entre formats
$ sudo qemu-img convert -f qcow2 -O raw proves.qcow2 proves.rawEl disc de suport (backing file) és la peça que fa eficient un laboratori: la imatge base es comparteix i cada VM només guarda les seves diferències. Deu màquines de proves ocupen la base més deu petits fitxers de canvis, no deu sistemes complets. Amb una regla que cal respectar: si modifiques la imatge base, tots els discos que la tenen com a suport es corrompen. La base és de només lectura, a la pràctica.
# Aplanar un disc: incorporar el contingut de la base i trencar la dependencia
$ sudo qemu-img rebase -p -b "" proves.qcow2Pools d'emmagatzematge
libvirt organitza l'emmagatzematge en pools, que abstreuen on viuen els discos:
$ virsh pool-list --all --details
Name State Autostart Persistent Capacity Allocation Available
-------------------------------------------------------------------------------
default running yes yes 14.51 GiB 1.31 GiB 13.20 GiB
$ virsh pool-dumpxml default | grep -E '<path>|<type|name>'
<pool type='dir'>
<name>default</name>
<path>/var/lib/libvirt/images</path>
# Crear un pool al volum de dades, que te mes lloc
$ virsh pool-define-as proves dir --target /srv/tramontana/vm
$ virsh pool-build proves && virsh pool-start proves
$ virsh pool-autostart proves
$ virsh vol-list proves --detailsUn pool pot ser un directori, un grup de volums LVM, un dispositiu iSCSI, NFS o Ceph. El de tipus logical sobre LVM és interessant aquí: vg-dades ja existeix des de 05-04 i fer servir volums lògics directes com a discos evita la capa de fitxer.
Instantànies, i l'advertiment
$ virsh snapshot-create-as srv-tramontana-proves \
--name neta-24.04 \
--description "Acabada d aprovisionar per cloud-init, abans de proves" \
--atomic
Domain snapshot neta-24.04 created
$ virsh snapshot-list srv-tramontana-proves
Name Creation Time State
---------------------------------------------------
neta-24.04 2026-08-18 18:22:41 +0200 shutoff
# Trencar alguna cosa, provar, i tornar enrere
$ virsh snapshot-revert srv-tramontana-proves --snapshotname neta-24.04
$ virsh snapshot-delete srv-tramontana-proves --snapshotname neta-24.04I l'advertiment, amb el mateix pes que el de 05-04 sobre RAID:
Una instantània no és una còpia de seguretat. Viu al mateix fitxer (o al seu costat), al mateix disc, a la mateixa màquina. Si el disc falla, si el fitxer es corromp o si algú esborra el directori, se'n van la instantània i l'original junts. No compleix cap dels tres requisits de la regla 3-2-1 de 05-08.
El que una instantània sí que és: un punt de retorn ràpid per a una operació arriscada. Exactament el que necessites abans de provar un canvi de nucli. I té dos costos que cal conèixer: cada instantània activa degrada el rendiment d'escriptura, perquè cada bloc modificat exigeix copiar l'original primer; i acumular desenes d'instantànies encadenades pot fer el disc impossible de manejar.
Les instantànies amb la màquina en marxa (--live) capturen també la memòria i són molt més delicades: si l'aplicació té dades a mig escriure, l'estat restaurat pot ser inconsistent. L'opció --quiesce demana a l'agent de l'hoste que buidi els sistemes de fitxers abans, i requereix qemu-guest-agent instal·lat a dins. Per a un entorn de proves, apagar la màquina i fer la instantània en fred és més simple i més fiable.
Xarxa: NAT, aïllada i pont
Els tres modes, i quan cadascun:
| Mode | La VM veu | La xarxa veu la VM | Entre VM | Quan |
|---|---|---|---|---|
NAT (default) |
Internet, sí | No | Sí | Per defecte; laboratori |
| Aïllada | Res de fora | No | Sí | Proves sense sortida; programari maliciós |
| Pont | Tot | Sí, amb IP pròpia | Sí | Servidors que han de ser accessibles |
$ virsh net-dumpxml default
<network>
<name>default</name>
<forward mode='nat'/>
<bridge name='virbr0' stp='on' delay='0'/>
<ip address='192.168.122.1' netmask='255.255.255.0'>
<dhcp>
<range start='192.168.122.2' end='192.168.122.254'/>
</dhcp>
</ip>
</network>En NAT, libvirt munta un pont (virbr0), un servidor DHCP i DNS (dnsmasq) i les regles de traducció d'adreces. La VM surt a Internet amb la IP de l'amfitrió, i des de la xarxa ningú no pot iniciar una connexió cap a ella. Per a un entorn de proves és el correcte: aïllament per defecte sense configurar res.
I aquí convé tancar l'assumpte de virbr0 i l'arrencada, perquè ara es veu el mecanisme complet: la interfície existeix des que libvirt arrenca, però no té enllaç fins que una VM s'hi connecta. systemd-networkd-wait-online, en la seva configuració per defecte, esperava que totes les interfícies gestionades estiguessin en línia, i aquella no ho estaria mai amb les màquines apagades. D'aquí els 35 segons.
$ virsh net-define /dev/stdin <<'EOF'
<network>
<name>aillada</name>
<bridge name='virbr1' stp='on' delay='0'/>
<ip address='192.168.200.1' netmask='255.255.255.0'>
<dhcp><range start='192.168.200.10' end='192.168.200.100'/></dhcp>
</ip>
</network>
EOF
$ virsh net-start aillada && virsh net-autostart ailladaSense element <forward>, la xarxa no té sortida: les màquines es veuen entre si i amb l'amfitrió, i res més. És el que es fa servir per provar una configuració de tallafocs o analitzar alguna cosa sospitosa.
El pont és el mode que cal quan la VM ha de ser un servidor accessible. Requereix reconfigurar la xarxa de l'amfitrió amb netplan, aplicant 06-01 — i amb la mateixa cura, perquè et pot deixar sense accés a la màquina:
$ sudo cp -p /etc/netplan/50-cloud-init.yaml \
/etc/netplan/50-cloud-init.yaml.bak-$(date +%F)
$ sudo tee /etc/netplan/60-pont.yaml >/dev/null <<'EOF'
network:
version: 2
ethernets:
enp0s3:
dhcp4: false
dhcp6: false
bridges:
br0:
interfaces: [enp0s3]
addresses: [10.0.2.15/24]
routes:
- to: default
via: 10.0.2.2
nameservers:
addresses: [10.0.2.2, 1.1.1.1]
parameters:
stp: false
forward-delay: 0
EOF
$ sudo chmod 600 /etc/netplan/60-pont.yaml
# netplan try amb reversio automatica als 120 s: la xarxa de seguretat de 06-01
$ sudo netplan try
Do you want to keep these settings?
Press ENTER before the timeout to accept the new configurationAquell netplan try no és opcional. Configurar un pont per SSH és exactament el cas per al qual existeix: si el pont surt malament, perds la sessió, i la reversió automàtica als 120 segons et torna la màquina.
I un advertiment específic: el pont reassigna la IP de la interfície física al pont. Durant la transició hi ha un tall de xarxa d'uns segons, i si la configuració és incorrecta el tall és permanent. En un servidor remot sense consola, això es fa amb moltíssima cura.
Rendiment: virtio i configuració de CPU
virtio: la diferència entre lenta i ràpida
Els dispositius que QEMU presenta a l'hoste poden ser emulats (imita un dispositiu real, com una targeta Intel e1000) o paravirtualitzats (virtio: un dispositiu que no existeix al món real, dissenyat per parlar directament amb l'hipervisor).
La diferència és gran i mereix veure's mesurada:
| Dispositiu | Emulat | virtio |
|---|---|---|
| Disc | ~40 % del rendiment natiu | 95-98 % |
| Xarxa | ~1 Gbit/s amb molta CPU | 10 Gbit/s+ amb poca CPU |
$ virsh dumpxml srv-tramontana-proves | grep -A2 -E "<disk|<interface"
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2' cache='none' io='native' discard='unmap'/>
<source file='/var/lib/libvirt/images/proves.qcow2'/>
<target dev='vda' bus='virtio'/>
<interface type='network'>
<mac address='52:54:00:8a:c1:f2'/>
<source network='default'/>
<model type='virtio'/>Les pistes que virtio està actiu: el disc s'anomena vda (no sda) i el bus és virtio. Si veus sda amb bus sata, estàs fent servir emulació i perdent més de la meitat del rendiment de disc.
Els tres atributs del <driver> també importen:
| Atribut | Valor | Per què |
|---|---|---|
cache |
none |
Evita la doble memòria cau amfitrió/hoste; més segur davant de talls |
io |
native |
E/S asíncrona del nucli; millor amb cache=none |
discard |
unmap |
Propaga el TRIM de l'hoste: el fitxer qcow2 es redueix en esborrar |
discard=unmap és el que evita que un disc qcow2 creixi indefinidament: sense ell, esborrar dades dins de l'hoste no allibera espai a l'amfitrió.
Configuració de CPU
$ virsh dumpxml srv-tramontana-proves | grep -A3 '<cpu'
<cpu mode='host-passthrough' check='none' migratable='on'/>Els tres modes:
| Mode | Què exposa | Migració en viu |
|---|---|---|
host-passthrough |
La CPU real, totes les seves extensions | Només a amfitrions idèntics |
host-model |
Un model equivalent al de l'amfitrió | A amfitrions similars |
custom |
Un model concret que tries tu | A qualsevol amfitrió amb aquell model o superior |
I aquí es resol el pendent de 07-03, el d'AES-NI:
$ ssh [email protected] 'grep -o -m1 aes /proc/cpuinfo'
aes
$ ssh [email protected] 'openssl speed -evp aes-256-cbc 2>&1 | tail -2'
type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes
aes-256-cbc 1284412.10k 3841204.88k 4218844.12k 4402118.42k 4441204.88k4,4 GB/s de xifratge AES: allò només és possible amb acceleració per maquinari. Amb host-model en lloc de host-passthrough, o amb una CPU virtual genèrica, el mateix openssl speed donaria entre 200 i 600 MB/s, i aquí està el factor de cinc a deu que es plantejava com a hipòtesi a l'últim exercici de 07-03 per a la lentitud de la còpia xifrada.
La contrapartida de host-passthrough és la migració en viu: una màquina que veu les extensions exactes d'un processador no es pot migrar a un altre amfitrió que no les tingui, perquè l'hoste les està fent servir. Per a un entorn de proves en un únic amfitrió, host-passthrough és l'elecció correcta.
Dos ajustos més de memòria, esmentats per completesa:
$ virsh dumpxml srv-tramontana-proves | grep -A3 -E '<memballoon|<memoryBacking'
<memballoon model='virtio'>El ballooning permet a l'amfitrió recuperar memòria d'un hoste que no la fa servir, mitjançant un controlador dins de l'hoste que la «infla». És útil per a densitat, i contraproduent per a una base de dades, que reserva memòria compartida i no espera perdre-la. Les hugepages (<memoryBacking><hugepages/></memoryBacking>) redueixen les fallades de TLB de l'hoste, amb la mateixa lògica que les THP de 07-03, i són habituals en màquines grans de base de dades.
Clonar i crear srv-tramontana-proves
La màquina de cloud-init és neta i reproduïble, però per reproduir un problema de producció de vegades cal una còpia de l'estat real. virt-clone la fa:
# La maquina origen ha d estar APAGADA
$ virsh shutdown srv-tramontana-proves
$ virt-clone --original srv-tramontana-proves \
--name srv-tramontana-proves-2 \
--auto-clone
Allocating 'proves-2.qcow2' | 20 GB 00:00:04
Clone 'srv-tramontana-proves-2' created successfully.virt-clone copia els discos i genera adreces MAC i UUID nous, que és el que evita el conflicte que produeix copiar el fitxer a mà. Però deixa intacte l'interior de l'hoste: mateix nom de màquina, mateixes claus d'amfitrió d'SSH, mateix machine-id. I això dona problemes reals:
$ sudo virt-sysprep -d srv-tramontana-proves-2 \
--hostname proves-2 \
--operations defaults,-ssh-userdir
[ 0.0] Examining the guest ...
[ 4.2] Performing "abrt-data" ...
[ 4.2] Performing "bash-history" ...
[ 4.3] Performing "machine-id" ...
[ 4.4] Performing "ssh-hostkeys" ...
[ 4.5] Performing "logfiles" ...
[ 4.8] Setting a random seed
[ 4.9] Setting the machine ID in /etc/machine-id
[ 5.0] Setting the hostname: proves-2virt-sysprep neteja el que fa única una màquina: machine-id —que systemd i el journal fan servir com a identificador—, claus d'amfitrió d'SSH, registres, historial de shell, i configuració de xarxa associada a la MAC anterior. Sense aquest pas, dues màquines amb el mateix machine-id produeixen entrades de journal barrejades si es centralitzen, i dues amb les mateixes claus d'amfitrió provoquen l'avís d'empremta canviada de 06-02.
I libguestfs permet a més treballar amb el disc d'una màquina apagada sense arrencar-la, cosa que resol l'escenari de 07-01 sense necessitat d'un mitjà de rescat:
# Inspeccionar un disc sense arrencar la maquina
$ sudo virt-ls -d srv-tramontana-proves /etc/tramontana/
app.conf
# Llegir un fitxer
$ sudo virt-cat -d srv-tramontana-proves /etc/fstab
# I ARREGLAR un fstab trencat sense arrencar ni fer servir un Live CD
$ sudo guestfish -d srv-tramontana-proves -i edit /etc/fstabAixò és el que converteix la recuperació de 07-01 en una operació de dos minuts quan la màquina és virtual: en lloc d'arrencar des d'un ISO, muntar i fer chroot, s'edita el fitxer directament al disc apagat.
L'entorn de proves, i per a què serveix
Amb srv-tramontana-proves en marxa, els quatre deutes del principi de la lliçó es poden liquidar:
# 1. El release 3.3.0 que no arrencava (deute del Modul 4)
$ virsh snapshot-create-as srv-tramontana-proves --name abans-de-3.3.0 --atomic
$ scp /srv/tramontana/backups/enviaments/tramontana-3.3.0.tar.gz \
[email protected]:/tmp/
$ ssh [email protected] \
'sudo ~/scripts/desplegar.sh 3.3.0; sudo journalctl -u tramontana -n 40'
# I amb el registre complet al davant, per fi es pot diagnosticar
# 2. El planificador d E/S (exercici 3 de 07-03), sense degradar produccio
$ ssh [email protected] \
'sync; echo 3 | sudo tee /proc/sys/vm/drop_caches; \
echo mq-deadline | sudo tee /sys/block/vda/queue/scheduler'
# 3. La recuperacio de l arrencada de 07-01, amb virsh console
$ virsh console srv-tramontana-proves
# (Ctrl+] per sortir)
# 4. I AES-NI, ja comprovat
$ ssh [email protected] 'grep -c -m1 aes /proc/cpuinfo'
1
# Tornar al punt de partida quan s acabi
$ virsh snapshot-revert srv-tramontana-proves --snapshotname abans-de-3.3.0Sobre la migració en viu, per tancar: libvirt permet moure una màquina en execució d'un amfitrió a un altre sense interrompre-la, copiant la memòria en diverses passades fins que en queda tan poca per transferir que es pot pausar uns mil·lisegons i completar el canvi.
Requereix emmagatzematge compartit (o --copy-storage-all, molt més lent) i CPU compatibles —d'aquí la contrapartida de host-passthrough—. És la base del manteniment sense talls: es buiden els amfitrions un a un per actualitzar-los. I és un avançament de 07-07: moure una màquina no és el mateix que tenir alta disponibilitat, perquè la migració requereix que l'amfitrió origen continuï funcionant. Davant d'una fallada sobtada, no serveix.
Eines gràfiques i de més alt nivell, esmentades: virt-manager és la interfície gràfica de libvirt, còmoda per explorar i per accedir a la consola d'una màquina amb entorn gràfic; Vagrant defineix màquines de desenvolupament en un Vagrantfile versionable i funciona sobre libvirt, VirtualBox o VMware, i és l'eina indicada quan un equip sencer necessita entorns idèntics; i Terraform i OpenStack operen a escala d'infraestructura, parlant també amb libvirt per sota.
Errors Comuns i Consells
- No activar la virtualització imbricada.
kvm-okdiuKVM is disabled by your BIOSi tot funciona per emulació, deu vegades més lent. A VirtualBox,VBoxManage modifyvm <vm> --nested-hw-virt onamb la màquina apagada. - Oblidar
console=ttyS0a la línia d'ordres del nucli.virsh consolemostra una pantalla en blanc i sembla que la màquina no arrenca. Va aparellat amb--console pty,target_type=serial. - Fer servir dispositius emulats en lloc de
virtio. Si el disc de l'hoste s'anomenasdai novda, estàs perdent més de la meitat del rendiment de disc. Comprovabus='virtio'a l'XML. - Confondre
destroyamb esborrar.virsh destroyés estirar el cable: no esborra res, però pot deixar el sistema de fitxers de l'hoste inconsistent. Fes servirshutdowni espera. - Modificar una imatge base que té discos que la fan servir de suport. Corromp tots els discos derivats. La base és de només lectura a la pràctica; fes servir
qemu-img rebasesi necessites independitzar-ne un. - Confiar en una instantània com a còpia de seguretat. Viu al mateix disc i a la mateixa màquina. No compleix cap dels tres requisits de la regla 3-2-1.
- Acumular instantànies encadenades. Cadascuna activa degrada l'escriptura, i una cadena llarga fa el disc impossible de manejar. Consolida o esborra.
- Clonar sense
virt-sysprep. Dues màquines amb el mateixmachine-idi les mateixes claus d'amfitrió d'SSH provoquen journals barrejats i avisos d'empremta canviada. - Configurar un pont per SSH sense
netplan try. Un pont mal definit et deixa fora de la màquina de forma permanent. La reversió automàtica als 120 segons existeix exactament per a això. - Ometre
discard=unmap. El fitxerqcow2creix indefinidament perquè esborrar dins de l'hoste no allibera espai a l'amfitrió. - Activar ballooning en una màquina de base de dades. La base de dades reserva memòria compartida i no espera que se li tregui. Provoca degradació difícil de diagnosticar.
- Consell de mètode. Versiona el
user-datade cloud-init a git juntament amb els scripts. Una màquina de proves que es recrea amb una ordre en dos minuts es fa servir; una que cal reinstal·lar a mà s'abandona així que es desconfigura.
Exercicis
Exercici 1
Dissenya el user-data de cloud-init per a una màquina srv-tramontana-proves que reprodueixi la configuració de seguretat de producció el més fidelment possible, i explica què no es pot reproduir i per què. Justifica cada decisió.
Exercici 2
El release 3.3.0 no arrenca. Dissenya el procediment complet per diagnosticar-lo a l'entorn de proves, fent servir el que has après a 07-01, 07-02 i aquesta lliçó, de manera que puguis repetir l'intent tantes vegades com calgui.
Exercici 3
La Marta pregunta si convé moure Tramontana Reserves a màquines virtuals gestionades per KVM en un servidor propi, en lloc del VPS actual. Redacta l'anàlisi: què s'hi guanya, què s'hi perd, i què recomanes.
Solucions
Solució 1
#cloud-config
# user-data per a srv-tramontana-proves
# Objectiu: reproduir produccio prou perque les proves siguin valides,
# SENSE copiar res que sigui un secret real.
hostname: srv-tramontana-proves
fqdn: srv-tramontana-proves.tramontana.example
manage_etc_hosts: true
# --- Identitats: mateixos uid/gid que produccio ---
# Motiu: els permisos, ACL i SGID nomes son representatius si els
# identificadors numerics coincideixen. Un 2770 sobre el gid 1002 nomes es
# comporta igual si el grup tramontana ES el 1002.
groups:
- tramontana: [operador]
users:
- name: operador
uid: 1000
groups: [sudo, adm, tramontana]
shell: /bin/bash
lock_passwd: false
sudo: 'ALL=(ALL) NOPASSWD:ALL'
ssh_authorized_keys:
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... operador@portatil-alumne
- name: luis
uid: 1001
groups: [tramontana]
shell: /bin/bash
lock_passwd: true
- name: svc-tramontana
uid: 997
system: true
shell: /usr/sbin/nologin
homedir: /opt/tramontana
create_groups: false
no_create_home: true
ssh_pwauth: false
disable_root: true
# --- Paquets: els mateixos que produccio, mes els de diagnostic ---
package_update: true
package_upgrade: true
packages:
- postgresql-16
- restic
- ufw
- fail2ban
- auditd
- aide
- apparmor-utils
- libpam-pwquality
- needrestart
- sysstat
# Eines de diagnostic: en proves SI, en produccio no calen
- linux-tools-generic
- strace
- bpfcc-tools
- bpftrace
- qemu-guest-agent
write_files:
# Configuracio de l aplicacio, amb log_nivell=debug (unica diferencia)
- path: /etc/tramontana/app.conf
owner: root:tramontana
permissions: '0640'
content: |
db_host=127.0.0.1
db_port=5432
db_name=tramontana_reserves
max_connexions=80
timeout_consulta=30
log_nivell=debug
escolta=127.0.0.1
# sysctl de rendiment: identic a produccio. Sense aixo, qualsevol
# mesura comparativa seria invalida.
- path: /etc/sysctl.d/70-rendiment.conf
owner: root:root
permissions: '0644'
content: |
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
vm.swappiness = 10
vm.dirty_background_ratio = 5
vm.dirty_ratio = 10
fs.inotify.max_user_watches = 524288
# sysctl de seguretat: identic, INCLOS ptrace_scope.
# Decisio deliberada: si en proves relaxem ptrace_scope, no
# reproduiriem l "Operation not permitted" de 07-02, i les proves
# de diagnostic no serien representatives.
- path: /etc/sysctl.d/60-enfortiment.conf
owner: root:root
permissions: '0644'
content: |
kernel.dmesg_restrict = 1
kernel.kptr_restrict = 2
kernel.randomize_va_space = 2
fs.protected_hardlinks = 1
fs.protected_symlinks = 1
fs.protected_fifos = 2
fs.protected_regular = 2
kernel.unprivileged_bpf_disabled = 1
kernel.yama.ptrace_scope = 1
- path: /etc/modprobe.d/blacklist-tramontana.conf
owner: root:root
permissions: '0644'
content: |
install cramfs /bin/true
install freevxfs /bin/true
install jffs2 /bin/true
install udf /bin/true
install dccp /bin/true
install sctp /bin/true
# Dades de prova SINTETIQUES, generades, mai copiades de produccio
- path: /home/operador/dades/cases.txt
owner: operador:operador
permissions: '0640'
content: |
mas-figueres
can-ventos
la-solana
cal-ferrer
el-moli
runcmd:
# Rutes amb els mateixos permisos i SGID que produccio
- [ install, -d, -m, '0755', -o, root, -g, root, /opt/tramontana ]
- [ install, -d, -m, '2770', -o, svc-tramontana, -g, tramontana,
/opt/tramontana/shared/uploads ]
- [ install, -d, -m, '0750', -o, svc-tramontana, -g, adm,
/var/log/tramontana ]
- [ install, -d, -m, '2770', -o, operador, -g, tramontana,
/srv/tramontana/backups ]
# Tallafocs amb la mateixa politica de llista blanca
- [ ufw, --force, default, deny, incoming ]
- [ ufw, --force, default, allow, outgoing ]
- [ ufw, limit, '22/tcp' ]
- [ ufw, allow, from, 192.168.122.0/24, to, any, port, '5432', proto, tcp ]
- [ ufw, --force, enable ]
# Aplicar i activar
- [ sysctl, --system ]
- [ update-initramfs, -u, -k, all ]
- [ systemctl, enable, --now, sysstat ]
- [ systemctl, enable, --now, qemu-guest-agent ]
# Generar reserves.csv sintetiques amb la mateixa estructura
- [ bash, -c, 'printf "id;data;casa;hoste;nits;import\n" > /home/operador/dades/reserves.csv' ]
- [ bash, -c, 'for i in $(seq 1001 1025); do printf "%s;2026-08-%02d;mas-figueres;Hoste %s;2;250,00\n" "$i" "$((i-1000))" "$i"; done >> /home/operador/dades/reserves.csv' ]
- [ chown, 'operador:operador', /home/operador/dades/reserves.csv ]
final_message: "srv-tramontana-proves llest despres de $UPTIME segons"Què NO es pot reproduir, i per què. Aquesta és la part important de l'exercici, perquè determina quines proves són vàlides:
| No reproduïble | Per què | Conseqüència per a les proves |
|---|---|---|
Els secrets reals (db_password, contrasenya de restic, clau GPG de pass) |
Copiar-los multiplicaria per dos la seva exposició i violaria la regla de 06-05 | Les proves fan servir credencials pròpies. No es pot provar la rotació real |
El fitxer .cred de systemd-creds |
Està xifrat amb una clau derivada de la màquina de producció; és indesxifrable aquí | Cal generar-ne un de nou. És la limitació que ja es va documentar a 06-05 |
| El certificat de Let's Encrypt | Requereix el domini públic i el desafiament ACME. A més, cada emissió consumeix quota | Se'n fa servir un d'autosignat. No es pot provar la renovació real |
| Les dades personals d'hostes | RGPD: un entorn de proves té menys controls, més accessos i més còpies. Copiar-les seria una infracció | Dades sintètiques amb la mateixa estructura i volum |
| El volum LUKS amb la seva clau | La clau és un secret i el disc és físic | Es pot crear un LUKS nou amb clau de proves. Vàlid per mesurar rendiment, no per restaurar còpies reals |
| La base de dades d'AIDE | Depèn de les sumes dels fitxers reals d'aquesta màquina | S'inicialitza aquí. Vàlid per provar el mecanisme, no per comparar amb producció |
| El maquinari exacte | És una VM imbricada, amb dues capes d'hipervisor | Les mesures absolutes de rendiment no són comparables; només les relatives abans/després dins de la mateixa màquina |
I les tres decisions que convé justificar perquè són contraintuïtives:
- Mantenir
ptrace_scope = 1en proves. La temptació és relaxar-lo per diagnosticar còmodament. Seria un error: aleshores no reproduiríem l'Operation not permittedde 07-02 i les proves de diagnòstic no valdrien. Un entorn de proves que difereix en seguretat no prova la seguretat. - Mateixos UID i GID numèrics. És fàcil deixar que cloud-init assigni els que vulgui, i aleshores el
2770sobre el gruptramontanano es comporta igual, i les proves de permisos són invàlides. Els identificadors numèrics són part de la configuració. log_nivell=debugcom a única diferència intencionada, més les eines de diagnòstic. Totes dues coses són més del que hi ha en producció, no menys, així que no invaliden res — i cal anotar-les, perquè el volum de registres sí que difereix.
L'últim advertiment va al manual d'operació: aquest user-data conté la clau pública d'SSH i els identificadors de l'organització, així que es versiona al repositori intern, no en un de públic. I mai no ha de contenir un secret real: per a això hi ha pass i l'aprovisionament posterior.
Solució 2
La clau del disseny és que el diagnòstic ha de ser repetible: cada intent parteix del mateix estat, perquè les diferències observades es deguin al canvi i no a residus de l'intent anterior.
# --- Fase 0: punt de retorn net i repetible ---
$ virsh shutdown srv-tramontana-proves
$ for i in {1..30}; do
[[ "$(virsh domstate srv-tramontana-proves)" == "shut off" ]] && break
sleep 2
done
$ virsh snapshot-create-as srv-tramontana-proves \
--name base-3.2.1 \
--description "3.2.1 activa i verificada, abans d intentar 3.3.0" \
--atomic
$ virsh start srv-tramontana-provesLa instantània en fred és deliberada: una --live capturaria la memòria i, sense --quiesce, podria deixar PostgreSQL inconsistent. Per a un punt de retorn, apagada és més simple i més fiable.
# --- Fase 1: verificar l estat de partida ---
$ VM=192.168.122.104
$ ssh operador@$VM '~/scripts/revisio_salut.sh; echo "estat: $?"'
estat: 0
$ ssh operador@$VM 'readlink /opt/tramontana/app'
releases/3.2.1Sense aquesta verificació, una fallada de 3.3.0 es podria confondre amb un entorn de proves que ja estava trencat.
# --- Fase 2: preparar l observacio ABANS de provocar la fallada ---
# L error pot durar mil·lisegons: cal estar mirant quan passi.
$ ssh operador@$VM 'sudo journalctl -f -u tramontana' > /tmp/journal-3.3.0.log &
$ ssh operador@$VM 'sudo execsnoop-bpfcc -T' > /tmp/processos-3.3.0.log &
$ ssh operador@$VM 'sudo journalctl -f -k | grep -i apparmor' > /tmp/apparmor.log &execsnoop-bpfcc és l'elecció informada aquí: si el binari arrenca i mor en 200 ms, ps no el veurà mai, i aquesta eina captura cada execve amb el seu codi de sortida. És exactament el cas d'ús de la taula de 07-02.
# --- Fase 3: l intent, amb el mode de simulacio primer ---
$ scp /srv/tramontana/backups/enviaments/tramontana-3.3.0.tar.gz \
/srv/tramontana/backups/enviaments/tramontana-3.3.0.tar.gz.sha256 \
operador@$VM:/tmp/
$ ssh operador@$VM 'cd /tmp && sha256sum -c tramontana-3.3.0.tar.gz.sha256'
tramontana-3.3.0.tar.gz: OK
# --dry-run primer: convencio del curs, i descarta problemes de l script
$ ssh operador@$VM 'sudo ~/scripts/desplegar.sh --dry-run 3.3.0'
$ ssh operador@$VM 'sudo ~/scripts/desplegar.sh 3.3.0'# --- Fase 4: recollir l evidencia, del general a l especific ---
# 4a. El journal. La causa hi es el 70% de les vegades.
$ ssh operador@$VM 'sudo journalctl -u tramontana -n 60 --no-pager -o short-precise'
# 4b. Com va morir? El codi de sortida i el senyal ho diuen tot.
$ ssh operador@$VM 'systemctl show tramontana -p ExecMainStatus -p ExecMainCode \
-p Result -p StatusErrno'I aquí està l'arbre de decisió que fa útil aquest procediment, perquè cada símptoma té una eina diferent:
| Evidència | Hipòtesi | Eina que la confirma |
|---|---|---|
signal=SYS |
Filtre seccomp de SystemCallFilter |
ausyscall <n> sobre el syscall= del journal |
apparmor="DENIED" |
El perfil d'AppArmor no contempla una ruta nova | journalctl -k | grep DENIED |
status=127 o not found |
Falta una biblioteca compartida | ldd sobre el binari nou |
status=1 amb missatge propi |
Configuració: falta una clau a app.conf |
strace -e trace=%file | grep ENOENT |
Killed / oom-kill |
Excedeix MemoryMax=512M |
journalctl -k | grep -i oom |
| Arrenca i mor sense missatge | Qualsevol de les anteriors, silenciada | execsnoop + strace -f des de l'arrencada |
# 4c. Biblioteques: la causa mes comuna d un binari nou que no arrenca
$ ssh operador@$VM 'ldd /opt/tramontana/releases/3.3.0/tramontana | grep -i "not found"'
libpq.so.6 => not found
# I si apareix, la confirmacio i la causa arrel
$ ssh operador@$VM 'apt-cache policy libpq5; dpkg -l | grep libpq'# 4d. Si el journal no diu res util: tracar l arrencada des del principi
$ ssh operador@$VM 'sudo -u svc-tramontana strace -f -o /tmp/traca.txt \
/opt/tramontana/releases/3.3.0/tramontana --config /etc/tramontana/app.conf; \
grep -E "ENOENT|EACCES|EPERM" /tmp/traca.txt | grep -v "lib\|locale" | tail -20'
# 4e. Comparar 3.2.1 amb 3.3.0: que ha canviat de debo
$ ssh operador@$VM 'diff <(ldd /opt/tramontana/releases/3.2.1/tramontana | sort) \
<(ldd /opt/tramontana/releases/3.3.0/tramontana | sort)'
$ ssh operador@$VM 'sudo systemd-analyze security tramontana.service | tail -1'El pas 4e és el que més rendiment dona i el que se sol oblidar: comparar la versió que funciona amb la que no. Si l'única diferència és una biblioteca nova, ja tens la resposta sense traçar res.
# --- Fase 5: tornar al punt de partida i repetir ---
$ kill %1 %2 %3 2>/dev/null # tancar els observadors
$ virsh shutdown srv-tramontana-proves
$ virsh snapshot-revert srv-tramontana-proves --snapshotname base-3.2.1
$ virsh start srv-tramontana-proves
$ ssh operador@$VM '~/scripts/revisio_salut.sh; echo "estat: $?"'
estat: 0Tres decisions de disseny que justifiquen el procediment:
- Els observadors es llancen abans de l'intent. Un binari que mor en 200 ms no es pot observar a posteriori. És la diferència entre tenir l'evidència i haver de repetir.
- L'arbre de decisió està escrit abans de començar. Sota pressió, la temptació és llançar
stracea tot i ofegar-se en sortida. Amb la taula al davant, cada símptoma porta a una eina concreta. - La instantània permet intents il·limitats. I aquella és la raó de ser de la lliçó: aquest diagnòstic no es pot fer en producció. Cada intent fallit deixa un release a mig desplegar, un servei caigut i una reversió. En proves,
snapshot-reverti una altra vegada.
Nota final: quan es trobi la causa, la correcció s'aplica i es prova en proves fins que revisio_salut.sh retorni 0, i només aleshores es desplega en producció. Que desplegar.sh tingués reversió automàtica des de 04-07 va evitar el desastre en el seu moment; tenir on diagnosticar és el que permet arreglar-ho.
Solució 3
Anàlisi: migrar Tramontana Reserves a virtualització pròpia amb KVM Per a: Marta Vidal · De: Operacions de sistemes · 18 d'agost de 2026
Recomanació breu: no ara. Mantenir el VPS i fer servir KVM únicament per a l'entorn de proves, que és on el benefici és immediat i el risc nul. En detallo el raonament.
Què hi guanyaríem
- Control complet de la pila. Podríem ajustar la CPU de la màquina (
host-passthrough), la configuració de discos i el planificador d'E/S. Recorda que a les proves de rendiment d'aquesta setmana no vam poder determinar si el xifratge de les còpies anava accelerat per maquinari, precisament perquè no controlem aquella capa.- Aïllament fort entre serveis. Podríem separar la base de dades de l'aplicació en màquines diferents, amb una frontera de seguretat real entre elles. Avui comparteixen sistema operatiu: un compromís de l'aplicació arriba directament a la base de dades.
- Instantànies abans de cada canvi. Un punt de retorn de segons, en lloc de dependre de la restauració de còpies amb el seu RTO de 8 hores.
- Cost predictible a partir de cert volum. Un servidor propi amb capacitat per a diverses màquines pot sortir més barat que quatre o cinc VPS.
- Sense dependència del proveïdor quant a versions de nucli, característiques disponibles o canvis de preu.
Què hi perdríem, i això és el determinant
- El maquinari passa a ser problema nostre. Discos, fonts, memòria, ventiladors. Un disc que falla a les tres de la matinada avui el resol el proveïdor; amb servidor propi el resolem nosaltres, i necessitaríem discos en RAID —recordant que RAID no és una còpia de seguretat— i recanvis.
- L'energia, la refrigeració i la xarxa deixen d'estar garantides. Un servidor en una oficina depèn d'un sol circuit elèctric i d'una sola línia de dades. Un tall de llum de dues hores és una caiguda de dues hores. Un allotjament amb SAI redundant i doble escomesa costa diners.
- Un únic punt de fallada, i un de nou: l'amfitrió. Avui tenim un servidor que pot fallar. Amb virtualització pròpia tindríem les màquines virtuals més l'amfitrió, i si l'amfitrió cau, cauen totes alhora. Això és important: la virtualització no dona alta disponibilitat, i creure el contrari és l'error de disseny més comú de l'àrea. Amb un sol amfitrió, el risc de caiguda total augmenta.
- Augmenta la càrrega de treball, no disminueix. Avui administrem un sistema operatiu. Amb virtualització pròpia administraríem l'amfitrió, l'hipervisor, la xarxa virtual, l'emmagatzematge i cada màquina hoste. Amb la plantilla actual, això és temps que surt d'un altre lloc.
- Cost inicial real. Servidor amb capacitat i redundància de discos, més allotjament adequat, més els recanvis. No és menyspreable, i cal comparar-ho amb el cost anual del VPS a diversos anys, no a un.
- Implicacions de compliment. Tractem dades personals d'hostes. Un servidor propi ens converteix en responsables de la seguretat física de l'equip, que avui és del proveïdor i que al nostre model d'amenaces figura explícitament com a fora d'abast. Allò s'hauria de revisar amb el responsable de protecció de dades, i probablement exigiria xifratge complet del disc arrel i control d'accés a l'espai físic.
El que sí que proposo, i ja està en marxa
Fer servir KVM per a l'entorn de proves, a la mateixa màquina d'administració o al VPS actual. El benefici és immediat i el risc, cap:
- Aquesta setmana ha permès, per primera vegada, poder diagnosticar el release 3.3.0 que va fallar al juliol i que va quedar sense explicació.
- Permet provar canvis de configuració i actualitzacions de nucli abans d'aplicar-los en producció.
- Permet assajar el procediment de recuperació del manual d'operació sense tocar el servidor real.
- Es recrea de zero en dos minuts amb un fitxer de configuració versionat a git.
Quan reconsiderar-ho. L'anàlisi canvia si es donen almenys dues d'aquestes condicions:
Condició Per què canvia la decisió Necessitem quatre o més servidors El cost per màquina del servidor propi baixa molt Hi ha pressupost per a dos amfitrions Només aleshores la virtualització aporta disponibilitat, no la resta Hi ha allotjament professional disponible Resol energia, refrigeració i xarxa Hi ha una persona dedicada a infraestructura La càrrega de treball deixa de sortir d'un altre lloc El cost del VPS supera clarament l'alternativa a tres anys És quan la inversió s'amortitza de debò I una alternativa intermèdia que mereix considerar-se abans. Si l'objectiu real és separar la base de dades de l'aplicació per seguretat, o tenir un entorn de preproducció permanent, contractar un segon VPS aconsegueix això mateix per una fracció del cost i sense assumir la responsabilitat del maquinari. És un pas reversible; comprar un servidor no ho és.
Resum per decidir. La virtualització pròpia és la resposta correcta quan el problema és escala i hi ha recursos per fer-la bé. El nostre problema avui no és l'escala: és que no teníem entorn de proves —resolt— i que tenim un únic punt de fallada, que és un problema de redundància i no de virtualització. Aquell segon assumpte l'estic estudiant i et portaré una proposta amb números.
Conclusió
Ja tens l'entorn de proves que el curs feia quatre mòduls que trobava a faltar, i entens la pila que el sosté. Saps què virtualitza cada peça: KVM dona accés a les extensions de la CPU, QEMU emula els dispositius, libvirt gestiona el conjunt amb una API estable, i virsh és l'eina del dia a dia. Saps que destroy és estirar el cable i no esborrar, que virsh console és la via per recuperar una arrencada trencada sense interfície gràfica, i que virtio al disc i a la xarxa és la diferència entre una màquina lenta i una de ràpida. Aprovisiones sense intervenció amb cloud-init a partir d'un fitxer versionat a git, tries qcow2 per les seves instantànies i els seus discos de suport sabent el que costa aquell 2-5 % de rendiment, i tens clar que una instantània no és una còpia de seguretat.
I de passada has tancat tres assumptes pendents. El virbr0 que costava 35 segons d'arrencada a 07-01 té ara una explicació completa: una interfície que existeix però no té enllaç fins que arrenca una màquina. El dubte de 07-03 sobre AES-NI està resolt: amb host-passthrough, l'hoste veu les extensions de la CPU i xifra a 4,4 GB/s, cosa que confirma el factor de cinc a deu que es plantejava com a hipòtesi. I el release 3.3.0 que va fallar al Mòdul 4 té per fi un lloc on reproduir-se tantes vegades com calgui, amb una instantània com a punt de retorn i un arbre de decisió escrit abans de començar.
Fixa't ara en el preu que has pagat per l'aïllament fort de les màquines virtuals. Cada VM porta el seu propi nucli, triga mig minut a arrencar, ocupa gigabytes al disc i reserva centenars de megabytes de memòria només per existir. Per a un entorn de proves allò és perfectament raonable. Per desplegar una aplicació i la seva base de dades, i poder-les recrear en segons, és caríssim. I al diagrama del tercer apartat ja vas veure l'alternativa: compartir el nucli de l'amfitrió i aïllar només l'imprescindible.
A la lliçó 07-05: Contenidors de Linux i Docker es construeix això, i comença per la idea que cal tenir clara abans d'escriure el primer docker run: un contenidor no és una màquina petita, és un procés aïllat. Veuràs les tres primitives del nucli que ho fan possible —els namespaces, que aïllen el que un procés veu; els cgroups v2, que són literalment la mateixa tecnologia del MemoryMax=512M que vas posar a 05-05; i les capabilities de 05-02—, i reconeixeràs als namespaces de muntatge el chroot amb què vas reparar GRUB a 07-01. Després arriba Docker: imatges i capes, un Dockerfile amb construcció en diverses etapes per no enviar el compilador a producció, volums davant de bind mounts, xarxes amb resolució per nom, i un compose.yaml que aixeca l'aplicació i PostgreSQL junts amb comprovacions de salut. Amb dos advertiments que la lliçó es pren seriosament: pertànyer al grup docker equival a la pràctica a tenir root, i aquell kernel.unprivileged_userns_clone que vas deixar comentat a 06-06 amb una nota explicant per què — ha arribat el moment d'entendre-la del tot.
Curs de Linux: De Principiant a Administrador de Sistemes
Mòdul 1: Introducció a Linux
- Què és Linux?
- Història de Linux
- Distribucions de Linux
- Instal·lant Linux
- Primer Contacte amb el Sistema
- Estructura del Sistema de Fitxers de Linux
Mòdul 2: Comandes Bàsiques de Linux
- Introducció a la Línia de Comandes
- Obtenir Ajuda i Documentació del Sistema
- Navegant pel Sistema de Fitxers
- Operacions amb Fitxers i Directoris
- Visualització i Edició de Fitxers
- Enllaços Durs i Simbòlics
- Permisos i Propietat dels Fitxers
Mòdul 3: Habilitats Avançades en la Línia de Comandes
- L'Entorn del Shell: Variables, Àlies i Historial
- Ús de Comodins i Expressions Regulars
- Cerca de Fitxers i Contingut: find, locate i grep
- Canonades i Redirecció
- Processament de Text: cut, sort, uniq, sed i awk
- Gestió de Processos
- Programació de Tasques amb Cron
- Comandes de Xarxa
Mòdul 4: Scripting en Shell
- Introducció al Scripting en Shell
- Variables i Tipus de Dades
- Entrada, Sortida i Arguments d'un Script
- Estructures de Control
- Funcions i Biblioteques
- Depuració i Gestió d'Errors
- Scripts de Producció: Bones Pràctiques
Mòdul 5: Administració del Sistema
- Gestió d'Usuaris i Grups
- sudo i Permisos Especials
- Gestió de Paquets
- Gestió de Discs
- systemd i la Gestió de Serveis
- Registres del Sistema: journald i syslog
- Monitoratge del Sistema i Optimització del Rendiment
- Còpies de Seguretat i Restauració
Mòdul 6: Xarxes i Seguretat
- Configuració de Xarxes
- SSH i Accés Remot
- Tallafocs i Seguretat Perimetral
- Sistemes de Detecció d'Intrusions
- Gestió de Secrets i Certificats TLS
- Assegurant Sistemes Linux
Mòdul 7: Temes Avançats
- El Procés d'Arrencada i la Recuperació del Sistema
- Diagnòstic Avançat: strace, perf i eBPF
- Optimització del Nucli de Linux
- Virtualització amb Linux
- Contenidors de Linux i Docker
- Automatització amb Ansible
- Alta Disponibilitat i Balanceig de Càrrega
