hits counter

Clúster:



Montar un clúster

Una de las cosas más interesantes que podemos hacer, si disponemos de varias Raspberry Pi, es crear un clúster con todas las placas. En este ejemplo vamos a crear un clúster con cinco nodos: cuatro serán nodos esclavos y el quinto será el nodo maestro. Necesitamos un switch ethernet, al que irán conectados por cable todas las máquinas, y también un adaptador USB wifi que estará conectado al nodo maestro y que será el que ofrezca conexión a Internet a través del router (en su lugar, podríamos usar un adaptador USB Ethernet si deseamos conexión por cable). El esquema sería el siguiente:

Lo primero que haremos será instalar Raspbian en cada uno de los cinco nodos. Hecho esto, pasamos a realizar la configuración de la red. El clúster que vamos a montar usará una subred del tipo 192.168.2.X para la red ethernet (eth0), mientras que la tarjeta wireless (wlan0) del nodo maestro tendrá una dirección IP del tipo 192.168.1.X, asignada mediante el servidor DHCP del router, ya que las dos subredes (ethernet y wireless) han de ser diferentes.

En resumen: el router está configurado para ofrecer direcciones 192.168.1.X, que es el tipo de IP que se le va a asignar a la tarjeta USB wifi. Y aparte crearemos otra subred, del tipo 192.168.2.X, para conectar por cable todos los nodos.


Configurar la red del nodo maestro

Comenzamos la configuración del nodo maestro editando el fichero correspondiente:

sudo nano /etc/network/interfaces

e incluyendo las siguientes líneas:

auto lo
iface lo inet loopback

allow-hotplug eth0
iface eth0 inet static
address 192.168.2.1
netmask 255.255.255.0
network 192.168.2.0

allow-hotplug wlan0
iface wlan0 inet dhcp
wpa-ssid NOMBRE_RED
wpa-psk CONTRASEÑA

NOMBRE_RED y CONTRASEÑA los sustituiremos, naturalmente, por el SSID de nuestra red y por la clave que tengamos establecida para el acceso inalámbrico.

Haremos a continuación algunos cambios para que los nodos esclavos puedan acceder a Internet a través del nodo maestro. Primero editamos el fichero que contiene los parámetros del kérnel:

sudo nano /etc/sysctl.conf

y descomentamos la línea que se muestra a continuación, de modo que quede así:

net.ipv4.ip_forward=1

En segundo lugar, necesitamos hacer un cambio en el cortafuegos (firewall) del sistema y que se ejecute cada vez que se arranca el mismo. Para ello, editamos el fichero

sudo nano /etc/rc.local

Nos situamos al final del mismo, añadimos una línea en blanco y luego escribimos lo siguiente:

sudo /sbin/iptables --table nat -A POSTROUTING -o wlan0 -j MASQUERADE

El último paso para dejar terminada la configuración del nodo maestro es asignar las direcciones IP con sus respectivos nombres para cada uno de los nodos esclavos. Esto lo haremos editando el siguiente fichero:

sudo nano /etc/hosts

e incluyendo en el mismo estas líneas:

192.168.2.201     rpi1
192.168.2.202     rpi2
192.168.2.203     rpi3
192.168.2.204     rpi4

Recordemos que la subred ethernet debe tener sus direcciones IP dentro del rango 192.168.2.X, como dijimos al principio.

Con esto concluimos la configuración del nodo maestro. Reiniciamos la máquina y pasamos ahora a configurar los nodos esclavos.


Configurar la red de los nodos esclavos

En cada uno de los nodos tendremos que realizar una serie de pasos, que son los siguientes:

  1. 1.- Editamos el fichero
    sudo nano /etc/hostname
    y cambiamos el nombre por defecto (raspberrypi) por el nombre correspondiente a cada nodo (rpi1 para la primera máquina).

  2. 2.- Editamos ahora el fichero
    sudo nano /etc/hosts
    y sustituimos asimismo el nombre por defecto (raspberrypi) por el que le corresponde, igual que antes, en cada una de sus apariciones.

  3. 3.- Editamos también el fichero
    sudo nano /etc/network/interfaces
    e incluimos el siguiente contenido (sustituyendo XXX por el número que corresponde a cada nodo según lo asignado más arriba en el fichero /etc/hosts del nodo maestro):
    auto lo
    iface lo inet loopback

    iface eth0 inet static
    address 192.168.2.XXX
    netmask 255.255.255.0
    network 192.168.2.0
    broadcast 192.168.2.255
    gateway 192.168.2.1
  4. 4.- Editamos por último el fichero
    sudo nano /etc/resolv.conf

    y ponemos unas DNS válidas para dar salida a Internet a los nodos.

  5. 5.- Creamos un directorio para poder entrar en cada nodo sin usar una contraseña:
    mkdir ~/.ssh

Reiniciamos el primer nodo que hemos configurado y pasamos a configurar los restantes. Una vez configurados y reiniciados todos los nodos esclavos, realizamos los pasos 1 y 2 también en el nodo maestro, cambiando el nombre por defecto por rpi0. Lo reiniciamos y pasamos a hacer un test para comprobar las conexiones de red.


Test de red

Desde el nodo maestro hacemos un ping a cada nodo esclavo y nos conectamos además por SSH. En el caso del primer nodo, sería así:

ping rpi1
     PING rpi1 (192.168.2.201) 56(84) bytes of data.
     64 bytes from rpi1 (192.168.2.201): icmp_req=1 ttl=64 time=2.04 ms
     64 bytes from rpi1 (192.168.2.201): icmp_req=2 ttl=64 time=0.955 ms
ssh pi@rpi1

Cerramos la conexión con exit y ya podemos estar seguros de que la red funciona correctamente. Ahora pasaremos a configurar un acceso a los nodos sin usar contraseña.


Configurar un acceso sin clave desde el nodo maestro a los nodos esclavos

En el nodo maestro ejecutamos este comando:

ssh-keygen

y pulsamos INTRO cuando se nos pida una contraseña. Esto producirá una clave privada y otra pública, que se almacenarán en ~/.ssh/id_rsa y en ~/.ssh/id_rsa.pub, respectivamente.

A continuación copiamos ~/.ssh/id_rsa.pub en el ~/.ssh/authorized_keys de cada nodo esclavo. Podemos hacerlo de una forma rápida mediante el comando scp:

scp -p /home/pi/.ssh/id_rsa.pub rpi1:/home/pi/.ssh/authorized_keys
scp -p /home/pi/.ssh/id_rsa.pub rpi2:/home/pi/.ssh/authorized_keys
scp -p /home/pi/.ssh/id_rsa.pub rpi3:/home/pi/.ssh/authorized_keys
scp -p /home/pi/.ssh/id_rsa.pub rpi4:/home/pi/.ssh/authorized_keys

Si nos encontramos con problemas, debemos darle permisos 600 al fichero authorized_keys:

chmod 600 ~/.ssh/authorized_keys

A partir de ahora podremos acceder desde el nodo maestro a cada uno de los nodos esclavos por SSH sin necesidad de escribir una contraseña; simplemente así:

ssh rpi1

Ejecutar comandos en todos los nodos esclavos

Vamos a crear un método sencillo para ejecutar un mismo comando en todos los nodos esclavos a la vez. Para ello, en el nodo maestro nos desplazamos al directorio /usr/local/bin y creamos un fichero de script llamado cluster.sh:

sudo nano /usr/local/bin/cluster.sh

Insertamos en él el siguiente contenido:

#!/bin/sh
HOSTS="rpi1 rpi2 rpi3 rpi4"
for HOSTNAME in $HOSTS; do
     echo executing command on $HOSTNAME
     ssh `whoami`@$HOSTNAME $@
done

y lo convertimos en ejecutable:

sudo chmod a+x /usr/local/bin/cluster.sh

Si ejecutamos el script sin argumentos, entraremos por SSH en cada nodo y habrá que escribir exit para ir al siguiente. Pero lo normal sería usar como argumento un comando, de manera que dicho comando se ejecute en cada nodo de manera secuencial. Por ejemplo, para apagar todas las máquinas escribiríamos esto:

cluster.sh sudo shutdown -h now

[Fuente: www.mccarroll.net]


Computación paralela

Otra cosa distinta que podemos hacer, si disponemos de varias placas, es introducirnos en la computación paralela, que es algo bastante más complejo que crear un simple clúster. Esta clase de procesos se realiza mediante MPI (Message Passing Interface), un protocolo de comunicaciones que ofrece una interfaz estándar para ejecutar aplicaciones de computación paralela. Existen dos implementaciones de esta tecnología: OpenMPI y MPICH (Message Passing Interface CHameleon). Nosotros usaremos la segunda, ya que se trata de una versión del MPI estándar que permite usar aplicaciones escritas en los lenguajes C, C++ y Fortran.

Para hacer el proceso de instalación y configuración de MPI lo más sencillo posible, vamos a usar sólo dos placas Raspberry Pi: la primera será el nodo maestro (rpi1) y la segunda, el nodo esclavo (rpi2).


Configurar el nodo maestro

Lo primero que hemos de hacer es instalar y configurar adecuadamente Raspbian en la tarjeta SD de la Raspberry Pi que actuará como nodo maestro. Hecho esto, accedemos a la placa mediante SSH y generamos el par de claves RSA para poder realizar conexiones desde este nodo al nodo esclavo sin tener que escribir constantemente la contraseña de acceso, de forma similar a como lo hicimos en el apartado anterior:

cd
ssh-keygen

Pulsamos INTRO cuando se nos pida la contraseña y al final copiamos la clave pública en el fichero authorized_keys:

cat /home/pi/.ssh/id_rsa.pub >> /home/pi/.ssh/authorized_keys

Ahora editamos el fichero

sudo nano /etc/hostname

y cambiamos el nombre por defecto (raspberrypi) por rpi1.

A continuación, para que él trabajo con MPI resulte más fácil, es conveniente instalar Fortran:

sudo apt-get install gfortran

Las aplicaciones en este lenguaje podemos guardarlas en un directorio específico:

mkdir /home/pi/fortran

Otra cosa que es recomendable hacer, ya que nos facilitará el trabajo después, es instalar un multiplexor de terminales, como por ejemplo, tmux.

Antes de instalar MIPCH, vamos a crear algunos directorios:

mkdir mpich3
cd mpich3
mkdir build install

El primero será el directorio donde instalaremos MIPCH. Así pues, lo descargamos:

wget http://www.mpich.org/static/downloads/3.1.4/mpich-3.1.4.tar.gz

y lo descomprimimos:

tar xvfz mpich-3.1.4.tar.gz

Nos cambiamos al directorio build:

cd build

Le pasamos un parámetro de configuración para que MIPCH se instale en el directorio install creado antes:

/home/pi/mpich3/mpich-3.1.4/configure -prefix=/home/pi/mpich3/install

Aparecerá un mensaje similar a este:

         Configuring MPICH version 3.1.4 with '-prefix=/home/pi/mpich3/install'

Después lo compilamos (lo que tardará un tiempo):

make
make install

Mientras se lleva a cabo la compilación podemos echar un vistazo a la guía de usuario de MIPCH.

Acabado el proceso, necesitamos que el directorio donde se ha instalado MIPCH esté en el PATH para poder acceder al mismo desde cualquier sitio, sin tener que escribir la ruta completa en cada ocasión:

export PATH=$PATH:/home/pi/mpich3/install/bin

Ahora lo añadimos al profile del usuario:

nano /home/pi/.profile

poniendo este contenido en el fichero:

# MPI
export PATH="$PATH:/home/pi/mpich3/install/bin"

Necesitamos crear un fichero que contenga un listado con los nodos de nuestra red que queremos que corran aplicaciones MPI (lo llamaremos, por ejemplo, pifile):

nano /home/pi/pifile

De momento incluiremos en él la IP del nodo maestro que estamos configurando (en nuestro caso sería 192.168.1.84).

Podemos hacer una prueba para comprobar que funciona correctamente:

mpiexec -f pifile hostname

que nos debería devolver esto:

         Output is:
         rpi1

Por último, vamos a comprobar que el sistema MPICH trabaja de forma adecuada en la máquina que hemos configurado ejecutando una aplicación de ejemplo (cpi) que calcula el valor de Pi (Π):

mpiexec -f pifile -n 2 ~/mpich3/build/examples/cpi

La salida debería ser muy similar a esta:

         Process 0 of 2 is on rpi1
         Process 1 of 2 is on rpi1
         pi is approximately 3.1415926544231318, Error is 0.0000000008333387
         wall clock time = 0.018371


Configurar el nodo esclavo

Para configurar el segundo nodo aprovecharemos lo que ya hemos hecho en el primero. Así pues, apagamos la RPi, extraemos la tarjeta SD y la clonamos mediante la aplicación Win32DiskImager. Hecho esto, ya podemos colocar ambas tarjetas en sus respectivas máquinas y encender los dos nodos.

Desde el nodo maestro nos conectamos por SSH al nodo esclavo:

ssh -A pi@192.168.1.85

nos desplazamos al directorio /.ssh, borramos la dos claves RSA y cerramos la sesión:

cd /home/pi/.ssh
ls -al
rm id_rsa id_rsa.pub
exit

Ahora copiamos la clave pública del nodo maestro en el fichero authorized_keys del nodo esclavo:

cat ~/.ssh/id_rsa.pub | ssh pi@192.168.1.85 "cat >> .ssh/authorized_keys"

Aceptamos el mensaje que se nos muestra, escribimos la contraseña de acceso SSH, pulsamos INTRO cuando se nos pida la contraseña RSA y cerramos la sesión.

Necesitamos cambiar el hostname del segundo nodo. Para ello, esta vez entramos directamente por SSH en el nodo esclavo y editamos el fichero correspondiente, cambiando el nombre por defecto (raspberrypi) por rpi2:

sudo nano /etc/hostname

Por último, en el nodo maestro editamos el fichero /home/pi/pifile:

nano /home/pi/pifile

y añadimos la IP de la máquina esclava:

192.168.1.85

Llegados a este punto, ya podemos comprobar que el sistema MPICH trabaja de forma adecuada con los dos nodos que hemos configurado. Para ello, ejecutamos de nuevo la aplicación de ejemplo (cpi) que calcula el valor de Pi (Π):

mpiexec -f pifile -n 2 ~/mpich3/build/examples/cpi

Ahora la salida debería ser similar a esta:

         Process 0 of 2 is on rpi1
         Process 1 of 2 is on rpi2
         pi is approximately 3.1415926544231318, Error is 0.0000000008333387
         wall clock time = 0.018672

A partir de este momento podemos crear aplicaciones MPI usando, por ejemplo, el lenguaje C. Un buen documento para conocer todas las funciones y los tipos de datos de MPI es este manual.


[Extraído del libro Raspberry Pi Super Cluster, de Andrew K. Dennis, Packt Publishing, 2013]