rootfs sobre ISCSI con tu Raspberry y Ubuntu 20.04

Tome la determinación de hacer que mis de mis Raspberries tengan el boot desde la microSD y tener el rootfs sobre iSCSI de un target compartido desde mi NAS (una asignación 1 a 1), considero esto como una mejora al procedimiento del boot sobre NFS, pero esta solución es más compleja también.

Esta solución es más segura (el protocolo iSCSI ademas de poder filtrar por IP permite autenticar con usuario y contraseña).

Encontré información perdigonada en los foros de la fundación Raspberry, pero no encontré nada que este documentado de punta a punta. Quizás si no hubiese hecho andar la solución en NFS, en forma previa, no hubiese tenido el conocimiento acumulado como para llenar los blancos y hacer andar esta.

Preparación de entorno:

Lo primera acción a realizar es descargar la imagen de Ubuntu 20.04 para Raspberry desde la página oficial, una vez finalizada la misma, procedemos a descomprimirla.

En el ejemplo la descarga la hice en el /tmp

cd /tmp
unxz ubuntu-20.04-preinstalled-server-arm64+raspi.img.xz

En cada caso adecuar el nombre del archivo en base a la versión que se haya descargado.

Y una vez finalizada la descompresión voy a proceder a montar la imagen para copiar y armar el boot y el / que vamos a utilizar.

Para eso utilizamos la utilidad losetup que nos crea una unidad /dev/loop0 (si ya hay una unidad montada en el loopX lo hará con el siguiente disponible, lo muestra en la salida del comando) con dos particiones, /dev/loop0p1 y /dev/loop0p2 que corresponden al boot y al / respectivamente.

Monto ambas particiones en directorios creados dentro del /tmp

sudo losetup -P -f --show ./ubuntu-20.04-preinstalled-server-arm64+raspi.img
mkdir -p /tmp/imgP1
mkdir -p /tmp/imgP2
sudo mount /dev/loop0p1 /tmp/imgP1/
sudo mount /dev/loop0p2 /tmp/imgP2/
Captura de pantalla de la ejecución del comando losetup.

PREPARANDO EL ROOTFS BASE:

El siguiente paso es montar la partición / de la imagen para copiarla a la ubicación donde voy a utilizarla como origen para mis instalaciones.

sudo mkdir -p /mnt/storage/rbpi-nfs/base-ub-2004-rootfs
sudo rsync -avz ./imgP2/ /mnt/storage/rbpi-nfs/base-ub-2004-rootfs

El comando rsync va a demandar unos minutos. Si no lo tenes instalado, en esta página tenes el set de aplicaciones/utilidades que considero «obligatorias».

Posterior a la copia ejecuto los siguientes comandos para permitir que me pueda conectar como «root» a través del «ssh» utilizando la llave ssh que tengo creada en el sistema.

sudo mkdir -p /mnt/storage/rbpi-nfs/base-ub-2004-rootfs/root/.ssh/
cat ~/.ssh/id_rsa.pub | sudo tee -a /mnt/storage/rbpi-nfs/base-ub-2004-rootfs/root/.ssh/authorized_keys

Preparando el boot base:

En la partición 1 voy a crear un archivo sin vacío con nombre ssh, para que el equipo levante con el servicio SSH habilitado, voy a resguardar el archivo original cmdline.txt y crear uno nuevo con la plantilla de los datos que tengo que cargar.

En este archivo defino la configuración de red en el parámetro «ip=«

ip=::::::

donde:

  • client-ip -> es la ip que va a tener la raspberry.
  • net-boot-server-ip -> es la ip del servidor de netboot, en este caso no lo usamos y dejamos en valor nulo (::)
  • gw-ip -> La ip del gateway de la red
  • netmaks -> La máscara de subred, tipicamente 255.255.255.0
  • hostname -> El nombre que utilizará nuestra Raspberry.
  • device -> el dispositivo que vamos a configurar, en este caso eth0.
  • autoconf -> Si habilitamos o deshabilitamos el DHCP en este dispositivo on/off.

En mi caso voy a dejar solo como variable la ip y el nombre de servidor, ya que la el gateway y la mascara de red no van a cambiar.

sudo touch /tmp/imgP1/ssh
sudo mv /tmp/imgP1/cmdline.txt /tmp/imgP1/cmdline.ori
echo "net.ifnames=0 dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 ISCSI_INITIATOR=\$\$ISCSI_INITIATOR\$\$ ISCSI_TARGET_NAME=\$\$ISCSI_TARGET_NAME\$\$ ISCSI_TARGET_IP=\$\$ISCSI_TARGET_IP\$\$ ISCSI_TARGET_PORT=3260 ISCSI_TARGET_GROUP=1 ISCSI_USERNAME=\$\$ISCSI_USERNAME\$\$ ISCSI_PASSWORD=\$\$ISCSI_PASSWORD\$\$ rw rootfs=ext4 root=UUID=\$\$ISCSI_UUID\$\$ fsck.repair=yes elevator=deadline rootwait fixrtc ip=\$\$CLIENT-IP\$\$::10.0.0.3:255.255.255.0:\$\$HOSTNAME\$\$:eth0:off" | sudo tee -a /tmp/imgP1/cmdline.txt

Finalizada la copia y los trabajos voy a proceder a desmontar las particiones y desacoplar la imagen del sistema.

sudo umount /tmp/imgP1
sudo umount /tmp/imgP2
sudo losetup -d /dev/loop0

Ahora voy a reducir la imagen que descargué de Ubuntu para que contenga solo el boot y reducir su tamaño.

sudo parted ./ubuntu-20.04-preinstalled-server-arm64+raspi.img

En la consola de «parted» ejecutar los comandos delante del #

u     #cambiar tipo de unidad de medida
b     #Configurar unidad en bytes
p     #Listar particiones
rm 2  #Borrar partición 2 (ya habíamos copiado el contenido).
quit  #Salir de parted
Captura de pantalla de la ejecución del comando «parted» sobre la imagen de Ubuntu 20.04 para Raspberry 4

El valor que tomamos es donde termina la primer partición. En este caso «269484031», procedemos a continuación a generar el archivo img del boot en forma estricta. Como los bloque se cortan cada 512B tenemos que cortar la imagen con el mismo criterio.

sudo dd if=./ubuntu-20.04-preinstalled-server-arm64+raspi.img of=./base-ub-2004-boot.img bs=$((((269484031/512)+1)*512)) count=1

Finalizado esto procedo a hacer una copia a la carpeta donde deje los directorios con las fuentes para las nuevas instalaciones.

mv *boot.img /mnt/storage/rbpi-nfs/

En el estado final mi unidad quedo con dos archivos .img y dos directorios con los rootsfs uno de cada para distribución.

Listado de archivos con los elementos creados como base para las próximas instalaciones.

Configurando la microSD y el entorno para tener nuestra raspberry con el rootfs en el iSCSI.

Asumo que tenes un servidor iSCSI configurado como lo explico en el tutorial «Configurar iSCSI Storage Server en Ubuntu 20.04» y creaste un destino a tal fin.

Preparando el rootfs sobre ISCSI:

El siguiente paso es refrescar que targets nos expone nuestro iSCSI Storage Server a la ip del cliente. En este caso la ip de mi servidor es la «10.0.0.1«.

sudo iscsiadm -m discovery -t sendtargets -p 10.0.0.1
Captura de pantalla donde se listan las destinos disponibles.

Para poder establecer la conexión debemos ejecutar los siguientes comandos. Pongo en negrita los datos que son específicos de cada instancia.

sudo iscsiadm --mode node -T alphaprime.sismonda.local:rbpi3-003 -p 10.0.0.1:3260 --op=update --name node.session.auth.authmethod --value=CHAP
sudo iscsiadm --mode node -T alphaprime.sismonda.local:rbpi3-003 -p 10.0.0.1:3260 --op=update --name node.session.auth.username --value=Usuario
sudo iscsiadm --mode node -T alphaprime.sismonda.local:rbpi3-003 -p 10.0.0.1:3260 --op=update --name node.session.auth.password --value=SuperSecreto
sudo iscsiadm --mode node -T alphaprime.sismonda.local:rbpi3-003 -p 10.0.0.1:3260 --login
Captura de pantalla de la secuencia de comandos para establecer la conexión iSCSI.

Para saber que dispositivo fue el asignado para el destino iSCSI podemos ejecutar el siguiente comando:

dmesg |tail -n 11
Identificado el dispositivo asignado para la unidad iSCSI.

Como la unidad esta sin formatea proceso a formatearla en ‘ext4‘ y montarla en el directorio ‘/mnt/iSCSI‘. En el proceso de formateo resguardar el valor del UUID le la unidad formteada.

sudo mkfs.ext4 /dev/sdb
sudo mkdir -p /mnt/iSCSI
sudo mount /dev/sdb /mnt/iSCSI
Captura de la ejecución del comando «sudo mkfs.ext4 /dev/sdb«. Se debe resguardar el valor del UUID.

Verificamos que este montado ejecutando el comando:

mount |grep iSCSI
Confirmación de unidad montada.

El siguiente paso a seguir es copiar la estructura base a la unidad que va a ser el «rootfs» de la raspberry.

sudo rsync -avhP /mnt/storage/rbpi-nfs/base-ub-2004-rootfs/ /mnt/iSCSI

Finalizada la clonación del sistema de archivos, voy a proceder a crear un identificador del iniciador iSCSI con un nombre descriptivo para podes distinguir quien consume el recurso desde el iSCSI Storage Server. Resguardar el valor del InitiatorName

echo "InitiatorName=$(iscsi-iname -p rbpi3003)" | sudo tee /mnt/iSCSI/etc/iscsi/initiatorname.iscsi
Definiendo el valor del InitiatorName

El último paso es adecuar el fstab para que tome el rootfs con el UUID.

sudo vi /mnt/iSCSI/etc/fstab

Antes:

LABEL=writable / ext4 defaults 0 0
LABEL=system-boot /boot/firmware vfat defaults 0 1

Despues:

UUID=0ba4ce0b-2ed6-4048-b2ac-9a980a985a1e / ext4 defaults 0 0
LABEL=system-boot /boot/firmware vfat defaults 0 1

Con esto podemos dar por terminada la perapración de nuestro rootfs sobre iSCSI y procedemos a desmontar y desvincular la unidad iSCSI.

sudo umount /mnt/iSCSI
sudo iscsiadm --mode node -T alphaprime.sismonda.local:rbpi3-003 -p 10.0.0.1:3260 -u
sudo iscsiadm --mode node -T alphaprime.sismonda.local:rbpi3-003 -p 10.0.0.1:3260 -o delete

Preparación del boot en la microSD:

A continuación procedemos a preparar la microSD. La conectamos al equipo con nuestro lector preferido y verificamos que unidad es la asignada.

dmesg |tail
Salida del comando dmesg, donde se ve que la microSD fue detectada como sdb

En este caso mi MicroSD es el dispositivo /dev/sdb (revisar y estar seguro que es el mismo en el caso de ustedes, caso contrario adecuar porque sino van a romper algo).

sudo dd if=/mnt/storage/rbpi-nfs/base-ub-2004-boot.img of=/dev/sdb bs=4M status=progress

Procedo a montarla para poder adecuar los archivos para el booteo por iSCSI.

sudo mkdir -p /tmp/sdb1/
sudo mount /dev/sdb1 /tmp/sdb1/

Ahora tengo que modificar el archivo «cmdline.txt«. Este archivo contiene una sola línea, por favor revisen que en la edición no se escape ningún salto de línea.

sudo vi /tmp/sdb1/cmdline.txt

Antes de editar el «cmdline.txt«:

net.ifnames=0 dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1  ISCSI_INITIATOR=$$ISCSI_INITIATOR$$ ISCSI_TARGET_NAME=$$ISCSI_TARGET_NAME$$ ISCSI_TARGET_IP=$$ISCSI_TARGET_IP$$ ISCSI_TARGET_PORT=3260 ISCSI_TARGET_GROUP=1 ISCSI_USERNAME=$$ISCSI_USERNAME$$ ISCSI_PASSWORD=$$ISCSI_PASSWORD$$ rw rootfs=ext4 root=UUID=$$ISCSI_UUID$$ fsck.repair=yes elevator=deadline rootwait fixrtc ip=$$CLIENT-IP$$::10.0.0.3:255.255.255.0:$$HOSTNAME$$:eth0:off

Y adecuar los datos por:

$$ISCSI_INITIATOR$$ -> rbpi3003:a22c632eb8a
$$ISCSI_TARGET_NAME$$ -> alphaprime.sismonda.local:rbpi3-003
$$ISCSI_TARGET_IP$$ -> 10.0.0.1
$$ISCSI_USERNAME$$ -> Usuario
$$ISCSI_PASSWORD$$ -> SuperSecreto
$$ISCSI_UUID$$ -> 0ba4ce0b-2ed6-4048-b2ac-9a980a985a1e
$$CLIENT-IP$$ -> 10.0.0.33
$$HOSTNAME$$ -> rbpi3-003

Después DE EDITAR EL «CMDLINE.TXT«:

net.ifnames=0 dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1  ISCSI_INITIATOR=rbpi3003:a22c632eb8a ISCSI_TARGET_NAME=alphaprime.sismonda.local:rbpi3-003 ISCSI_TARGET_IP=10.0.0.1 ISCSI_TARGET_PORT=3260 ISCSI_TARGET_GROUP=1 ISCSI_USERNAME=Usuario ISCSI_PASSWORD=SuperSecreto rw rootfs=ext4 root=UUID=0ba4ce0b-2ed6-4048-b2ac-9a980a985a1e fsck.repair=yes elevator=deadline rootwait fixrtc ip=10.0.0.33::10.0.0.3:255.255.255.0:rbpi3-003:eth0:off

finalizada la edición del archivo, se debe desmontar la tarjeta microSD y ponerla en la raspberry, conectar la red y después darle energía.

sudo umount /dev/sdb1

Ya en nuestra Raspberry con rootfs sobre ISCSI :

Renombre de usuario por defecto:

Ya que entramos como root, vamos a cambiar el usuario «ubuntu» / «pi» por uno de uso personal. Esto lo hacemos ejecutando los siguientes comandos:

usermod -md /home/NuevoUsuario -l NuevoUsuario ubuntu
usermod -c "Nuevo nombre apellido" NuevoUsuario
groupmod -n NuevoUsuario ubuntu

También podemos proceder a cambiar al contraseña del nuevo usuario, esto se realiza ejecutando el comando:

passwd NuevoUsuario

Ahora podemos salir del equipo y volver a ingresar con un usuario terrenal y dejar el root.

CONFIGURACIÓN DE ZONA HORARIA:

Por defecto Ubuntu vienen configurados en GTM 0. Esto discrepa con la configuración regional de mi residencia.

sudo dpkg-reconfigure tzdata
Configuración tzdata para uso horario pantalla 1 de 2.
Configuración tzdata para uso horario pantalla 2 de 2.

Con estos paso ya tenemos el sistema en fecha y mostrando la hora local.

Configuración de hostname / nombre de servidor:

Para que nos muestre el prompt el nombre que le asignamos al equipo. Para que impacte el cambio debemos salir y volver a entrar al equipo.

sudo hostnamectl set-hostname rbpi3-003

Configurar DNS:

Como en la configuración de red que usamos no se puede especificar el dns, vamos a configurar los mismos en el archivo «/etc/systemd/resolved.conf«.

sudo vi /etc/systemd/resolved.conf

Y edito las líneas en negrita. Adecuar los valores según la configuración de la red donde están.

[Resolve]
DNS=10.0.0.10 10.0.0.31 10.0.0.62
#FallbackDNS=
Domains=sismonda.local
#LLMNR=no
#MulticastDNS=no
#DNSSEC=no
#DNSOverTLS=no
#Cache=yes
#DNSStubListener=yes
#ReadEtcHosts=yes

Finalizada la edición debemos reiniciar el servicio para que aplique los cambios.

sudo systemctl restart systemd-resolved

Opcionales:

Si instalaste en entorno gráfico seguramente se van a aplicar los perfiles de ahorro de enrgía, me paso que la Raspberry dejaba de funcionar cuando la dejaba de usar después de 20/30 minutos. Para evitar esto debemos proceder a deshabilitar la función de hibernación del Ubuntu.

sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target

Si por algún motivo lo queremos volver a activar, podemos hacerlo ejecutando.

sudo systemctl unmask sleep.target suspend.target hibernate.target hybrid-sleep.target

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.