Ampliamos la configuración para poder ofertar gpus nvidia como recursos.
Introducción
En este articulo ampliamos la configuración del agente de Apache Mesos, a lo expuesto en articulos anteriores, configurando gpus nvidia como los puertos que podemos utilizar en los agente de Apache Mesos y que van a ser ofertados por los nodos maestros de Apache Mesos a los frameworks para su uso.
GPUS Nvidia
Para incluir soporte de gpus nvidia tendremos que configurar los indicadores necesarios (recursos) en el agente de Apache Mesos para que el maestro de Apache Mesos pueda ofertarlas a los frameworks. Para un sistema operativo ubuntu, seguiremos los siguientes pasos:
$ sudo apt-get remove nvidia*
$ sudo apt-get autoremove
$ sudo apt-get update
$ sudo apt-get install dkms build-essential linux-headers-generic
Para evitar interferencias entre drivers, baneamos los drivers opensource nouveau:
$ sudo nano /etc/modprobe.d/blacklist-nouveau.conf
blacklist nouveau
blacklist lbm-nouveau
options nouveau modeset=0
alias nouveau off
alias lbm-nouveau off
Los desactivamos también del kernel con las siguientes ordenes:
$ echo options nouveau modeset=0 | sudo tee -a /etc/modprobe.d/nouveau-kms.conf
$ sudo update-initramfs -u
Ya solo nos queda instalar los drivers de la gpu nvidia. Podemos hacerlos de varias formas, lo vamos a hacer utilizando los paquetes que vienen en la distribución de Ubuntu.
$ sudo apt-get install nvidia-driver-390 nvidia-compute-utils-390 nvidia-dkms-390 nvidia-cuda-toolkit
Y ejecutamos el siguiente comando para comprobar que todo esta como debe de estar:
$ nvidia-smi
Fri Dec 28 14:24:47 2018
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 390.77 Driver Version: 390.77 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 GeForce GTX 960M Off | 00000000:01:00.0 Off | N/A |
| N/A 44C P8 N/A / N/A | 0MiB / 2004MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+
Configurando el Agente de Mesos
Añadimos el isolator correspondiente en la configuración del agente:
#/etc/default/mesos-agent
# Options to pass to mesos-agent
MESOS_AGENT=--hostname=agent4.leonvillamayor.org --ip=192.168.1.200 --log_dir=/var/log/mesos/agent --work_dir=/var/lib/mesos/agent --master=zk://192.168.1.11:2181,192.168.1.12:2181,192.168.1.13:2181/mesos --containerizers=docker,mesos -1-docker=/usr/bin/docker --executor_registration_timeout=10mins --attributes='rack:3;os:ubuntu1804;ip:192.168.1.200' --resources=file:///etc/default/recursos --isolation="filesystem/linux,cgroups/devices,gpu/nvidia"
Para que la gpu pueda funcionar correctamente necesitamos definir los aisladores necesarios, que son componentes que definen cada uno un aspectos de cómo se construye un entorno de ejecución de tareas (o contenedores). Los aisladores pueden controlar cómo se aíslan los contenedores entre sí, cómo se aplican los límites de recursos de tareas, cómo se configura la red, cómo se aplican las políticas de seguridad, etc.
En nuestro caso tenemos:
- filesystem/linux: Con este indicador le decimos al agente que use comandos específicos de Linux para preparar el sistema de archivos raíz y los volúmenes para los contenedores que los requieran. Específicamente, se basa en los espacios de nombres de montaje de Linux para evitar que los montajes de un contenedor se propaguen a la tabla de montaje de host. En el caso que nos ocupa, de gpus, requerimos que este indicador monte correctamente ciertos binarios de Nvidia (por ejemplo, nvidia-smi) y bibliotecas (por ejemplo, libnvidia-ml.so) en un contenedor cuando sea necesario.
- cgroups/devices: Le indica al agente que restrinja el acceso a un conjunto especifico de dispositivos para cada tarea que se inicie (es decir, un subconjunto de todos los dispositivos enumerados en /dev).
- gpu/nvidia: Junto con el indicador anterior, este indicador nos permite dar/revocar el acceso a GPUs especificas por tarea.
Como veremos en posteriores artículos, los aisladores son muy importante para garantizar que cada tarea se ejecuta de forma independiente, sin invadir los espacios de otras tareas, garantizando entre otras cosas la seguridad. Veremos como aplicarlos cuando configuremos Apacha Spark y Apache Flink, siendo capaces de aislar cada job que remitan los frameworks.
En el anterior articulo configuramos los recursos que un agente expone y que el maestro oferta a los frameworks. En este caso, solo disponemos de una sola gpu y el agente de Apache Mesos la descubre de forma automática, pero que ocurre si disponemos de más gpus y queremos utilizar una en concreto, o dos, o n?
De la ejecución del comando nvidia-smi tomaremos la línea:
0 GeForce GTX 960M Off
Vemos que el id para esta tarjeta es el 0, lo incluimos en las siguientes líneas en la configuración del agente:
#/etc/default/mesos-agent
# Options to pass to mesos-agent
MESOS_AGENT=--hostname=agent4.leonvillamayor.org --ip=192.168.1.200 --log_dir=/var/log/mesos/agent --work_dir=/var/lib/mesos/agent --master=zk://192.168.1.11:2181,192.168.1.12:2181,192.168.1.13:2181/mesos --containerizers=docker,mesos -1-docker=/usr/bin/docker --executor_registration_timeout=10mins --attributes='rack:3;os:ubuntu1804;ip:192.168.1.23' --resources=file:///etc/default/recursos --isolation="filesystem/linux,cgroups/devices,gpu/nvidia" --nvidia_gpu_devices="0"
Ahora incluimos como un recurso más la gpu en el fichero de recursos:
$ cat /etc/default/recursos
[{"name":"cpus","type":"SCALAR","scalar":{"value":2}},{"name":"mem","type":"SCALAR","scalar":{"value":2048}},{"name":"gpus","type":"SCALAR","scalar":{"value":1}}]
Ahora solo nos falta comprobar que todo esta correctamente, ejecutamos el siguiente comando:
$ /opt/mesos/bin/mesos-execute \
--master=zk://192.168.1.11:2181,192.168.1.12:2181,192.168.1.13:2181/mesos \
--name=gpu-test \
--command="nvidia-smi" \
--framework_capabilities="GPU_RESOURCES" \
--resources="gpus:1"
I1228 20:10:26.522105 3956 scheduler.cpp:189] Version: 1.7.0
I1228 20:10:26.522240 3963 scheduler.cpp:355] Using default 'basic' HTTP authenticatee
2018-12-28 20:10:26,522:3956(0x7f55d7744700):ZOO_INFO@log_env@753: Client environment:zookeeper.version=zookeeper C client 3.4.8
2018-12-28 20:10:26,522:3956(0x7f55d7744700):ZOO_INFO@log_env@757: Client environment:host.name=agent4
2018-12-28 20:10:26,522:3956(0x7f55d7744700):ZOO_INFO@log_env@764: Client environment:os.name=Linux
2018-12-28 20:10:26,522:3956(0x7f55d7744700):ZOO_INFO@log_env@765: Client environment:os.arch=4.15.0-34-generic
2018-12-28 20:10:26,522:3956(0x7f55d7744700):ZOO_INFO@log_env@766: Client environment:os.version=#37-Ubuntu SMP Mon Aug 27 15:21:48 UTC 2018
2018-12-28 20:10:26,522:3956(0x7f55d7744700):ZOO_INFO@log_env@774: Client environment:user.name=jleon
2018-12-28 20:10:26,522:3956(0x7f55d7744700):ZOO_INFO@log_env@782: Client environment:user.home=/home/jleon
2018-12-28 20:10:26,522:3956(0x7f55d7744700):ZOO_INFO@log_env@794: Client environment:user.dir=/home/jleon
2018-12-28 20:10:26,522:3956(0x7f55d7744700):ZOO_INFO@zookeeper_init@827: Initiating client connection, host=192.168.1.11:2181,192.168.1.12:2181,192.168.1.13:2181 sessionTimeout=10000 watcher=0x7f55e4448510 sessionId=0 sessionPasswd=<null> context=0x7f55b8001f78 flags=0
2018-12-28 20:10:26,523:3956(0x7f55d3f3d700):ZOO_INFO@check_events@1764: initiated connection to server [192.168.1.11:2181]
2018-12-28 20:10:26,526:3956(0x7f55d3f3d700):ZOO_INFO@check_events@1811: session establishment complete on server [192.168.1.11:2181], sessionId=0x167f4e8609f000f, negotiated timeout=10000
I1228 20:10:26.526281 3958 group.cpp:341] Group process (zookeeper-group(1)@192.168.1.200:42983) connected to ZooKeeper
I1228 20:10:26.526307 3958 group.cpp:831] Syncing group operations: queue size (joins, cancels, datas) = (0, 0, 0)
I1228 20:10:26.526317 3958 group.cpp:419] Trying to create path '/mesos' in ZooKeeper
I1228 20:10:26.527997 3958 detector.cpp:152] Detected a new leader: (id='11')
I1228 20:10:26.528157 3959 group.cpp:700] Trying to get '/mesos/json.info_0000000011' in ZooKeeper
I1228 20:10:26.530999 3959 zookeeper.cpp:262] A new leading master (UPID=master@192.168.1.11:5050) is detected
I1228 20:10:26.531107 3959 scheduler.cpp:538] New master detected at master@192.168.1.11:5050
Subscribed with ID 7d03b8bb-8c65-4cd3-8b3c-d0e13c64be0d-0000
Submitted task 'gpu-test' to agent '7d03b8bb-8c65-4cd3-8b3c-d0e13c64be0d-S1'
Received status update TASK_STARTING for task 'gpu-test'
source: SOURCE_EXECUTOR
Received status update TASK_RUNNING for task 'gpu-test'
source: SOURCE_EXECUTOR
Received status update TASK_FINISHED for task 'gpu-test'
message: 'Command exited with status 0'
source: SOURCE_EXECUTOR
2018-12-28 20:10:26,893:3956(0x7f55e61606c0):ZOO_INFO@zookeeper_close@2562: Closing zookeeper sessionId=0x167f4e8609f000f to [192.168.1.11:2181]
Vemos que la tarea se ha ejecutado correctamente, pero, ¿donde podemos ver el resultado? Basicamente tenemos dos formas, en la propia gui del maestro de Apache Mesos y también revisando la ejecución en el agente. Vamos a por la difícil:
$ cd /var/lib/mesos/agent # Accedemos a la ubicación de ejecuciones del agente
$ cd slaves/7d03b8bb-8c65-4cd3-8b3c-d0e13c64be0d-S1/frameworks/6c9f018b-8049-4fa4-850a-72f52eca936d-0000/executors/gpu-test/runs/latest
# Vamos entrando por las ejecuciones del framework y los executors
$ cat cat stdout
Fri Dec 28 20:46:39 2018
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 390.77 Driver Version: 390.77 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 GeForce GTX 960M Off | 00000000:01:00.0 Off | N/A |
| N/A 44C P8 N/A / N/A | 0MiB / 2004MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+
Como vemos, el comando ha quedado ejecutado correctamente y de paso, comprobamos que todo lo contado sobre el funcionamiento de los agentes es correcto, como la disponibilidad de executors.
Conclusiones
Hemos incluido como recursos las GPU de nvidia, que podemos utilizar no solo para jugar, sino para ejecutar jobs en ellas. Para los que nos dedicamos al mundo datascience, este recurso es muy valioso ya que nos permite entrenar nuestros modelos por su capacidad de paralelización. Adicionalmente, si usamos tensorflow, nos dotará de la capacidad necesaria de proceso si disponemos de varias gpus simplemente indicando cuantas gpus necesitamos (configurarlo en tensorflow directamente con varias máquinas no esta muy conseguido y es un infierno).