The Lost Papers - The CEREBELLUM Files (I)


============================================


THE CEREBELLUM FILES (I)


============================================

MareNostrum, Finisterrae2, Picasso, CaesarAugusta, Cibeles. Son nombres que conocemos la mayoría de todos nosotros. Por contra en el ámbito académico y científico existe otro mundo aparte en el cual dichas nomenclaturas no se refieren explícitamente al Mar Mediterráneo de los romanos, a Cabo Fisterra y ritos paganos, no se refieren a lienzos ni esculturas, como tampoco lo hacen con respecto a la Historia de la ciudad de Zaragoza; tampoco hablamos de celebraciones en el ámbito deportivo. Dichos nombres han sido inspirados por el lugar en el cual se ubican. Hablamos de la supercomputación.

Puede parecer una terminología ciertamente lejana desde sus inicios al presente para el común de las personas; pero cabe recalcar que dependemos de dichas tecnologías. Los nombres mencionados al comienzo de esta entrada son hacen referencia a parte integrante de la Red Española de Supercomputación creada en el año 2007 con fines científicos.

Pero retrocedamos a la década de los 90, a los años 1993 y 1994 más concretamente, cuando en la NASA surgió la idea de Thomas Sterling y Donald Becker para crear el primer clúster Beowulf con la intención de hacer accesible el supercómputo para economías mucho más modestas que las grandes corporaciones y estamentos gubernamentales.

Para dicho proyecto aprovecharon mucho material que por aquel entonces ya se consideraba obsoleto, recordemos el lugar en el cual nació tal proyecto. Gran parte del éxito del mismo ha estado íntimamente relacionado con el kernel de Linux (GPL), el software Open Source y el hardware que puede considerado por muchos obsoleto.

En mi caso concreto corría el año 2008, conocía perfectamente la historia de Becker, Sterling y el primer clúster Beowulf. Pero lo consideraba inalcanzable, lo fué hasta que creé mi primer clúster. Lo componían dos IBM 300PL con procesadores Intel Pentium II a 400 y 450 MHz; así mismo la memoria RAM instalada era de 128 y 256 MB respectivamente. La distribución instalada era por aquel entonces Debian GNU/Linux y por lo tanto al estar habituado a trabajar con ella comencé a hacer las primeras pruebas con ClusterKnoppix, PelicanHPC 2.2 en su versión para 32 bits. Tras un pequeño análisis acerca de lo que ofrecía o me podía ofrecer, si me interesaba realmente continuar con dicho tipo de proyectos relacionados y que las primeras impresiones fueron muy satisfactorias opté por acabar montando el primer clúster que tras organizaciones y reorganizaciones del mismo, adoptar y aprender la metodología de trabajo de otras distribuciones como asi ocurrió con Arch Linux tras los problemas expuestos en otro manual que publiqué hace tiempo con los dispositivos de video Intel ( http://eb1agg.hol.es/?q=node/51 ), valorar aspectos acerca de las expectativas relacionadas con ello. Un cúmulo de motivos tales como la satisfacción por el aprendizaje a nivel aficionado y la motivación personal de hacer algo que la gran mayoría considera inalcancable poderlo tener a mi entera disposición. Con todo ello se ha llegado al día presente con el paso de los años.

CEREBELLUM en sus inicios.

El motivo fundamental de este manual es tratar acerca de la instalación y configuración de un pequeño clúster basado en OpenMPI ( https://www.open-mpi.org/ ).

Uno de los puntos más importantes y que mas confusión genera es si se pueden mezclar 386/686 y x86_64. La respuesta es muy sencilla, un "Sí, pero ...". Se puede hacer si nos ceñimos a la limitación que supone basar todo el clúster en un sistema operativo de 32 bit. En mi caso CEREBELLUM se divide en tres subclúster. PEGASUS trabajando en x86_64, PERSEUS en 686 e HYDRA en ARM.

El manual constará de varias partes relacionadas con la gestión de usuarios, sistemas de ficheros remotos, instalación de OpenMPI, uso básico de compilación y de ejecución de aplicaciones de muestra. Así pues vamos a ponernos manos a la obra

1. Creación de usuarios.

De optar por la opción de hacerlo mediante intérprete de comandos debemos llevar a cabo ciertos pasos para crearlo.

[root@VULCANO ~]# useradd -d /home/beowulf -m -s /bin/bash beowulf

Lo que hacemos al pasar estas opciones al crear el usuario es indicar con '-d' que el directorio personal sea '/home/beowulf/', la opción '-m' indica la creación del mismo si no existe y con el parámetro '-s' indicamos que el shell o intérprete de comandos (como deseemos llamarle) sea bash. Al añadir el usuario beowulf también se crea el grupo primario con el mismo nombre; por lo tanto si necesitamos que otro sea el principal de trabajo utilizaremos la opción '-g' quedando de la siguente forma:

[root@VULCANO ~]# useradd -g cluster -d /home/beowulf -m -s /bin/bash beowulf

A continuación modificaremos la contraseña por defecto para el usuario que acabamos de crear:

[root@VULCANO ~]# passwd beowulf

En algunas ocasiones tras la creación al realizar login por primera vez podemos obtener algún tipo de mensaje de error debido a que los permisos del directorio personal no son los correctos. Una de las soluciones es cambiar de forma recursiva el usuario el cual es propietario de dicho directorio y el grupo al que pertenece. En este ejemplo cambiamos los permisos para el usuario beowulf y para el grupo primario con el mismo nombre.

[root@VULCANO ~]# chown -R beowulf:beowulf /home/beowulf/

Como nota aclaratoria decir que para tener una configuración homogénea se recomienda que tanto el usuario, el directorio personal, el UID y el directorio de trabajo compartido a través de NFS sean los mismos en todas las máquinas.

2. Asociando nombres de host a direcciones IP.

Una de las costumbres que he tenido desde mis primeros pasos usando GNU/Linux a partir de aquel remoto año 2001 fué la de siempre asignar un nombre de host a una dirección IP tanto dentro como fuera de la red local para hacer más rápido el acceso. Para ello editaremos el fichero /etc/hosts lo cual no merece una reseña especial con respecto a la configuración debido a su sencillez.

# ip-address hostname
127.0.0.1 localhost
::1 localhost

192.168.43.1 router
192.168.43.2 routerwifi
192.168.43.3 cronos
192.168.43.4 vulcano
192.168.43.5 orion
192.168.43.6 nemesis
192.168.43.7 apolo
192.168.43.8 neptuno
192.168.43.9 titan
192.168.43.10 hermes
192.168.43.21 azor-aprs
192.168.43.22 azor-digi
192.168.43.23 azor-sdr
192.168.0.132 zeus
192.168.0.131 galaxy

3. Configuración de la autenticación a tarvés de SSH.

He aquí uno de los puntos más importantes a tener en cuenta con la configuración de nuestro pequeño clúster. La creación e importación de una clave pública SSH (Secure Shell) cuya función será el acceso remoto del usuario que hemos creado en todas las máquinas, tanto el nodo maestro como el resto de nodos esclavos, sin necesidad de contraseña.

/p>

Para ello, como no, hemos de tener OpenSSH instalado y convenientemente configurado. Sobre todo si queremos correr remotamente aplicaciones gráficas a través de X11 Forwarding. Eso ya será bajo el criterio acerca de las políticas de seguridad que deseemos implantar y el gusto de cada uno.

Para crear e importar la clave podemos realizar una conexión 'loopback' desde un terminal o acceder directamente a través de una consola virtual (TTY) haciendo login con los datos correspondientes.

En el ejemplo que sigue crearemos una clave pública de 2048 bit utilizando el algoritmo RSA. Un dato a tener en cuenta para que todo funcione correctamente es que cuando en el proceso se nos requiera de introducir una contraseña no indiquemos ninguna.

[beowulf@VULCANO ~]$ ssh-keygen -t rsa -b 2048

A continuación procedemos a copiar la claves generadas en todos los equipos entre el nodo maestro y los nodos esclavos.

[beowulf@VULCANO ~]$ scp .ssh/id_rsa.pub beowulf@apolo:~

Continuamos importando la clave pública generada al fichero .ssh/authorized_keys.

[beowulf@APOLO ~]$ cat id_rsa.pub >> .ssh/authorized_keys

Una vez hecho esto en todos los nodos entre el maestro y los esclavos procedemos a conectarnos vía SSH entre ellos para comprobar que todo está funcionando correctamente. De no ser así repetiremos la configuración importando las claves de dichos nodos.

De mostrarnos algún tipo de mensaje de error con respecto a la ubicación del fichero de claves autorizadas editaremos el fichero de configuración del daemon SSH buscando las siguientes líneas y editandolo de la siguiente manera:

# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
# but this is overridden so installations will only check .ssh/authorized_keys
AuthorizedKeysFile %h/.ssh/authorized_keys

4. Instalación y configuracion de NFS.

Dependiendo de la distribución el nombre de los paquetes variará de manera significativa. En esta parte del manual se hará referencia explícita a la instalación a través de pacman en Arch Linux que es la distribución que llevo utilizando en los últimos años por ser la que más se ajusta a mis necesidades. Instalaremos los paquetes nfs-utils, nfsidmap y libnfs.

Primero antes de continuar con la instalación de NFS creamos el directorio que montaremos remotamente en los nodos esclavos y exportaremos a través del nodo maestro. En mi caso concreto el montaje se realiza en /home/beowulf/desarrollo.

[beowulf@VULCANO ~]$ mkdir /home/beowulf/desarrollo

Continuamos instalando NFS a través de pacman. Llegados a este punto del manual lo dividiremos en las configuraciones del lado cliente (nodos esclavos) y del servidor (nodo maestro).

. Configuración del lado servidor (Nodo maestro):

Buscamos los paquetes relacionados con NFS a través de pacman en los repositorios de Arch Linux:

[txus@VULCANO ~]$ pacman -Ss nfs
core/mkinitcpio-nfs-utils 0.3-5
ipconfig and nfsmount tools for NFS root support in mkinitcpio
core/nfs-utils 2.1.1-4 [instalado]
Support programs for Network File Systems
core/nfsidmap 0.26-1 [instalado]
Library to help mapping IDs, mainly for NFSv4
extra/gvfs-nfs 1.32.1+5+gf0d758df-1 (gnome)
Virtual filesystem implementation for GIO (NFS backend)
community/liblockfile 1.09_6-1
a library with NFS-safe locking functions
community/libnfs 2.0.0-1 [instalado]
client library for accessing NFS shares
community/perl-file-nfslock 1.27-2
NFS compatible (safe) locking utility
community/unionfs-fuse 2.0-1
A user space unionfs implementation

Una vez localizados en la búsqueda los instalamos de la siguiente manera:

[txus@VULCANO ~]$ sudo pacman -S nfs-utils nfidmap libnfs

Una vez instalados procedemos a configurar el directorio exportado a través de NFS en el nodo maestro para que pueda ser montado remotamente en los nodos esclabos. Editamos el fichero /etc/exports y añadimos la siguiente línea al final del mismo. Las direcciones IP de la red local (LAN) la cambiaremos según se ajuste a nuestras necesidades.

/home/beowulf/desarrollo 192.168.43.0/24 (rw,no_subtree_check,async,no_root_squash)

A continuación activaremos los servicios y los arrancaremos a traves de systemd:

[txus@VULCANO ~]$ sudo systemctl enable rpcbind nfs-server && sudo systemctl start rpcbind nfs-server

. Configuración del lado cliente (Nodos esclavos).

Comenzamos la configuración de los nodos esclavos con la instalación de los paquetes necesarios para utilizar NFS de la misma manera que hicimos en el servidor. Salvo por pequeños matices que diferencian la configuración del maestro con respecto a ellos.

Realizamos la búsqueda en los repositorios de Arch Linux:

[txus@APOLO ~]$ pacman -Ss nfs
core/mkinitcpio-nfs-utils 0.3-5
ipconfig and nfsmount tools for NFS root support in mkinitcpio
core/nfs-utils 2.1.1-4 [instalado]
Support programs for Network File Systems
core/nfsidmap 0.26-1 [instalado]
Library to help mapping IDs, mainly for NFSv4
extra/gvfs-nfs 1.32.1+5+gf0d758df-1 (gnome)
Virtual filesystem implementation for GIO (NFS backend)
community/liblockfile 1.09_6-1
a library with NFS-safe locking functions
community/libnfs 2.0.0-1 [instalado]
client library for accessing NFS shares
community/perl-file-nfslock 1.27-2
NFS compatible (safe) locking utility
community/unionfs-fuse 2.0-1
A user space unionfs implementation

E instalamos el conjunto de paquetes:

[txus@APOLO ~]$ sudo pacman -S nfs-utils nfidmap libnfs

Una vez realizado el proceso de instalación crearemos el directorio el punto de montaje a través del cual tendremos acceso al directorio exportado remotamamente a través de NFS perteneciente al nodo maestro. Recordemos que ha de ser el mismo en todos los nodos.

[beowulf@VULCANO ~]$ mkdir /home/beowulf/desarrollo

A continuación nos centraremos en la edición del fichero /etc/fstab al cual añadiremos la siguiente línea al final del mismo. Será la encargada de montar el directorio remoto en el punto que hemos creado en el paso anterior.

# NFS VULCANO
VULCANO:/home/beowulf/desarrollo/ /home/beowulf/desarrollo nfs4 size=8192,wsize=8192,timeo=14,intr,_netdev 0 0

Una vez guardados los cambios procedemos a montar el directorio:

[beowulf@APOLO ~]$ su
Contraseña:
[root@APOLO beowulf]# mount /home/beowulf/desarrollo/

Os habréis preguntado el porqué no he utilizado sudo y en cambio he usado la orden su para obtener privilegios de root. La respuesta es bastante sencilla, está ligada a la política de seguridad que le demos a nuestros sistemas. Por lo tanto no deseo que el usuario beowulf pueda escalar privilegios menos que sea mediante esta vía.

Para comprobar que el directorio del nodo maestro se está exportando correctamente podemos ejecutar desde cualquiera de los esclavos la siguiente orden. Deberíamos recibir una salida parecida a esta en el terminal.

[txus@APOLO ~]$ showmount -e vulcano
Export list for vulcano:
/home/beowulf/desarrollo 192.168.43.0/24

NOTA ACLARATORIA - La instalación de NFS puede ser sustituído por el uso de SAMBA y CIFS. Este tipo de configuración probablemente lo trataré en la siguiente parte de esta serie de artículos.

5. Instalación y configuración de OpenMPI.

En este último punto realizaremos la instalación de OpenMPI. En este caso instalaremos lo referido en los repositorios de Arch Linux y si precisamos de alguna más en concreto la instalaremos sin problema alguno.

txus@VULCANO ~]$ pacman -Ss openmpi
extra/openmpi 2.1.1-1 [instalado]
High performance message passing library (MPI)
community/hdf5-openmpi 1.10.1-1 [instalado]
General purpose library and file format for storing scientific data (openmpi
version)
community/parallel-netcdf-openmpi 1.8.1-4 [instalado]
A Parallel I/O Library for NetCDF File Access
community/python-h5py-openmpi 2.7.0-3 [instalado]
General-purpose Python bindings for the HDF5 library (openmpi version)
community/python2-h5py-openmpi 2.7.0-3 [instalado]
General-purpose Python bindings for the HDF5 library (openmpi version)

Una vez buscados los instalamos:

[txus@VULCANO ~]$ sudo pacman -S openmpi hdf5-openmpi parallel-netcdf-openmpi python-h5py-openmpi python2-h5py-openmpi

Ahora para finalizar editaremos en el directorio personal del usuario que creamos en el nodo maestro el fichero .mpi_hostfile (/home/beowulf/.mpi_hostfile). En el cual indicaremos las máquinas que componen el clúster, así como los slots disponibles en cada una de las mismas. Los nombres de host de los equipos han de ser los mismos que asignamos en el fichero /etc/hosts.

[beowulf@VULCANO ~]$ more .mpi_hostfile
# Nodo maestro

VULCANO slots=2

# Nodo(s) Esclavo(s)

APOLO slots=2
ORION slots=4
NEMESIS slots=2

Una vez terminada la configuración el siguiente paso es familiarizarse un tanto con el entorno de trabajo que acabamos de instalar en nuestras máquinas.

. Ejemplos de prueba.

Llegados a este punto tras haber finalizado la configuración vamos a llevar a cabo varias operaciones para cercionarnos que está todo funcionando correctamente. La primera de ellas es comprobar que está el directorio remoto compartido a través de NFS montado ya que de no ser así al superar cierto número de slots, dependiendo de cuantos procesadores y a su vez los núcleos tengamos disponibles o configurados en el fichero /home/beowulf/.mpi_hostfile, las aplicaciones no se iniciarán de manera correcta.

1. Lenguaje de programación C.

Hacemos login remotamente a través de SSH en el nodo maestro. Creamos un nuevo fichero de texto en el directorio /home/beowulf/desarrollo/ del nodo maestro llamado pi.c, copiamos y pegamos el contenido desde este enlace ( http://www.qsl.net/eb1agg/data/ejemplosmpi/pi.c ).

Dicho código fuente lo compilaremos con la siguiente orden. No nos resultará extraño dado que el funcionamiento es idéntico a estar utilizando gcc.

[beowulf@NEPTUNO desarrollo]$ mpicc -o pi pi.c

El programa que acabamos de compilar calcula el número pi utilizando OpenMPI. En este caso en concreto para hacer las capturas correspondientes estaré utilizando el nodo maestro y dos nodos esclavos del clúster PERSEUS que es el que utiliza instrucciones de procesador de 32 bits. Lo ejecutaremos con la siguiente orden:

[beowulf@NEPTUNO desarrollo]$ mpirun -np 6 --hostfile ~/.mpi_hostfile ./pi

Figura 1 - Ejecutando aplicación C de muestra.

Como podemos observar en la imagen superior la ejecución del proceso genera una distribución del mismo entre el nodo maestro y los dos nodos esclavos.

Las opciones que le pasamos a mpirun se refieren a lo siguiente. La opción referente -np 6 le indicará cuantos slot de los disponibles o configurados en el clúster utilizará la ejecución de dicha aplicación y creará tantos procesos paralelos como sean indicados. La opción --hostfile es evidente, indica la ruta del fichero de configuración .mpi_hostfile. Y ya para terminar incluímos la aplicación que deseamos ejecutar con mpirun.

Se dá otro escenario. Si no incluímos en las opciones de mpirun la ruta correspondiente al fichero de configuración .mpi_hostfile ocurrirá esto que se ejecutarán en el nodo maestro únicamente como puede observarse en la siguiente imagen.

Figura 2 - Ejecutando aplicación de muestra sin indicar ruta a ~/.mpi_hostfile.

2. Lenguaje de programación C++.

Realizaremos las mismas operaciones que en el paso anterior. Crearemos un fichero llamado primos.c++ en el directorio compartido del nodo maestro y pegaremos el código fuente incluído en este enlace ( http://www.qsl.net/eb1agg/data/ejemplosmpi/primos.c++ ).

Debido a que esta aplicación está escrita en C++ en vez de utilizar mpicc utilizaremos mpic++. La podremos compilar con la siguiente orden.

[beowulf@NEPTUNO desarrollo]$ mpic++ -o primos.c++ primos

Para ejecutar la aplicación lo haremos como en el caso anterior:

[beowulf@NEPTUNO desarrollo]$ mpirun -np 6 --hostfile ~/.mpi_hostfile ./primos

Como se puede apreciar en la imagen inferior se reparten los procesos entre los slots del clúster PERSEUS.

Figura 3 - Ejecutando aplicación C++ de muestra.

Si toda la configuración ha sido correctamente hecha, los procesos y los mensajes recibidos a través del terminal se ajustan a lo expuesto entonces tendremos nuestro pequeño clúster basado en OpenMPI plenamente operativo.

That's all folks!