Data Center AutomationTechnologieEinfache Einrichtung von Docker mit Nvidia GPU-Unterstützung durch Ansible

In den vorherigen Datadrivers Artikeln ging es um Analysen und Darstellungen von Daten zu bestimmten Themen, Fakten und Ereignissen. Es wurden verschiedene Modelle und Darstellungsmöglichkeiten aufgezeigt, um die gesammelten Informationen anschaulich und leicht verständlich mit einfachen Mitteln wie Microsoft Power BI oder ähnlichen Tools zu visualisieren. In diesem Artikel widmen wir uns den technischen Aspekten, um Anwendungen innerhalb einer Docker-Container-Umgebung den Zugriff auf die Hardware-Schnittstellen von Nvidia GPUs zu ermöglichen. Durch die zusätzliche Möglichkeit von GPU-Ressourcen über die CUDA-Schnittstelle kann man in gewissen Tools des Machine Learnings wie Tensorflow, xgboost oder ähnlichem, schnellere Auswertungen durch Trainingsmodelle erzielen.

Die Ansteuerung der GPU-Ressourcen erfolgt über eine Schnittstelle von Nvidia, die sogenannte CUDA-Schnittstelle. Durch die CUDA-Schnittstelle werden die Rechenkapazitäten der Grafikkarte (GPU) als Co-Prozessor eingebunden, um so schneller parallele, meist technische Berechnungen zu beschleunigen. Die GPU der Grafikkarte ist wesentlich effektiver und effizienter in der hochgradigen parallelen Verarbeitung von  Berechnungen mit hoher Datenparallelität. Am Ende des Posts werden wir die Vorteile dieser erweiterten Nutzbarkeit von CPU und GPU mit einem einfachen Beispiel und der Gegenüberstellung der Resultate aufzeigen.

Man kann die Bereitstellung der CUDA-Schnittstelle und der entsprechenden Ressourcen auf jeder Maschine, die eine vom CUDA Framework unterstützte Nvidia Grafikkarte besitzt, einrichten. Es ist egal, ob sie physikalisch, paravirtualisiert oder virtualisiert ist. In der Vergangenheit war die Einrichtung und der Betrieb der verschiedenen Treiber und der CUDA-Software als Schnittstelle zwischen Anwendung und GPU sehr aufwendig und man musste jedesmal die kompatiblen Versionen finden und kompilieren. Diese Art der Bereitstellung ist zum aktuellen Zeitpunkt nur auf Unix/Linux-basierenden Systemen nutzbar (kein Windows und MacOS).

In Zeiten der Ressourcen-Teilung durch Virtualisierung und Containerisierung möchte man die GPU-Ressourcen möglichst einfach, schnell und für viele Jobs parallel zur Verfügung stellen. Nvidia veröffentlichte Ende Juni 2016 nvidia-docker. Dies sind vorkompilierte Softwarepakete mit allen notwendigen Bibliotheken und Treibern für den jeweiligen genutzten Nvidia-Treiber, um die Verwendung von CUDA innerhalb des Docker-Daemons und somit auch des Containers zu ermöglichen. Früher war es nötig, komplexe Pfade, Verzeichnisse und Bibliotheken in die Docker Container zu integrieren, was extrem komplex und fehleranfällig war. Mit nvidia-docker wurde eine einfache Integration in Docker angestrebt.

Die nvidia-docker Implementierung unterstützt nur bestimmte Nvidia Treiber- und Docker-Versionen, weshalb man sich dringend vorher auf der Webseite informieren sollte [1] +[2] . In der Version 2 von nvidia-docker wurde die Integration der Komponenten in den Docker Daemon erleichtert und erfolgt durch Einbindung als Docker Runtime. Die genaue, manuelle Installation und Einbindung kann man auf den Wikiseiten des Nvidia-Projektes nachlesen [3] . Aktuell werden offiziell Debian/Ubuntu und CentOS/RHEL-basierende Betriebssysteme in Form von Nvidia-betriebenen Software-Repositories unterstützt. Die Einbindung der Repositories erfolgt über den jeweiligen Softwarepaketmanager und kann auf der offiziellen Seite im Detail nachgeschaut werden [4] .

Aufgrund der vielen einzelnen Schritte und deren Reihenfolge, haben wir eine entsprechende Ansible-Rolle entwickelt, welche uns die Installation für CentOS/RHEL-Systeme erleichtert. Zur Veranschaulichung der Ansible-Rollen-Nutzung wurde zusätzlich ein Ansible Playbook erstellt, was im weiterführendem Beispiel als Referenz genutzt wird.

Die Anwendung dieser Ansible Rolle und die Nutzung zur endgültigen Installation wird im folgenden Beispiel näher dargestellt. Zu finden sind die Ansible Rolle und das Ansible Playbook auf Github im Datadrivers GmbH Bereich unter ansible-role-docker und ansible-playbook-nvidia_gpu_docker_demoZugleich wurde die Ansible Rolle auf der offiziellen Ansible-Galaxy Plattform veröffentlicht [5] .

Am einfachsten und anschaulichsten ist die Nutzung eines in der Cloud gehosteten Systems wie z.B. AWS EC2 Instanzen mit GPUs (Instanzentypen: P2-, P3- und G3-Serie). In unserem Beispiel werden wir die Ansible Demo auf die derzeit kleinsten P2-Instanztyp anwenden.

Am Anfang benötigt man eine laufende AWS P2-Instanz mit einem Standard CentOS 7 Linux als Betriebssystem. Der Zugriff von Ansible erfordert SSH- und sudo-Rechte.

Zur Nutzung der Ansible Demo benötigt man einen Git-Client und ein installiertes Ansible oder einen Ansible-Docker-Container. Die offizielle Installationdokumentation ist unter folgendem Link zu finden: https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html .

Alle Befehle, die in Codeblöcken aufgelistet werden, werden in einem Kommandozeilenfenster ausgeführt.

# Git checkout der Demo-Umgebung
$ git clone https://github.com/datadrivers/ansible-playbook-nvidia_gpu_docker_demo.git
 
# Wechseln in das neue Verzeichnis
cd ansible-playbook-nvidia_gpu_docker_demo
 
# Installation der benötigten Ansible Rolle
$ ansible-galaxy install -v -r requirements.yml

Anschließend muss man noch die Einstellungen in den zwei Dateien group_vars/docker-host und inventory/hosts an das Zielsystem anpassen. Die Aktivierung der Docker-Installation mit GPU-Unterstützung wird durch die Einstellung docker_install_nvidia_docker=true gesteuert. Wenn die Instanzdaten in der Datei inventory/hosts konfiguriert sind, kann man mit dem folgenden Befehl die Ansible Demo starten. Wichtig ist für die Ausführung der SSH-Benutzer und SSH Private Key, damit man sich sicher auf das Zielsystem verbinden kann.

# SSH Benutzer: centos
# Pfad zum SSH Private Key: ~/.ssh/id_rsa
 
# Start der Ansible Demo
$ ansible-playbook demo.yml --user centos --diff -v
 
# Falls der SSH Private Key woanders liegt, sollte man den Pfad zur Datei durch den Parameter --key-fileangeben angeben <Pfad zum SSH Private Key>
$ ansible-playbook demo.yml --user centos --key-file ~/.ssh/id_rsa --diff -v

Im Anschluß wird das Zielsystem am Besten neugestartet, damit alle Dienste mit den neuen Softwarepaketen und Treibern laufen.

# SSH Benutzer: centos
# Pfad zum SSH Private Key: ~/.ssh/id_rsa
 
# Neustart des Zielsystems mit OpenSSH
$ ssh -l centos -i ~/.ssh/id_rsa <IP ADRESSE des Zielsystems> sudo reboot

Wenn das Zielsystem wieder erreichbar ist, kann man sich mit SSH auf das Zielsystem verbinden und einen ersten Test mit einem Docker Container machen, um zu überprüfen, ob alles richtig konfiguriert wurde.

# Anzeige der Hardware- und CUDA Schnittstelle mit nvidia-smi
$ sudo docker run --rm nvidia/cuda nvidia-smi
 
Tue Jul 10 18:35:59 2018
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 390.67                 Driver Version: 390.67                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla K80           Off  | 00000000:00:1E.0 Off |                    0 |
| N/A   36C    P0    75W / 149W |      0MiB / 11441MiB |     94%      Default |
+-------------------------------+----------------------+----------------------+
 
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+

Um z.B. Tensorflow oder xgboost im Docker Container nutzen zu können, müssen alle vorherigen Schritte erfolgreich durchlaufen sein.

Im folgenden Beispiel zeigen wir die Funktionalität mit einem Tensorflow Container mit GPU-Unterstützung und Jupyter Notebook:

# Start eines Tensorflow GPU Containers
$ sudo docker run -it -p 8888:8888 tensorflow/tensorflow:latest-gpu
 
Unable to find image 'tensorflow/tensorflow:latest-gpu' locally
latest-gpu: Pulling from tensorflow/tensorflow
d3938036b19c: Pull complete
a9b30c108bda: Pull complete
67de21feec18: Pull complete
817da545be2b: Pull complete
d967c497ce23: Pull complete
5ddeb439bad8: Pull complete
c6496427ad3b: Pull complete
360fde1360ca: Pull complete
1c3227e49e63: Pull complete
ec2edd14d4b6: Pull complete
96c7a24a6f0c: Pull complete
dee49a23eeb6: Pull complete
3c5ca73fbac5: Pull complete
50f4e1802dc1: Pull complete
316fabb600d5: Pull complete
62c1e601d7a6: Pull complete
Digest: sha256:d31c50ce2d31a21cb5396be59fcab4f8dba405dda2fcaf0f747a407ca277c9f0
Status: Downloaded newer image for tensorflow/tensorflow:latest-gpu
[I 18:38:41.268 NotebookApp] Writing notebook server cookie secret to /root/.local/share/jupyter/runtime/notebook_cookie_secret
[W 18:38:41.284 NotebookApp] WARNING: The notebook server is listening on all IP addresses and not using encryption. This is not recommended.
[I 18:38:41.293 NotebookApp] Serving notebooks from local directory: /notebooks
[I 18:38:41.293 NotebookApp] 0 active kernels
[I 18:38:41.293 NotebookApp] The Jupyter Notebook is running at:
[I 18:38:41.293 NotebookApp] http://[all ip addresses on your system]:8888/?token=625558795203ba2463ab39ac410566041b19ad5ea2fc307d
[I 18:38:41.293 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 18:38:41.293 NotebookApp]
 
    Copy/paste this URL into your browser when you connect for the first time,
    to login with a token:
        http://localhost:8888/?token=625558795203ba2463ab39ac410566041b19ad5ea2fc307d

Danach kann man mit seinem Browser auf den Tensorflow Container verbinden und im Jupyter Notebook einige Testabfragen vornehmen.

 http://<IP ADRESSE des Zielsystems>:8888

Dieses Beispiel ist ein Benchmark zwischen CPU- und GPU-Processing, um die Vorteile der GPU-Unterstützung schnell sichtbar zu machen. Der Benchmark stammt von http://learningtensorflow.com/.
Das Skript muss auf das Zielsystem kopiert oder per wget oder curl direkt heruntergeladen werden.

# Download mit curl auf dem Zielsystem
$ curl https://raw.githubusercontent.com/datadrivers/ansible-playbook-nvidia_gpu_docker_demo/master/benchmark.py -O
 
# Setzen des Executable-Flags
$ chmod +x benchmark.py

benchmark.py

import sys
import numpy as np
import tensorflow as tf
from datetime import datetime
 
device_name = sys.argv[1]  # Choose device from cmd line. Options: gpu or cpu
shape = (int(sys.argv[2]), int(sys.argv[2]))
if device_name == "gpu":
    device_name = "/gpu:0"
else:
    device_name = "/cpu:0"
 
with tf.device(device_name):
    random_matrix = tf.random_uniform(shape=shape, minval=0, maxval=1)
    dot_operation = tf.matmul(random_matrix, tf.transpose(random_matrix))
    sum_operation = tf.reduce_sum(dot_operation)
 
startTime = datetime.now()
with tf.Session(config=tf.ConfigProto(log_device_placement=True)) as session:
        result = session.run(sum_operation)
        print(result)
 
# It can be hard to see the results on the terminal with lots of output -- add some newlines to improve readability.
print("\n" * 5)
print("Shape:", shape, "Device:", device_name)
print("Time taken:", str(datetime.now() - startTime))

Der Vergleich zwischen CPU und GPU mithilfe des Benchmark-Skript benchmark.py:

CPU Benchmark

# Skript mit CPU:
$ sudo docker run --rm -ti -v "${PWD}:/app" tensorflow/tensorflow:latest-gpu python /app/benchmark.py cpu 10000
...
..
.
2018-07-10 19:01:26.900157: I tensorflow/core/common_runtime/placer.cc:886] random_uniform/min: (Const)/job:localhost/replica:0/task:0/device:CPU:0
random_uniform/shape: (Const): /job:localhost/replica:0/task:0/device:CPU:0
2018-07-10 19:01:26.900179: I tensorflow/core/common_runtime/placer.cc:886] random_uniform/shape: (Const)/job:localhost/replica:0/task:0/device:CPU:0
254409180000.0
 
('Shape:', (10000, 10000), 'Device:', '/cpu:0')
('Time taken:', '0:00:28.707561') 

GPU Benchmark

 # Skript mit GPU:
$ sudo docker run --rm -ti -v "${PWD}:/app" tensorflow/tensorflow:latest-gpu python /app/benchmark.py gpu 10000
...
..
.
2018-07-10 19:03:07.362865: I tensorflow/core/common_runtime/placer.cc:886] random_uniform/min: (Const)/job:localhost/replica:0/task:0/device:GPU:0
random_uniform/shape: (Const): /job:localhost/replica:0/task:0/device:GPU:0
2018-07-10 19:03:07.362880: I tensorflow/core/common_runtime/placer.cc:886] random_uniform/shape: (Const)/job:localhost/replica:0/task:0/device:GPU:0
249999210000.0
 
('Shape:', (10000, 10000), 'Device:', '/gpu:0')
('Time taken:', '0:00:04.274232') 

Die Ergebnisse belegen eindrucksvoll den Vorteil der Berechnung mit GPU Unterstützung (4 Sekunden) gegenüber der CPU (28 Sekunden). Die parallele Verarbeitung von komplexen, großen Datenmengen mit einer hohen Datendichte ist einer der Vorteile der GPU-Berechnungen. Ein Einsatzszenario ist das Trainieren von neuronalen Netzen im Machine Learning. In der Regel ist die Verarbeitung von großen Datenmengen mit der GPU schneller, da die GPU größere Mengen an Daten parallel verarbeiten kann.

Sie sehen, dass der Installationsprozess mithilfe von Ansible, um einiges einfacher, schneller und reproduzierbarer ist. Auf der jetzt bereitstehenden Docker-Umgebung können Data-Analysten ihre Trainingsmodelle konzipieren und trainieren.

Im folgenden Blogartikel werden unsere Data Scientists die GPU Beschleunigung ausnutzen, um mit dem Tensorflow Back-End einen auf Deep Learning basierten Recommender zu entwerfen.

Links:

[1] https://github.com/NVIDIA/nvidia-docker/wiki/Frequently-Asked-Questions#which-docker-packages-are-supported

[2] https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#pre-installation-actions

[3] https://github.com/NVIDIA/nvidia-docker/wiki/Installation-(version-2.0)#prerequisites

[4] https://github.com/NVIDIA/nvidia-docker#quickstart

[5] https://galaxy.ansible.com/datadrivers/datadrivers_docker

    © 2022 DATADRIVERS GMBH. Alle Rechte vorbehalten.

    © 2021 DATADRIVERS GMBH. Alle Rechte vorbehalten.