Unsere Geschichte begann mit einer scheinbar einfachen Aufgabe. Es war notwendig, Analysewerkzeuge für Data-Science-Spezialisten und nur für Datenanalysten einzurichten. Diese Aufgabe wurde von Kollegen aus den Bereichen Retail Risk und CRM angesprochen, in denen die Konzentration von Data Science-Spezialisten historisch hoch ist. Kunden hatten den einfachen Wunsch, Python-Code zu schreiben, erweiterte Bibliotheken (xgboost, pytorch, tensorflow usw.) zu importieren und Algorithmen für Daten auszuführen, die aus dem hdfs-Cluster stammen.

Alles scheint einfach und klar zu sein. Aber es gab so viele Fallstricke, dass wir beschlossen, einen Beitrag darüber zu schreiben und die fertige Lösung auf GitHub zu veröffentlichen.
Zunächst einige Details zur Quellinfrastruktur:
- HDFS Data Warehouse (12 Oracle Big Data Appliance-Knoten, Cloudera-Distribution). Insgesamt verfügt das Lagerhaus über 130 TB Daten aus verschiedenen internen Systemen der Bank, und es gibt auch heterogene Informationen aus externen Quellen.
- Zwei Anwendungsserver, auf denen die Bereitstellung von Analysetools vorgesehen war. Es ist erwähnenswert, dass sich auf diesen Servern nicht nur erweiterte Analyseaufgaben "drehen". Eine der Anforderungen bestand darin, Containerisierungstools (Docker) zu verwenden, um Serverressourcen zu verwalten, verschiedene Umgebungen zu verwenden und diese zu konfigurieren.
Als Hauptumgebung für die Arbeit von Analysten entschieden sie sich für JupyterHub, das de facto bereits zu einem der Standards für die Arbeit mit Daten und die Entwicklung von Modellen für maschinelles Lernen geworden ist. Lesen Sie
hier mehr darüber. In Zukunft haben wir uns JupyterLab bereits vorgestellt.
Es scheint, dass alles einfach ist: Sie müssen eine Reihe von Python + Anaconda + Spark nehmen und konfigurieren. Installieren Sie Jupyter Hub auf dem Anwendungsserver, integrieren Sie es in LDAP, verbinden Sie Spark oder stellen Sie auf andere Weise eine Verbindung zu HDFS-Daten her und erstellen Sie Modelle!
Wenn Sie sich mit allen Quelldaten und Anforderungen befassen, finden Sie hier eine detailliertere Liste:
- Ausführen von JupyterHub in Docker (Basisbetriebssystem - Oracle Linux 7)
- Cloudera CDH 5.15.1 + Spark 2.3.0-Cluster mit Kerberos-Authentifizierung in Active Directory-Konfiguration + dediziertes Kerberos-MIT im Cluster (siehe Cluster-dediziertes MIT-KDC mit Active Directory ), Oracle Linux 6
- Active Directory-Integration
- Transparente Authentifizierung in Hadoop und Spark
- Python 2 und 3 Unterstützung
- Spark 1 und 2 (mit der Möglichkeit, Clusterressourcen für Trainingsmodelle und die Parallelisierung der Datenverarbeitung mit pyspark zu verwenden)
- Möglichkeit zur Begrenzung der Hostressourcen
- Bibliotheksset
Dieser Beitrag richtet sich an IT-Experten, die solche Probleme lösen müssen.
Lösungsbeschreibung
Starten Sie in Docker + Cloudera Cluster Integration
Hier ist nichts Ungewöhnliches. JupyterHub- und Cloudera-Produktclients werden im Container installiert (siehe unten), und die Konfigurationsdateien werden vom Hostcomputer bereitgestellt:
start-hub.shVOLUMES="-v/var/run/docker.sock:/var/run/docker.sock:Z -v/var/lib/pbis/.lsassd:/var/lib/pbis/.lsassd:Z -v/var/lib/pbis/.netlogond:/var/lib/pbis/.netlogond:Z -v/var/jupyterhub/home:/home/BANK/:Z -v/u00/:/u00/:Z -v/tmp:/host/tmp:Z -v${CONFIG_DIR}/krb5.conf:/etc/krb5.conf:ro -v${CONFIG_DIR}/hadoop/:/etc/hadoop/conf.cloudera.yarn/:ro -v${CONFIG_DIR}/spark/:/etc/spark/conf.cloudera.spark_on_yarn/:ro -v${CONFIG_DIR}/spark2/:/etc/spark2/conf.cloudera.spark2_on_yarn/:ro -v${CONFIG_DIR}/jupyterhub/:/etc/jupyterhub/:ro" docker run -p0.0.0.0:8000:8000/tcp ${VOLUMES} -e VOLUMES="${VOLUMES}" -e HOST_HOSTNAME=`hostname -f` dsai1.2
Active Directory-Integration
Für die Integration mit dem Active Directory / Kerberos-Eisen und nicht sehr Hosts ist der Standard in unserem Unternehmen das Produkt
PBIS Open . Technisch gesehen handelt es sich bei diesem Produkt um eine Reihe von Diensten, die mit Active Directory kommunizieren, mit denen Clients wiederum über Unix-Domain-Sockets arbeiten. Dieses Produkt lässt sich in Linux PAM und NSS integrieren.
Wir haben die Standard-Docker-Methode verwendet - Unix-Domain-Sockets von Host-Diensten wurden in einem Container bereitgestellt (Sockets wurden empirisch durch einfache Manipulationen mit dem Befehl lsof gefunden):
start-hub.sh VOLUMES="-v/var/run/docker.sock:/var/run/docker.sock:Z -v/var/lib/pbis/.lsassd:/var/lib/pbis/.lsassd:Z <b>-v/var/lib/pbis/.netlogond:/var/lib/pbis/.netlogond:Z -v/var/jupyterhub/home:/home/BANK/:Z -v/u00/:/u00/:Z -v/tmp:/host/tmp:Z -v${CONFIG_DIR}/krb5.conf:/etc/krb5.conf:ro </b> -v${CONFIG_DIR}/hadoop/:/etc/hadoop/conf.cloudera.yarn/:ro -v${CONFIG_DIR}/spark/:/etc/spark/conf.cloudera.spark_on_yarn/:ro -v${CONFIG_DIR}/spark2/:/etc/spark2/conf.cloudera.spark2_on_yarn/:ro -v${CONFIG_DIR}/jupyterhub/:/etc/jupyterhub/:ro" docker run -p0.0.0.0:8000:8000/tcp ${VOLUMES} -e VOLUMES="${VOLUMES}" -e HOST_HOSTNAME=`hostname -f` dsai1.2
PBIS-Pakete werden wiederum im Container installiert, ohne jedoch den Abschnitt nach der Installation auszuführen. Wir legen also nur ausführbare Dateien und Bibliotheken ab, starten jedoch keine Dienste im Container - dies ist für uns überflüssig. PAM- und NSS Linux-Integrationsbefehle werden manuell ausgeführt.
Dockerfile: # Install PAM itself and standard PAM configuration packages. RUN yum install -y pam util-linux \ # Here we just download PBIS RPM packages then install them omitting scripts. # We don't need scripts since they start PBIS services, which are not used - we connect to the host services instead. && find /var/yum/localrepo/ -type f -name 'pbis-open*.rpm' | xargs rpm -ivh --noscripts \ # Enable PBIS PAM integration. && domainjoin-cli configure --enable pam \ # Make pam_loginuid.so module optional (Docker requirement) and add pam_mkhomedir.so to have home directories created automatically. && mv /etc/pam.d/login /tmp \ && awk '{ if ($1 == "session" && $2 == "required" && $3 == "pam_loginuid.so") { print "session optional pam_loginuid.so"; print "session required pam_mkhomedir.so skel=/etc/skel/ umask=0022";} else { print $0; } }' /tmp/login > /etc/pam.d/login \ && rm /tmp/login \ # Enable PBIS nss integration. && domainjoin-cli configure --enable nsswitch
Es stellt sich heraus, dass die Clients des PBIS-Containers mit den PBIS-Hostdiensten kommunizieren. JupyterHub verwendet einen PAM-Authentifikator und mit ordnungsgemäß konfiguriertem PBIS auf dem Host funktioniert alles sofort.
Um zu verhindern, dass alle Benutzer von AD JupyterHub betreten, können Sie die Einstellung verwenden, mit der Benutzer auf bestimmte AD-Gruppen beschränkt werden.
config-example / jupyterhub / jupyterhub_config.py c.DSAIAuthenticator.group_whitelist = ['COMPANY\\domain^users']
Transparente Authentifizierung in Hadoop und Spark
Bei der Anmeldung bei JupyterHub speichert PBIS das Kerberos-Ticket des Benutzers in einer bestimmten Datei im Verzeichnis / tmp zwischen. Für eine transparente Authentifizierung auf diese Weise reicht es aus, das Verzeichnis / tmp des Hosts im Container bereitzustellen und die Variable KRB5CCNAME auf den gewünschten Wert zu setzen (dies erfolgt in unserer Authentifizierungsklasse).
start-hub.sh VOLUMES="-v/var/run/docker.sock:/var/run/docker.sock:Z -v/var/lib/pbis/.lsassd:/var/lib/pbis/.lsassd:Z -v/var/lib/pbis/.netlogond:/var/lib/pbis/.netlogond:Z -v/var/jupyterhub/home:/home/BANK/:Z -v/u00/:/u00/:Z -v/tmp:/host/tmp:Z -v${CONFIG_DIR}/krb5.conf:/etc/krb5.conf:ro -v${CONFIG_DIR}/hadoop/:/etc/hadoop/conf.cloudera.yarn/:ro -v${CONFIG_DIR}/spark/:/etc/spark/conf.cloudera.spark_on_yarn/:ro -v${CONFIG_DIR}/spark2/:/etc/spark2/conf.cloudera.spark2_on_yarn/:ro -v${CONFIG_DIR}/jupyterhub/:/etc/jupyterhub/:ro" docker run -p0.0.0.0:8000:8000/tcp ${VOLUMES} -e VOLUMES="${VOLUMES}" -e HOST_HOSTNAME=`hostname -f` dsai1.2
Vermögenswerte / jupyterhub / dsai.py env['KRB5CCNAME'] = '/host/tmp/krb5cc_%d' % pwd.getpwnam(self.user.name).pw_uid
Dank des obigen Codes kann der JupyterHub-Benutzer hdfs-Befehle vom Jupyter-Terminal ausführen und Spark-Jobs ohne zusätzliche Authentifizierungsschritte ausführen. Das Mounten des gesamten / tmp-Verzeichnisses des Hosts in den Container ist unsicher - wir kennen dieses Problem, aber seine Lösung befindet sich noch in der Entwicklung.
Python-Versionen 2 und 3
Hier scheint alles einfach zu sein: Sie müssen die erforderlichen Versionen von Python installieren und in Jupyter integrieren, um den erforderlichen Kernel zu erstellen. Dieses Problem wurde bereits an vielen Stellen behandelt. Conda wird zum Verwalten von Python-Umgebungen verwendet. Warum alle Einfachheit nur offensichtlich ist, wird im nächsten Abschnitt deutlich. Kernel-Beispiel für Python 3.6 (diese Datei ist nicht in Git - alle Kernel-Dateien werden durch Code generiert):
/opt/cloudera/parcels/Anaconda-5.3.1-dsai1.0/envs/python3.6.6/share/jupyter/kernels/python3.6.6/kernel.json { "argv": [ "/opt/cloudera/parcels/Anaconda-5.3.1-dsai1.0/envs/python3.6.6/bin/python", "-m", "ipykernel_launcher", "-f", "{connection_file}" ], "display_name": "Python 3", "language": "python" }
Funke 1 und 2
Zur Integration in SPARK-Clients müssen Sie auch Kernel erstellen. Kernel-Beispiel für Python 3.6 und SPARK 2.
/opt/cloudera/parcels/Anaconda-5.3.1-dsai1.0/envs/python3.6.6/share/jupyter/kernels/python3.6.6-pyspark2/kernel.json { "argv": [ "/opt/cloudera/parcels/Anaconda-5.3.1-dsai1.0/envs/python3.6.6/bin/python", "-m", "ipykernel_launcher", "-f", "{connection_file}" ], "display_name": "Python 3 + PySpark 2", "language": "python", "env": { "JAVA_HOME": "/usr/java/default/", "SPARK_HOME": "/opt/cloudera/parcels/SPARK2/lib/spark2/", "PYTHONSTARTUP": "/opt/cloudera/parcels/SPARK2/lib/spark2/python/pyspark/shell.py", "PYTHONPATH": "/opt/cloudera/parcels/SPARK2/lib/spark2/python/:/opt/cloudera/parcels/SPARK2/lib/spark2/python/lib/py4j-0.10.7-src.zip", "PYSPARK_PYTHON": "/opt/cloudera/parcels/Anaconda-5.3.1-dsai1.0/envs/python3.6.6/bin/python" } }
Beachten Sie nur, dass sich die Anforderung, Spark 1-Unterstützung zu haben, historisch entwickelt hat. Es ist jedoch möglich, dass jemand ähnlichen Einschränkungen ausgesetzt ist. Sie können beispielsweise Spark 2 nicht in einem Cluster installieren. Daher beschreiben wir hier die Fallstricke, denen wir auf dem Weg zur Implementierung begegnet sind.
Erstens
funktioniert Spark 1.6.1
nicht mit Python 3.6. Interessanterweise wurde dies in CDH 5.12.1 behoben, in 5.15.1 jedoch - aus irgendeinem Grund nicht). Zunächst wollten wir dieses Problem lösen, indem wir einfach den entsprechenden Patch anwenden. In Zukunft musste diese Idee jedoch aufgegeben werden, da dieser Ansatz die Installation eines modifizierten Spark in einem Cluster erfordert, was für uns nicht akzeptabel war. Die Lösung wurde beim Erstellen einer separaten Conda-Umgebung mit Python 3.5 gefunden.
Das zweite Problem verhindert, dass Spark 1 in Docker funktioniert. Der Spark-Treiber öffnet einen bestimmten Port, über den Worker eine Verbindung zum Treiber herstellt. Dazu sendet der Treiber ihm seine IP-Adresse. Im Fall von Docker Worker wird versucht, über die IP-Adresse des Containers eine Verbindung zum Treiber herzustellen. Bei Verwendung von network = bridge funktioniert dies nicht ganz natürlich.
Die naheliegende Lösung besteht darin, nicht die IP des Containers zu senden, sondern die IP des Hosts, die in Spark 2 durch Hinzufügen der entsprechenden Konfigurationseinstellungen
implementiert wurde . Dieser Patch wurde kreativ überarbeitet und auf Spark 1 angewendet. Auf diese Weise modifizierter Spark muss nicht auf den Cluster-Hosts platziert werden, sodass es kein Problem gibt, das der Inkompatibilität mit Python 3.6 ähnelt.
Unabhängig von der Version von Spark ist es für die Funktionalität erforderlich, im Cluster dieselben Python-Versionen wie im Container zu haben. Um Anaconda direkt unter Umgehung von Cloudera Manager zu installieren, mussten wir zwei Dinge lernen:
- Bauen Sie Ihr Paket mit Anaconda und den richtigen Umgebungen
- Installieren Sie es in Docker (aus Gründen der Konsistenz)
Montagepaket Anaconda
Dies stellte sich als ziemlich einfache Aufgabe heraus. Alles was Sie brauchen ist:
- Bereiten Sie den Paketinhalt vor, indem Sie die erforderlichen Versionen der Anaconda- und Python-Umgebung installieren
- Erstellen Sie Metadatendateien und legen Sie sie im Meta-Verzeichnis ab
- Erstellen Sie ein Paket mit einfachem Teer
- Überprüfen Sie das Paketdienstprogramm von Cloudera
Der Prozess wird auf
GitHub ausführlicher beschrieben, dort gibt es auch einen Validator-Code. Wir haben Metadaten im offiziellen Anaconda-
Paket für Cloudera ausgeliehen und sie kreativ überarbeitet.
Installieren Sie das Paket in Docker
Diese Praxis hat sich aus zwei Gründen als nützlich erwiesen:
- Sicherstellung der Spark-Funktionsfähigkeit - Es ist unmöglich, Anaconda ohne Paket in einen Cluster zu integrieren
- Spark 2 wird nur in Form von Paketen verteilt - Sie können es natürlich auch in Form von JAR-Dateien in einem Container installieren, aber dieser Ansatz wurde abgelehnt
Als Bonus erhielten wir als Ergebnis der Lösung der oben genannten Probleme:
- Einfache Einrichtung von Hadoop- und Spark-Clients - Wenn Sie dieselben Pakete in Docker und im Cluster installieren, sind die Pfade im Cluster und im Container identisch
- Einfache Aufrechterhaltung einer einheitlichen Umgebung im Container und im Cluster - Beim Aktualisieren des Clusters wird das Docker-Image einfach mit denselben Paketen neu erstellt, die im Cluster installiert wurden.
Um das Paket in Docker zu installieren, wird Cloudera Manager zuerst aus den RPM-Paketen installiert. Für die eigentliche Installation des Pakets wird Java-Code verwendet. Der Client in Java weiß, was der Client in Python nicht kann, daher musste ich Java verwenden und die Einheitlichkeit verlieren, wodurch die API aufgerufen wird.
Assets / Install-Pakete / src / InstallParcels.java ParcelsResourceV5 parcels = clusters.getParcelsResource(clusterName); for (int i = 1; i < args.length; i += 2) { result = installParcel(api, parcels, args[i], args[i + 1], pause); if (!result) { System.exit(1); } }
Einschränkung der Hostressourcen
Zum Verwalten von
Hostcomputerressourcen wird eine Kombination aus
DockerSpawner verwendet - einer Komponente, die Jupyter-Endbenutzer in einem separaten Docker-Container
ausführt - und
cgroups - einem Ressourcenverwaltungsmechanismus unter Linux. DockerSpawner verwendet die Docker-API, mit der Sie die übergeordnete cgroup für den Container festlegen können. Im regulären DockerSpawner gibt es keine solche Möglichkeit. Daher haben wir einfachen Code geschrieben, mit dem wir die Korrespondenz zwischen AD-Entitäten und der übergeordneten cgroup in der Konfiguration festlegen können.
Vermögenswerte / jupyterhub / dsai.py def set_extra_host_config(self): extra_host_config = {} if self.user.name in self.user_cgroup_parent: cgroup_parent = self.user_cgroup_parent[self.user.name] else: pw_name = pwd.getpwnam(self.user.name).pw_name group_found = False for g in grp.getgrall(): if pw_name in g.gr_mem and g.gr_name in self.group_cgroup_parent: cgroup_parent = self.group_cgroup_parent[g.gr_name] group_found = True break if not group_found: cgroup_parent = self.cgroup_parent extra_host_config['cgroup_parent'] = cgroup_parent
Es wurde auch eine kleine Modifikation eingeführt, die Jupyter von demselben Image aus startet, von dem aus JupyterHub gestartet wird. Daher muss nicht mehr als ein Bild verwendet werden.
Vermögenswerte / jupyterhub / dsai.py current_container = None host_name = socket.gethostname() for container in self.client.containers(): if container['Id'][0:12] == host_name: current_container = container break self.image = current_container['Image']
Was genau im Container Jupyter oder JupyterHub ausgeführt werden soll, wird im Startskript durch Umgebungsvariablen bestimmt:
Vermögenswerte / jupyterhub / dsai.py #!/bin/bash ANACONDA_PATH="/opt/cloudera/parcels/Anaconda/" DEFAULT_ENV=`cat ${ANACONDA_PATH}/envs/default` source activate ${DEFAULT_ENV} if [ -z "${JUPYTERHUB_CLIENT_ID}" ]; then while true; do jupyterhub -f /etc/jupyterhub/jupyterhub_config.py done else HOME=`su ${JUPYTERHUB_USER} -c 'echo ~'` cd ~ su ${JUPYTERHUB_USER} -p -c "jupyterhub-singleuser --KernelSpecManager.ensure_native_kernel=False --ip=0.0.0.0" fi
Die Möglichkeit, Jupyter Docker-Container über den JupyterHub Docker-Container zu starten, wird durch das Mounten des Docker-Daemon-Sockets im JupyterHub-Container erreicht.
start-hub.sh VOLUMES="-<b>v/var/run/docker.sock:/var/run/docker.sock:Z -v/var/lib/pbis/.lsassd:/var/lib/pbis/.lsassd:Z</b> -v/var/lib/pbis/.netlogond:/var/lib/pbis/.netlogond:Z -v/var/jupyterhub/home:/home/BANK/:Z -v/u00/:/u00/:Z -v/tmp:/host/tmp:Z -v${CONFIG_DIR}/krb5.conf:/etc/krb5.conf:ro -v${CONFIG_DIR}/hadoop/:/etc/hadoop/conf.cloudera.yarn/:ro -v${CONFIG_DIR}/spark/:/etc/spark/conf.cloudera.spark_on_yarn/:ro -v${CONFIG_DIR}/spark2/:/etc/spark2/conf.cloudera.spark2_on_yarn/:ro -v${CONFIG_DIR}/jupyterhub/:/etc/jupyterhub/:ro" docker run -p0.0.0.0:8000:8000/tcp ${VOLUMES} -e VOLUMES="${VOLUMES}" -e HOST_HOSTNAME=`hostname -f` dsai1.2
In Zukunft ist geplant, diese Entscheidung zugunsten von beispielsweise ssh aufzugeben.
Bei Verwendung von DockerSpawner in Verbindung mit Spark tritt ein weiteres Problem auf: Der Spark-Treiber öffnet zufällige Ports, über die Worker dann eine externe Verbindung herstellen. Wir können den Bereich der Portnummern steuern, aus denen zufällige ausgewählt werden, indem wir diese Bereiche in der Spark-Konfiguration festlegen. Diese Bereiche müssen jedoch für verschiedene Benutzer unterschiedlich sein, da wir keine Jupyter-Container mit denselben veröffentlichten Ports ausführen können. Um dieses Problem zu lösen, wurde Code geschrieben, der einfach Portbereiche anhand der Benutzer-ID aus der JupyterHub-Datenbank generiert und den Docker-Container und Spark mit der entsprechenden Konfiguration startet:
Vermögenswerte / jupyterhub / dsai.py def set_extra_create_kwargs(self): user_spark_driver_port, user_spark_blockmanager_port, user_spark_ui_port, user_spark_max_retries = self.get_spark_ports() if user_spark_driver_port == 0 or user_spark_blockmanager_port == 0 or user_spark_ui_port == 0 or user_spark_max_retries == 0: return ports = {} for p in range(user_spark_driver_port, user_spark_driver_port + user_spark_max_retries): ports['%d/tcp' % p] = None for p in range(user_spark_blockmanager_port, user_spark_blockmanager_port + user_spark_max_retries): ports['%d/tcp' % p] = None for p in range(user_spark_ui_port, user_spark_ui_port + user_spark_max_retries): ports['%d/tcp' % p] = None self.extra_create_kwargs = { 'ports' : ports }
Der Nachteil dieser Lösung ist, dass beim Neustart des Containers mit JupyterHub aufgrund von Datenbankverlust alles nicht mehr funktioniert. Wenn Sie den JupyterHub beispielsweise für eine Konfigurationsänderung neu starten, berühren wir daher nicht den Container selbst, sondern starten nur den darin enthaltenen JupyterHub-Prozess neu.
restart-hub.sh #!/bin/bash docker ps | fgrep 'dsai1.2' | fgrep -v 'jupyter-' | awk '{ print $1; }' | while read ID; do docker exec $ID /bin/bash -c "kill \$( cat /root/jupyterhub.pid )"; done
Cgroups selbst werden von Standard-Linux-Tools erstellt. Die Entsprechung zwischen AD-Entitäten und cgroups in der Konfiguration sieht folgendermaßen aus.
<b>config-example/jupyterhub/jupyterhub_config.py</b> c.DSAISpawner.user_cgroup_parent = { 'bank\\user1' : '/jupyter-cgroup-1', # user 1 'bank\\user2' : '/jupyter-cgroup-1', # user 2 'bank\\user3' : '/jupyter-cgroup-2', # user 3 } c.DSAISpawner.cgroup_parent = '/jupyter-cgroup-3'
Git-Code
Unsere Lösung ist auf GitHub öffentlich verfügbar:
https://github.com/DS-AI/dsai/ (DSAI - Data Science and Artificial Intelligence). Der gesamte Code ist in Verzeichnissen mit Seriennummern angeordnet. Der Code aus jedem nachfolgenden Verzeichnis kann Artefakte aus dem vorherigen verwenden. Das Ergebnis des Codes aus dem letzten Verzeichnis ist ein Docker-Image.
Jedes Verzeichnis enthält Dateien:
- Assets.sh - Erstellung von Artefakten, die für die Montage erforderlich sind (Herunterladen aus dem Internet oder Kopieren aus den Verzeichnissen der vorherigen Schritte)
- build.sh - build
- clean.sh - Reinigungsartefakte, die für die Montage benötigt werden
Um das Docker-Image vollständig neu zu erstellen, müssen clean.sh, assets.sh, build.sh aus den Verzeichnissen entsprechend ihrer Seriennummer ausgeführt werden.
Für die Montage verwenden wir eine Maschine mit Linux RedHat 7.4, Docker 17.05.0-ce. Das Gerät verfügt über 8 Kerne, 32 GB RAM und 250 GB Festplattenspeicher. Es wird dringend empfohlen, keinen Host mit den schlechtesten RAM- und HDD-Einstellungen zum Erstellen zu verwenden.
Hier ist die Hilfe für die verwendeten Namen:
- 01-Spark-Patched - RPM Spark 1.6.1 mit zwei Patches SPARK-4563 und SPARK-19019.
- 02-Validator - Paketvalidator
- 03-anaconda-dsai-parcel-1.0 - Paket Anaconda mit dem richtigen Python (2, 3.5 und 3.6)
- 04-cloudera-manager-api - Cloudera Manager-API-Bibliotheken
- 05-dsai1.2-offline - endgültiges Bild
Leider kann die Assembly aus Gründen abstürzen, die wir nicht beheben konnten (z. B. wird
Teer während der Assembly des Pakets
gelöscht . In diesem Fall müssen Sie die Assembly in der Regel nur neu starten, dies hilft jedoch nicht immer (z. B. hängt die Spark-Assembly von externen Ressourcen ab Cloudera, die möglicherweise nicht mehr verfügbar ist usw.).
Ein weiterer Nachteil ist, dass die Paketmontage nicht reproduzierbar ist. Da Bibliotheken ständig aktualisiert werden, kann die Wiederholung der Assembly zu einem anderen Ergebnis als dem vorherigen führen.
Großes Finale
Jetzt verwenden Benutzer die Tools erfolgreich, ihre Anzahl hat mehrere Dutzend überschritten und wächst weiter. In Zukunft planen wir, JupyterLab auszuprobieren, und überlegen, die GPU mit dem Cluster zu verbinden, da jetzt die Rechenressourcen von zwei ziemlich leistungsfähigen Anwendungsservern nicht mehr ausreichen.