Introducción

Buenas, en este post vamos a hacer una serie de ejercicios con libvirt, los cuáles al final del proceso migraremos una aplicación entre dos máquinas virtuales.

Ejercicio 1

Crea con virt-install una imagen de Debian Buster con formato qcow2 y un tamaño máximo de 3GiB. Esta imagen se denominará buster-base,qcow2. El sistema de ficheros del sistema instalado en esta imagen será XFS. La imagen debe estar configurada para poder usar hasta dos interfaces de red por dhcp. El usuario debian con contraseña debian puede utilizar sudo sin contraseña.

Creamos la imagen con los parámetros deseados:

virt-install --connect qemu:///system \
--cdrom ~/debian-10.6.0-amd64-netinst.iso \
--disk size=3 \
--network bridge=virbr0 \
--name buster-base \
--memory 1024 \
--vcpus 1

Comenzará la instalación:

1

Ponemos el sistema de ficheros XFS:

2

Y una vez seguidos los pasos básicos de una instalación que obviamente no vamos a poner, comprobarmos que se ha instalado correctamente accediendo desde virt-viewer:

3

O desde ssh comprobando antes su ip:

virsh -c qemu:///system net-dhcp-leases default      
 Expiry Time           MAC address         Protocol   IP address           Hostname   Client ID or DUID
------------------------------------------------------------------------------------------------------------------------------------------------
 2020-11-22 12:47:13   52:54:00:2e:b1:af   ipv4       192.168.122.249/24   debian     ff:00:2e:b1:af:00:01:00:01:27:4c:ed:89:52:54:00:2e:b1:af

Y conectamos:

ale@arya  ~  ssh debian@192.168.122.249                                 
debian@192.168.122.249's password: 
Linux debian 4.19.0-12-amd64 #1 SMP Debian 4.19.152-1 (2020-10-18) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Nov 22 10:36:12 2020
debian@debian:~$ 

Añadimos en el archivo:

/etc/sudoers

La siguiente línea si no se encuentra:

debian     ALL=(ALL) NOPASSWD: ALL

Y añadimos en el archivo:

sudo nano /etc/network/interfaces

El siguiente contenido:

auto ens3
iface ens3 inet dhcp

auto ens9 
iface ens9 inet dhcp

Ejercicio 2

Crea un par de claves ssh en formato ecdsa y sin frase de paso y agrega la clave pública al usuario debian.

Creamos el par de claves en nuestra máquina anfitriona:

ssh-keygen -t ecdsa
Generating public/private ecdsa key pair.
Enter file in which to save the key (/home/ale/.ssh/id_ecdsa): /home/ale/.ssh/hlc
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/ale/.ssh/hlc.
Your public key has been saved in /home/ale/.ssh/hlc.pub.
The key fingerprint is:
SHA256:eQUexj1idja5e6eOaGdWr/xKXXuNc+rNYXNpcU0wPqI ale@arya
The key's randomart image is:
+---[ECDSA 256]---+
|         .+. .o  |
|         o=oB. o |
|         o.+o+o .|
|         . o.. o.|
|        S E  . .+|
|         .  . ooO|
|             o+@*|
|          ..+++**|
|         ..+.oB++|
+----[SHA256]-----+

Pasamos la clave al host creado:

 ale@arya  ~  ssh-copy-id -i ~/.ssh/hlc debian@192.168.122.249
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/ale/.ssh/hlc.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
debian@192.168.122.249's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'debian@192.168.122.249'"
and check to make sure that only the key(s) you wanted were added.

Comprobamos el acceso:

 ale@arya  ~  ssh debian@192.168.122.249
Linux debian 4.19.0-12-amd64 #1 SMP Debian 4.19.152-1 (2020-10-18) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Nov 22 12:11:47 2020 from 192.168.122.1
debian@debian:~$

Ejercicio 3

Utiliza la herramienta virt-sparsify para reducir al máximo el tamaño de la imagen.

Apagamos la máquina:

virsh -c qemu:///system shutdown buster-base

Comprobamos el tamaño de la imagen:

sudo qemu-img info /var/lib/libvirt/images/buster-base.qcow2

image: /var/lib/libvirt/images/buster-base.qcow2
file format: qcow2
virtual size: 3.0G (3221225472 bytes)
disk size: 1.5G
cluster_size: 65536
Format specific information:
    compat: 1.1
    lazy refcounts: true
    refcount bits: 16
    corrupt: false

Reducimos su tamaño:

sudo virt-sparsify --in-place /var/lib/libvirt/images/buster-base.qcow2
 100% ⟦▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒⟧ --:--
[   7,6] Trimming /dev/sda1
[   7,8] Sparsify in-place operation completed with no errors

Y volvemos a comprobar:

sudo qemu-img info /var/lib/libvirt/images/buster-base.qcow2        

image: /var/lib/libvirt/images/buster-base.qcow2
file format: qcow2
virtual size: 3.0G (3221225472 bytes)
disk size: 1.3G
cluster_size: 65536
Format specific information:
    compat: 1.1
    lazy refcounts: true
    refcount bits: 16
    corrupt: false

Se ha reducido, pero hemos averiguado que existe otra opción que lo reduce todavía más:

sudo virt-sparsify --compress /var/lib/libvirt/images/buster-base.qcow2 /var/lib/libvirt/images/buster-base-2.qcow2

[   0.0] Create overlay file in /tmp to protect source disk
[   0.0] Examine source disk
[   3,8] Fill free space in /dev/sda1 with zero
[   5,9] Copy to destination and make sparse
[  60,9] Sparsify operation completed with no errors.
virt-sparsify: Before deleting the old disk, carefully check that the 
target disk boots and works correctly.

Comprobamos:

sudo qemu-img info /var/lib/libvirt/images/buster-base-2.qcow2

image: /var/lib/libvirt/images/buster-base-2.qcow2
file format: qcow2
virtual size: 3.0G (3221225472 bytes)
disk size: 464M
cluster_size: 65536
Format specific information:
    compat: 1.1
    lazy refcounts: false
    refcount bits: 16
    corrupt: false

Ejercicio 4

Sube la imagen y la clave privada ssh a alguna ubicación pública desde la que se pueda descargar.

Ya que tenemos los servidores de OVH, la voy a subir a mi página http://www.iesgn02.es, para ello, vamos a cambiar primero el propietario de buster-base.qcow2:

sudo chown -R ale. /var/lib/libvirt/images/buster-base-2.qcow2

Y ahora nos la pasamos a nuestro servidor igual que la clave privada:

scp /var/lib/libvirt/images/buster-base-2.qcow2 ned.iesgn02.es:/home/debian
scp ~/.ssh/hlc ned.iesgn02.es:/home/debian

Ejercicio 5

Crea una imagen nueva, que utilice buster-base.qcow2 como imagen base y tenga 5 GiB de tamaño máximo. Esta imagen se denominará maquina1.qcow2.

Vamos a obtener una imagen la cuál sólo obtenga los cambios realizados a partir de la imagen base, para ello:

sudo qemu-img create -f qcow2 -o backing_file=/var/lib/libvirt/images/buster-base-2.qcow2 /var/lib/libvirt/images/maquina1.qcow2 5G

Comprobamos que se ha creado y observamos su tamaño:

virsh -c qemu:///system vol-list default
                 
 Name                Path
----------------------------------------------------------------
 buster-base.qcow2   /var/lib/libvirt/images/buster-base.qcow2
 maquina1.qcow2      /var/lib/libvirt/images/maquina1.qcow2
sudo qemu-img info /var/lib/libvirt/images/maquina1.qcow2

image: /var/lib/libvirt/images/maquina1.qcow2
file format: qcow2
virtual size: 5.0G (3221225472 bytes)
disk size: 196K
cluster_size: 65536
backing file: /var/lib/libvirt/images/buster-base-2.qcow2
Format specific information:
    compat: 1.1
    lazy refcounts: false
    refcount bits: 16
    corrupt: false

Ejercicio 6

Crea una red interna de nombre intra con salida al exterior mediante NAT que utilice el direccionamiento 10.10.20.0/24.

Creamos el fichero:

nano intra.xml

Con el siguiente contenido:

<network>
  <name>intra</name>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <bridge name='br1' stp='on' delay='0'/>
  <ip address='10.10.20.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='10.10.20.50' end='10.10.20.100'/>
    </dhcp>
  </ip>
</network>

Definimos y activamos la red:

virsh -c qemu:///system net-define intra.xml
virsh -c qemu:///system net-start intra

Comprobamos:

virsh -c qemu:///system net-list       
 Name    State    Autostart   Persistent
------------------------------------------
 intra   active   no          yes

Ejercicio 7

Crea una máquina virtual (maquina1) conectada a la red intra, con 1 GiB de RAM, que utilice como disco raíz maquina1.qcow2 y que se inicie automáticamente.

Lanzamos la máquina:

virt-install --connect qemu:///system --name maquina1 \
--autostart \
--memory 1024 \
--network network=intra \
--vcpus 1 \
--disk /var/lib/libvirt/images/maquina1.qcow2,bus=sata \
--import

Ejercicio 8

Crea un volumen adicional de 1 GiB de tamaño en formato RAW ubicado en el pool por defecto.

Creamos el volumen adicional de 1GiB:

virsh -c qemu:///system vol-create-as --format raw --name vol-raw --capacity 1GiB --pool default

Ejercicio 9

Una vez iniciada la MV maquina1, conecta el volumen a la máquina, crea un sistema de ficheros XFS en el volumen y móntalo en el directorio /var/lib/pgsql. Ten cuidado con los propietarios y grupos que pongas, para que funcione adecuadamente el siguiente punto.

Conectamos el volumen a la máquina:

virsh -c qemu:///system attach-disk maquina1 /var/lib/libvirt/images/vol-raw sdb

Comprobamos en la máquina:

debian@debian:~$ lsblk
NAME   MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda      8:0    0   3G  0 disk 
└─sda1   8:1    0   3G  0 part /
sdb      8:16   0   1G  0 disk 

Creamos un sistema de fichero XFS dentro de la máquina:

sudo mkfs.xfs /dev/sdb 

meta-data=/dev/sdb               isize=512    agcount=4, agsize=65536 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=0
         =                       reflink=0
data     =                       bsize=4096   blocks=262144, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

Y montamos en la carpeta que creamos:

sudo mkdir /var/lib/pgsql
sudo mount /dev/sdb /var/lib/pgsql/
lsblk
NAME   MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda      8:0    0   3G  0 disk 
└─sda1   8:1    0   3G  0 part /
sdb      8:16   0   1G  0 disk /var/lib/pgsql

Cambiamos el propietario y grupo del directorio:

sudo chown -R postgres /var/lib/pgsql/

Ejercicio 10

Instala en maquina1 el sistema de BBDD PostgreSQL que ubicará sus ficheros con las bases de datos en /var/lib/pgsql utilizando una conexión ssh.

Instalamos PostgreSQL:

sudo apt install postgresql

Si entramos en postgre veremos dónde está alojado el directorio de sus datos:

sudo -u postgres psql
psql (11.9 (Debian 11.9-0+deb10u1))
Digite «help» para obtener ayuda.

postgres=# SHOW data_directory;
       data_directory        
-----------------------------
 /var/lib/postgresql/11/main
(1 fila)

Para cambiarlo, primero paramos postgre para garantizar la integridad de los datos:

sudo systemctl stop postgresql

Ahora instalamos rsync que usaremos para hacer la copia:

sudo apt install rsync

Y hacemos la copia copiando los permisos con -a:

sudo rsync -av /var/lib/postgresql /var/lib/pgsql

Cambiamos el nombre de la carpeta actual de postgre por si falla algo:

sudo mv /var/lib/postgresql/11/main /var/lib/postgresql/11/main.bak

Para apuntar a la nueva ubicación editamos:

sudo nano /etc/postgresql/11/main/postgresql.conf

Y editamos la línea de data directory dejándola de la siguiente forma:

data_directory = '/var/lib/pgsql/postgresql/11/main'

Reiniciamos postgre:

sudo systemctl restart postgresql

Y comprobamos:

sudo -u postgres psql
psql (11.9 (Debian 11.9-0+deb10u1))
Digite «help» para obtener ayuda.

postgres=# SHOW data_directory;
          data_directory           
-----------------------------------
 /var/lib/pgsql/postgresql/11/main
(1 fila)

Ya podríamos borrar el directorio antiguo de postgres:

sudo rm -rf /var/lib/postgresql/11/main.bak

Ejercicio 11

Puebla la base de datos con una BBDD de prueba.

Accedemos al usuario postgres con contraseña postgres:

debian@debian:~$ su - postgres
Contraseña: 
postgres@debian:~$

Creamos base de datos:

postgres@debian:~$ createdb prueba

Accedemos a para comprobar la base de datos:

postgres@debian:~$ psql
psql (11.9 (Debian 11.9-0+deb10u1))
Digite «help» para obtener ayuda.

postgres=# \c prueba
Ahora está conectado a la base de datos «prueba» con el usuario «postgres».
prueba=#

Ejercicio 12

Crea una regla de NAT para que la base de datos sea accesible desde el exterior.

Para que la base de datos sea accesible desde el exterior, editamos:

sudo nano /etc/postgresql/11/main/postgresql.conf

Y descomentamos la línea listen addresses y la dejamos de la siguiente forma:

listen_addresses = '*'

También tendremos que editar el siguiente fichero:

sudo nano /etc/postgresql/11/main/pg_hba.conf

Cambiando las IPv4 local connections:

# IPv4 local connections:
host    all             all             all            md5

Hemos creado al usuario externo para el acceso desde el exterior:

debian@debian:~$ su postgres

postgres@debian:/home/debian$ createuser -S -R -D -l externo

Y le hemos dado una contraseña:

postgres@debian:/home/debian$ psql
psql (11.9 (Debian 11.9-0+deb10u1))
Digite «help» para obtener ayuda.

postgres=# ALTER USER externo WITH ENCRYPTED PASSWORD 'externo';ALTER ROLE
ALTER ROLE

Reiniciamos postgres:

sudo systemctl restart postgres

Ahora accedemos desde nuestra máquina:

 ale@arya  ~  psql -h 10.10.20.50 -U externo -d prueba 
Contraseña para usuario externo: 
psql (11.9 (Debian 11.9-0+deb10u1))
conexión SSL (protocolo: TLSv1.3, cifrado: TLS_AES_256_GCM_SHA384, bits: 256, compresión: desactivado)
Digite «help» para obtener ayuda.

prueba=> 

No nos ha hecho falta añadir ninguna línea en iptables, pero en caso de que fuera necesario, bastaría con hacer lo siguiente en maquina1:

sudo iptables -A INPUT -s 10.10.20.1 -p tcp --dport 5432 -j ACCEPT
sudo iptables -A OUTPUT -d 10.10.20.1 -p tcp --dport 5432 -j ACCEPT

Y en el hipervisor:

iptables -t nat -A PREROUTING -p tcp --dport 5997 -j DNAT --to 10.10.20.64:5997

Ejercicio 13

Crea una imagen que utilice buster-base.qcow2 como imagen base y que tenga un tamaño de 4 GiB. Esta imagen se llamará maquina2.qcow2.

Creamos la imagen para maquina2:

sudo qemu-img create -f qcow2 -o backing_file=/var/lib/libvirt/images/buster-base-2.qcow2 /var/lib/libvirt/images/maquina2.qcow2 4G

Y ahora añadimos la imagen a dicho volumen:

Comprobamos:

sudo qemu-img info /var/lib/libvirt/images/maquina2.qcow2

image: /var/lib/libvirt/images/maquina2.qcow2
file format: qcow2
virtual size: 4.0G (3221225472 bytes)
disk size: 196K
cluster_size: 65536
Format specific information:
    compat: 1.1
    lazy refcounts: false
    refcount bits: 16
    corrupt: false

Ejercicio 14

Crea una nueva máquina (maquina2) que utilice imagen anterior, con 1 GiB de RAM y que también esté conectada a intra.

Lanzamos la máquina:

virt-install --connect qemu:///system --name maquina2 \
--autostart \
--memory 1024 \
--network network=intra \
--vcpus 1 \
--disk /var/lib/libvirt/images/maquina2.qcow2,bus=sata \
--import

Obtenemos su ip:

virsh -c qemu:///system domifaddr maquina2
 Name       MAC address          Protocol     Address
-------------------------------------------------------------------------------
 vnet1      52:54:00:ff:e3:49    ipv4         10.10.20.64/24

Ejercicio 15

Para el servicio postgreSQL, desmonta el dispositivo de bloques, desmonta el volumen de maquina1, monta el volumen en maquina2 en el directorio /var/lib/pgsql teniendo de nuevo cuidado con los propietarios y permisos del directorio.

En máquina1:

sudo systemctl stop postgresql
sudo umount /dev/sdb

En el hipervisor quitamos el volumen de maquina1 y lo asociamos a maquina2:

virsh -c qemu:///system detach-disk maquina1 /var/lib/libvirt/images/vol-raw
virsh -c qemu:///system attach-disk maquina2 /var/lib/libvirt/images/vol-raw sdb

En máquina2 creamos el directorio y montamos el volumen:

sudo mkdir /var/lib/pgsql
sudo mount /dev/sdb /var/lib/pgsql/

Ejercicio 16

Copia de forma adecuada todos los ficheros de configuración de PostgreSQL de maquina1 a maquina2.

Cambiamos permisos de los ficheros para poderlos pasar con usuario debian:

sudo chown debian. /etc/postgresql/11/main/postgres.conf
sudo chown debian. /etc/postgresql/11/main/pg_hba.conf

Lo envíamos por scp a maquina2:

scp /etc/postgresql/11/main/postgresql.conf debian@10.10.20.64:/home/debian
scp /etc/postgresql/11/main/pg_hba.conf debian@10.10.20.64:/home/debian

Ejercicio 17

Instala PostgreSQL en maquina2 a través de ssh.

Instalamos a través de ssh:

ssh -t debian@10.10.20.64 "sudo apt-get install postgresql"

En maquina2, copiamos los archivos de configuración a su sitio determinado:

sudo cp pg_hba.conf /etc/postgresql/11/main/pg_hba.conf
sudo cp postgresql.conf /etc/postgresql/11/main/postgresql.conf

Comprobamos que funciona desde nuestra máquina:

ale@arya  ~  psql -h 10.10.20.64 -U externo -d prueba
Contraseña para usuario externo: 
psql (11.9 (Debian 11.9-0+deb10u1))
conexión SSL (protocolo: TLSv1.3, cifrado: TLS_AES_256_GCM_SHA384, bits: 256, compresión: desactivado)
Digite «help» para obtener ayuda.

prueba=> 

Ejercicio 18

Conecta maquina2 al bridge exterior de tu equipo, comprueba la IP que tiene el equipo en el bridge exterior y muéstrala por la salida estándar. Desconecta maquina2 de intra.

Hemos creado otro fichero xml con el siguiente contenido:

<network>
  <name>intra_2</name>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <bridge name='br2' stp='on' delay='0'/>
  <ip address='10.10.50.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='10.10.50.50' end='10.10.50.100'/>
    </dhcp>
  </ip>
</network>

Definimos la red:

virsh -c qemu:///system net-define intra_2.xml                      

Y la arrancamos:

virsh -c qemu:///system net-start intra_2

La conectamos a maquina2:

virsh -c qemu:///system attach-interface --domain maquina2 --type network --source intra_2 --config --live

Y comprobamos:

virsh -c qemu:///system domiflist maquina2 
 Interface   Type      Source    Model     MAC
--------------------------------------------------------------
 vnet1       network   intra     e1000     52:54:00:ff:e3:49
 vnet2       network   intra_2   rtl8139   52:54:00:0f:d7:e3
virsh -c qemu:///system domifaddr maquina2 
 Name       MAC address          Protocol     Address
-------------------------------------------------------------------------------
 vnet1      52:54:00:ff:e3:49    ipv4         10.10.20.64/24
 vnet2      52:54:00:fa:a6:73    ipv4         10.10.50.54/24

Todo correcto, quitamos la interfaz de intra:

virsh -c qemu:///system detach-interface --domain maquina2 --type network --mac 52:54:00:ff:e3:49

Ejercicio 19

Comprueba que el servicio PostgreSQL funciona accediendo a través del bridge exterior.

Accedemos desde nuestro hipervisor:

 ale@arya  ~  psql -h 10.10.50.54 -U externo -d prueba
Contraseña para usuario externo: 
psql (11.9 (Debian 11.9-0+deb10u1))
conexión SSL (protocolo: TLSv1.3, cifrado: TLS_AES_256_GCM_SHA384, bits: 256, compresión: desactivado)
Digite «help» para obtener ayuda.

prueba=> 

Si tuvieramos que acceder desde el exterior, tendríamos que cambiar la regla de iptables:

iptables -t nat -A PREROUTING -p tcp --dport 5997 -j DNAT --to 10.10.50.54:5997

Ejercicio 20

Apaga maquina1 y aumenta la RAM de maquina2 a 2 GiB.

Apagamos máquina1:

virsh -c qemu:///system shutdown maquina1

En máquina2 la memoria máxima que puede tener de ram la tenemos en 1G, para modificarla tendremos que apagar la máquina:

virsh -c qemu:///system shutdown maquina2

Entramos en la configuración de la máquina:

virsh -c qemu:///system edit maquina2

Y cambiamos el valor memory:

<memory unit='KiB'>4194304</memory>

Iniciamos la máquina:

virsh -c qemu:///system start maquina2

Y ahora en caliente, como tenemos el memballoon activo, podremos aumentar la ram:

virsh -c qemu:///system setmem maquina2 --size 2G --live

Comprobamos dentro de máquina2:

free -h
              total        used        free      shared  buff/cache   available
Mem:          1,9Gi        64Mi       1,7Gi       5,0Mi        65Mi       1,6Gi
Swap:            0B          0B          0B