ЗапускаСм Apache Spark Π½Π° Kubernetes

Π”ΠΎΡ€ΠΎΠ³ΠΈΠ΅ Ρ‡ΠΈΡ‚Π°Ρ‚Π΅Π»ΠΈ, Π΄ΠΎΠ±Ρ€ΠΎΠ³ΠΎ дня. БСгодня ΠΏΠΎΠ³ΠΎΠ²ΠΎΡ€ΠΈΠΌ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ ΠΏΡ€ΠΎ Apache Spark ΠΈ Π΅Π³ΠΎ пСрспСктивы развития.

ЗапускаСм Apache Spark Π½Π° Kubernetes

Π’ соврСмСнном ΠΌΠΈΡ€Π΅ Big Data Apache Spark являСтся Π΄Π΅ Ρ„Π°ΠΊΡ‚ΠΎ стандартом ΠΏΡ€ΠΈ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ΅ Π·Π°Π΄Π°Ρ‡ ΠΏΠ°ΠΊΠ΅Ρ‚Π½ΠΎΠΉ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Π΄Π°Π½Π½Ρ‹Ρ…. Помимо этого, ΠΎΠ½ Ρ‚Π°ΠΊΠΆΠ΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для создания стриминговых ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ, Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‰ΠΈΡ… Π² ΠΊΠΎΠ½Ρ†Π΅ΠΏΡ†ΠΈΠΈ micro batch, ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°ΡŽΡ‰ΠΈΡ… ΠΈ ΠΎΡ‚Π³Ρ€ΡƒΠΆΠ°ΡŽΡ‰ΠΈΡ… Π΄Π°Π½Π½Ρ‹Π΅ малСнькими порциями (Spark Structured Streaming). И Ρ‚Ρ€Π°Π΄ΠΈΡ†ΠΈΠΎΠ½Π½ΠΎ ΠΎΠ½ являлся Ρ‡Π°ΡΡ‚ΡŒΡŽ ΠΎΠ±Ρ‰Π΅Π³ΠΎ стСка Hadoop, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ Π² качСствС ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€Π° рСсурсов YARN (ΠΈΠ»ΠΈ, Π² Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… случаях, Apache Mesos). К 2020 Π³ΠΎΠ΄Ρƒ Π΅Π³ΠΎ использованиС Π² Ρ‚Ρ€Π°Π΄ΠΈΡ†ΠΈΠΎΠ½Π½ΠΎΠΌ Π²ΠΈΠ΄Π΅ для Π±ΠΎΠ»ΡŒΡˆΠΈΠ½ΡΡ‚Π²Π° ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΉ находится ΠΏΠΎΠ΄ большим вопросом Π² Π²ΠΈΠ΄Ρƒ отсутствия ΠΏΡ€ΠΈΠ»ΠΈΡ‡Π½Ρ‹Ρ… дистрибутивов Hadoop β€” Ρ€Π°Π·Π²ΠΈΡ‚ΠΈΠ΅ HDP ΠΈ CDH остановлСно, CDH нСдостаточно ΠΏΡ€ΠΎΡ€Π°Π±ΠΎΡ‚Π°Π½ ΠΈ ΠΈΠΌΠ΅Π΅Ρ‚ Π²Ρ‹ΡΠΎΠΊΡƒΡŽ ΡΡ‚ΠΎΠΈΠΌΠΎΡΡ‚ΡŒ, Π° ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ поставщики Hadoop Π»ΠΈΠ±ΠΎ ΠΏΡ€Π΅ΠΊΡ€Π°Ρ‚ΠΈΠ»ΠΈ своё сущСствованиС, Π»ΠΈΠ±ΠΎ ΠΈΠΌΠ΅ΡŽΡ‚ Ρ‚ΡƒΠΌΠ°Π½Π½ΠΎΠ΅ Π±ΡƒΠ΄ΡƒΡ‰Π΅Π΅. ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ всё больший интСрСс Ρƒ сообщСства ΠΈ ΠΊΡ€ΡƒΠΏΠ½Ρ‹Ρ… ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΉ Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ запуск Apache Spark с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Kubernetes β€” став стандартом Π² оркСстрации ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ΠΎΠ² ΠΈ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠΈ рСсурсами Π² ΠΏΡ€ΠΈΠ²Π°Ρ‚Π½Ρ‹Ρ… ΠΈ ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹Ρ… ΠΎΠ±Π»Π°ΠΊΠ°Ρ…, ΠΎΠ½ Ρ€Π΅ΡˆΠ°Π΅Ρ‚ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ с Π½Π΅ΡƒΠ΄ΠΎΠ±Π½Ρ‹ΠΌ ΠΏΠ»Π°Π½ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ рСсурсов Π·Π°Π΄Π°Ρ‡ Spark Π½Π° YARN ΠΈ прСдоставляСт ΡΡ‚Π°Π±ΠΈΠ»ΡŒΠ½ΠΎ Ρ€Π°Π·Π²ΠΈΠ²Π°ΡŽΡ‰ΡƒΡŽΡΡ ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΡƒ с мноТСством коммСрчСских ΠΈ ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚Ρ‹Ρ… дистрибутивов для ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΉ всСх Ρ€Π°Π·ΠΌΠ΅Ρ€ΠΎΠ² ΠΈ мастСй. К Ρ‚ΠΎΠΌΡƒ ΠΆΠ΅ Π½Π° Π²ΠΎΠ»Π½Π΅ популярности Π±ΠΎΠ»ΡŒΡˆΠΈΠ½ΡΡ‚Π²ΠΎ ΡƒΠΆΠ΅ успСло ΠΎΠ±Π·Π°Π²Π΅ΡΡ‚ΠΈΡΡŒ ΠΏΠ°Ρ€ΠΎΠΉ-Ρ‚Ρ€ΠΎΠΉΠΊΠΎΠΉ своих инсталляций ΠΈ Π½Π°Ρ€Π°ΡΡ‚ΠΈΡ‚ΡŒ экспСртизу Π² Π΅Π³ΠΎ использовании, Ρ‡Ρ‚ΠΎ ΡƒΠΏΡ€ΠΎΡ‰Π°Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π΅Π·Π΄.

Начиная с вСрсии 2.3.0 Apache Spark обзавёлся ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠΉ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΎΠΉ запуска Π·Π°Π΄Π°Ρ‡ Π² кластСрС Kubernetes ΠΈ сСгодня, ΠΌΡ‹ ΠΏΠΎΠ³ΠΎΠ²ΠΎΡ€ΠΈΠΌ ΠΎ Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ зрСлости Π΄Π°Π½Π½ΠΎΠ³ΠΎ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Π°, Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Ρ… Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Π°Ρ… Π΅Π³ΠΎ использования ΠΈ ΠΏΠΎΠ΄Π²ΠΎΠ΄Π½Ρ‹Ρ… камнях, с ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌΠΈ прСдстоит ΡΡ‚ΠΎΠ»ΠΊΠ½ΡƒΡ‚ΡŒΡΡ ΠΏΡ€ΠΈ Π²Π½Π΅Π΄Ρ€Π΅Π½ΠΈΠΈ.

ΠŸΡ€Π΅ΠΆΠ΄Π΅ всСго, рассмотрим процСсс Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Π·Π°Π΄Π°Ρ‡ ΠΈ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Π½Π° Π±Π°Π·Π΅ Apache Spark ΠΈ Π²Ρ‹Π΄Π΅Π»ΠΈΠΌ Ρ‚ΠΈΠΏΠΎΠ²Ρ‹Π΅ случаи, Π² ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… трСбуСтся Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ Π·Π°Π΄Π°Ρ‡Ρƒ Π½Π° кластСрС Kubernetes. ΠŸΡ€ΠΈ ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΊΠ΅ Π΄Π°Π½Π½ΠΎΠ³ΠΎ поста Π² качСствС дистрибутива ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ OpenShift ΠΈ Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Ρ‹ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹, Π°ΠΊΡ‚ΡƒΠ°Π»ΡŒΠ½Ρ‹Π΅ для Π΅Π³ΠΎ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹ ΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΎΠΉ строки (oc). Для Π΄Ρ€ΡƒΠ³ΠΈΡ… дистрибутивов Kubernetes ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Π½Ρ‹ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ стандартной ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹ ΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΎΠΉ строки Kubernetes (kubectl) Π»ΠΈΠ±ΠΎ ΠΈΡ… Π°Π½Π°Π»ΠΎΠ³ΠΈ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, для oc adm policy).

ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ использования β€” spark-submit

Π’ процСссС Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Π·Π°Π΄Π°Ρ‡ ΠΈ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΡƒ трСбуСтся Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ Π·Π°Π΄Π°Ρ‡ΠΈ для ΠΎΡ‚Π»Π°Π΄ΠΊΠΈ трансформации Π΄Π°Π½Π½Ρ‹Ρ…. ВСорСтичСски для этих Ρ†Π΅Π»Π΅ΠΉ ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Π½Ρ‹ Π·Π°Π³Π»ΡƒΡˆΠΊΠΈ, Π½ΠΎ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° с участиСм Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹Ρ… (ΠΏΡƒΡΡ‚ΡŒ ΠΈ тСстовых) экзСмпляров ΠΊΠΎΠ½Π΅Ρ‡Π½Ρ‹Ρ… систСм, ΠΏΠΎΠΊΠ°Π·Π°Π»Π° сСбя Π² этом классС Π·Π°Π΄Π°Ρ‡ быстрСС ΠΈ качСствСннСС. Π’ Ρ‚ΠΎΠΌ случаС, ΠΊΠΎΠ³Π΄Π° ΠΌΡ‹ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΠΌ ΠΎΡ‚Π»Π°Π΄ΠΊΡƒ Π½Π° Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹Ρ… экзСмплярах ΠΊΠΎΠ½Π΅Ρ‡Π½Ρ‹Ρ… систСм, Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ‹ Π΄Π²Π° сцСнария Ρ€Π°Π±ΠΎΡ‚Ρ‹:

  • Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ запускаСт Π·Π°Π΄Π°Ρ‡Ρƒ Spark локально Π² Ρ€Π΅ΠΆΠΈΠΌΠ΅ standalone;

    ЗапускаСм Apache Spark Π½Π° Kubernetes

  • Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ запускаСт Π·Π°Π΄Π°Ρ‡Ρƒ Spark Π½Π° кластСрС Kubernetes Π² тСстовом ΠΊΠΎΠ½Ρ‚ΡƒΡ€Π΅.

    ЗапускаСм Apache Spark Π½Π° Kubernetes

ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ ΠΈΠΌΠ΅Π΅Ρ‚ ΠΏΡ€Π°Π²ΠΎ Π½Π° сущСствованиС, Π½ΠΎ Π²Π»Π΅Ρ‡Ρ‘Ρ‚ Π·Π° собой ряд нСдостатков:

  • для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ° трСбуСтся ΠΎΠ±Π΅ΡΠΏΠ΅Ρ‡ΠΈΡ‚ΡŒ доступ с Ρ€Π°Π±ΠΎΡ‡Π΅Π³ΠΎ мСста Π΄ΠΎ всСх Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Ρ… Π΅ΠΌΡƒ экзСмпляров ΠΊΠΎΠ½Π΅Ρ‡Π½Ρ‹Ρ… систСм;
  • Π½Π° Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ машинС трСбуСтся достаточноС количСство рСсурсов для запуска Ρ€Π°Π·Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅ΠΌΠΎΠΉ Π·Π°Π΄Π°Ρ‡ΠΈ.

Π’Ρ‚ΠΎΡ€ΠΎΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ Π»ΠΈΡˆΡ‘Π½ Π΄Π°Π½Π½Ρ‹Ρ… нСдостатков, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ использованиС кластСра Kubernetes позволяСт Π²Ρ‹Π΄Π΅Π»ΠΈΡ‚ΡŒ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹ΠΉ ΠΏΡƒΠ» рСсурсов для запуска Π·Π°Π΄Π°Ρ‡ ΠΈ ΠΎΠ±Π΅ΡΠΏΠ΅Ρ‡ΠΈΡ‚ΡŒ для Π½Π΅Π³ΠΎ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ доступы ΠΊ экзСмплярам ΠΊΠΎΠ½Π΅Ρ‡Π½Ρ‹Ρ… систСм, Π³ΠΈΠ±ΠΊΠΎ прСдоставляя ΠΊ Π½Π΅ΠΌΡƒ доступ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Ρ€ΠΎΠ»Π΅Π²ΠΎΠΉ ΠΌΠΎΠ΄Π΅Π»ΠΈ Kubernetes для всСх Ρ‡Π»Π΅Π½ΠΎΠ² ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ. Π’Ρ‹Π΄Π΅Π»ΠΈΠΌ Π΅Π³ΠΎ Π² качСствС ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Π° использования β€” запуск Π·Π°Π΄Π°Ρ‡ Spark с локальной ΠΌΠ°ΡˆΠΈΠ½Ρ‹ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ° Π½Π° кластСрС Kubernetes Π² тСстовом ΠΊΠΎΠ½Ρ‚ΡƒΡ€Π΅.

РасскаТСм ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½Π΅Π΅ ΠΎ процСссС настройки Spark для локального запуска. Π§Ρ‚ΠΎΠ±Ρ‹ Π½Π°Ρ‡Π°Ρ‚ΡŒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ Spark Π΅Π³ΠΎ трСбуСтся ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ:

mkdir /opt/spark
cd /opt/spark
wget http://mirror.linux-ia64.org/apache/spark/spark-2.4.5/spark-2.4.5.tgz
tar zxvf spark-2.4.5.tgz
rm -f spark-2.4.5.tgz

Π‘ΠΎΠ±ΠΈΡ€Π°Π΅ΠΌ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ ΠΏΠ°ΠΊΠ΅Ρ‚Ρ‹ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с Kubernetes:

cd spark-2.4.5/
./build/mvn -Pkubernetes -DskipTests clean package

Полная сборка Π·Π°Π½ΠΈΠΌΠ°Π΅Ρ‚ ΠΌΠ½ΠΎΠ³ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ, Π° для создания ΠΎΠ±Ρ€Π°Π·ΠΎΠ² Docker ΠΈ ΠΈΡ… запуска Π½Π° кластСрС Kubernetes Π² Ρ€Π΅Π°Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ Π½ΡƒΠΆΠ½Ρ‹ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ jar Ρ„Π°ΠΉΠ»Ρ‹ ΠΈΠ· Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ Β«assembly/Β», поэтому ΠΌΠΎΠΆΠ½ΠΎ ΡΠΎΠ±Ρ€Π°Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π΄Π°Π½Π½Ρ‹ΠΉ ΠΏΠΎΠ΄ΠΏΡ€ΠΎΠ΅ΠΊΡ‚:

./build/mvn -f ./assembly/pom.xml -Pkubernetes -DskipTests clean package

Для запуска Π·Π°Π΄Π°Ρ‡ Spark Π² Kubernetes трСбуСтся ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΎΠ±Ρ€Π°Π· Docker, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ Π² качСствС Π±Π°Π·ΠΎΠ²ΠΎΠ³ΠΎ. Π—Π΄Π΅ΡΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ‹ 2 ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Π°:

  • Π‘ΠΎΠ·Π΄Π°Π½Π½Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π· Docker Π²ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ Π² сСбя исполняСмый ΠΊΠΎΠ΄ Π·Π°Π΄Π°Ρ‡ΠΈ Spark;
  • Π‘ΠΎΠ·Π΄Π°Π½Π½Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π· Π²ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ Π² сСбя Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Spark ΠΈ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ зависимости, исполняСмый ΠΊΠΎΠ΄ размСщаСтся ΡƒΠ΄Π°Π»Ρ‘Π½Π½ΠΎ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π² HDFS).

Для Π½Π°Ρ‡Π°Π»Π° собСрём ΠΎΠ±Ρ€Π°Π· Docker, содСрТащий тСстовый ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π·Π°Π΄Π°Ρ‡ΠΈ Spark. Для создания ΠΎΠ±Ρ€Π°Π·ΠΎΠ² Docker Ρƒ Spark Π΅ΡΡ‚ΡŒ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π°Ρ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Π° ΠΏΠΎΠ΄ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ Β«docker-image-toolΒ». Π˜Π·ΡƒΡ‡ΠΈΠΌ ΠΏΠΎ Π½Π΅ΠΉ справку:

./bin/docker-image-tool.sh --help

Π‘ Π΅Ρ‘ ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΌΠΎΠΆΠ½ΠΎ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΎΠ±Ρ€Π°Π·Ρ‹ Docker ΠΈ ΠΎΡΡƒΡ‰Π΅ΡΡ‚Π²Π»ΡΡ‚ΡŒ ΠΈΡ… Π·Π°Π³Ρ€ΡƒΠ·ΠΊΡƒ Π² ΡƒΠ΄Π°Π»Ρ‘Π½Π½Ρ‹Π΅ рССстры, Π½ΠΎ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ ΠΎΠ½Π° ΠΈΠΌΠ΅Π΅Ρ‚ ряд нСдостатков:

  • Π² ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΠΌ порядкС создаёт сразу 3 ΠΎΠ±Ρ€Π°Π·Π° Docker β€” ΠΏΠΎΠ΄ Spark, PySpark ΠΈ R;
  • Π½Π΅ позволяСт ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ имя ΠΎΠ±Ρ€Π°Π·Π°.

ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΌΠΎΠ΄ΠΈΡ„ΠΈΡ†ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ Π΄Π°Π½Π½ΠΎΠΉ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹, ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Π½Π½Ρ‹ΠΉ Π½ΠΈΠΆΠ΅:

vi bin/docker-image-tool-upd.sh

#!/usr/bin/env bash

function error {
  echo "$@" 1>&2
  exit 1
}

if [ -z "${SPARK_HOME}" ]; then
  SPARK_HOME="$(cd "`dirname "$0"`"/..; pwd)"
fi
. "${SPARK_HOME}/bin/load-spark-env.sh"

function image_ref {
  local image="$1"
  local add_repo="${2:-1}"
  if [ $add_repo = 1 ] && [ -n "$REPO" ]; then
    image="$REPO/$image"
  fi
  if [ -n "$TAG" ]; then
    image="$image:$TAG"
  fi
  echo "$image"
}

function build {
  local BUILD_ARGS
  local IMG_PATH

  if [ ! -f "$SPARK_HOME/RELEASE" ]; then
    IMG_PATH=$BASEDOCKERFILE
    BUILD_ARGS=(
      ${BUILD_PARAMS}
      --build-arg
      img_path=$IMG_PATH
      --build-arg
      datagram_jars=datagram/runtimelibs
      --build-arg
      spark_jars=assembly/target/scala-$SPARK_SCALA_VERSION/jars
    )
  else
    IMG_PATH="kubernetes/dockerfiles"
    BUILD_ARGS=(${BUILD_PARAMS})
  fi

  if [ -z "$IMG_PATH" ]; then
    error "Cannot find docker image. This script must be run from a runnable distribution of Apache Spark."
  fi

  if [ -z "$IMAGE_REF" ]; then
    error "Cannot find docker image reference. Please add -i arg."
  fi

  local BINDING_BUILD_ARGS=(
    ${BUILD_PARAMS}
    --build-arg
    base_img=$(image_ref $IMAGE_REF)
  )
  local BASEDOCKERFILE=${BASEDOCKERFILE:-"$IMG_PATH/spark/docker/Dockerfile"}

  docker build $NOCACHEARG "${BUILD_ARGS[@]}" 
    -t $(image_ref $IMAGE_REF) 
    -f "$BASEDOCKERFILE" .
}

function push {
  docker push "$(image_ref $IMAGE_REF)"
}

function usage {
  cat <<EOF
Usage: $0 [options] [command]
Builds or pushes the built-in Spark Docker image.

Commands:
  build       Build image. Requires a repository address to be provided if the image will be
              pushed to a different registry.
  push        Push a pre-built image to a registry. Requires a repository address to be provided.

Options:
  -f file               Dockerfile to build for JVM based Jobs. By default builds the Dockerfile shipped with Spark.
  -p file               Dockerfile to build for PySpark Jobs. Builds Python dependencies and ships with Spark.
  -R file               Dockerfile to build for SparkR Jobs. Builds R dependencies and ships with Spark.
  -r repo               Repository address.
  -i name               Image name to apply to the built image, or to identify the image to be pushed.  
  -t tag                Tag to apply to the built image, or to identify the image to be pushed.
  -m                    Use minikube's Docker daemon.
  -n                    Build docker image with --no-cache
  -b arg      Build arg to build or push the image. For multiple build args, this option needs to
              be used separately for each build arg.

Using minikube when building images will do so directly into minikube's Docker daemon.
There is no need to push the images into minikube in that case, they'll be automatically
available when running applications inside the minikube cluster.

Check the following documentation for more information on using the minikube Docker daemon:

  https://kubernetes.io/docs/getting-started-guides/minikube/#reusing-the-docker-daemon

Examples:
  - Build image in minikube with tag "testing"
    $0 -m -t testing build

  - Build and push image with tag "v2.3.0" to docker.io/myrepo
    $0 -r docker.io/myrepo -t v2.3.0 build
    $0 -r docker.io/myrepo -t v2.3.0 push
EOF
}

if [[ "$@" = *--help ]] || [[ "$@" = *-h ]]; then
  usage
  exit 0
fi

REPO=
TAG=
BASEDOCKERFILE=
NOCACHEARG=
BUILD_PARAMS=
IMAGE_REF=
while getopts f:mr:t:nb:i: option
do
 case "${option}"
 in
 f) BASEDOCKERFILE=${OPTARG};;
 r) REPO=${OPTARG};;
 t) TAG=${OPTARG};;
 n) NOCACHEARG="--no-cache";;
 i) IMAGE_REF=${OPTARG};;
 b) BUILD_PARAMS=${BUILD_PARAMS}" --build-arg "${OPTARG};;
 esac
done

case "${@: -1}" in
  build)
    build
    ;;
  push)
    if [ -z "$REPO" ]; then
      usage
      exit 1
    fi
    push
    ;;
  *)
    usage
    exit 1
    ;;
esac

Π‘ Π΅Ρ‘ ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ собираСм Π±Π°Π·ΠΎΠ²Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π· Spark, содСрТащий Π² сСбС Ρ‚Π΅ΡΡ‚ΠΎΠ²ΡƒΡŽ Π·Π°Π΄Π°Ρ‡Ρƒ для вычислСния числа Pi с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Spark (здСсь {docker-registry-url} β€” URL вашСго рССстра ΠΎΠ±Ρ€Π°Π·ΠΎΠ² Docker, {repo} β€” имя рСпозитория Π²Π½ΡƒΡ‚Ρ€ΠΈ рССстра, ΡΠΎΠ²ΠΏΠ°Π΄Π°ΡŽΡ‰Π΅Π΅ с ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΎΠΌ Π² OpenShift, {image-name} β€” имя ΠΎΠ±Ρ€Π°Π·Π° (Ссли ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Ρ‚Ρ€Ρ‘Ρ…ΡƒΡ€ΠΎΠ²Π½Π΅Π²ΠΎΠ΅ Ρ€Π°Π·Π΄Π΅Π»Π΅Π½ΠΈΠ΅ ΠΎΠ±Ρ€Π°Π·ΠΎΠ², Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΊΠ°ΠΊ Π² ΠΈΠ½Ρ‚Π΅Π³Ρ€ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠΌ рССстрС ΠΎΠ±Ρ€Π°Π·ΠΎΠ² Red Hat OpenShift), {tag} β€” Ρ‚Π΅Π³ Π΄Π°Π½Π½ΠΎΠΉ вСрсии ΠΎΠ±Ρ€Π°Π·Π°):

./bin/docker-image-tool-upd.sh -f resource-managers/kubernetes/docker/src/main/dockerfiles/spark/Dockerfile -r {docker-registry-url}/{repo} -i {image-name} -t {tag} build

АвторизуСмся Π² кластСрС OKD с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ консольной ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹ (здСсь {OKD-API-URL} β€” URL API кластСра OKD):

oc login {OKD-API-URL}

ΠŸΠΎΠ»ΡƒΡ‡ΠΈΠΌ Ρ‚ΠΎΠΊΠ΅Π½ Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ для Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ Π² Docker Registry:

oc whoami -t

АвторизуСмся Π²ΠΎ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½Π΅ΠΌ Docker Registry кластСра OKD (Π² качСствС пароля ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Ρ‚ΠΎΠΊΠ΅Π½, ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½Ρ‹ΠΉ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅ΠΉ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹):

docker login {docker-registry-url}

Π—Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ собранный ΠΎΠ±Ρ€Π°Π· Docker Π² Docker Registry OKD:

./bin/docker-image-tool-upd.sh -r {docker-registry-url}/{repo} -i {image-name} -t {tag} push

ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΈΠΌ, Ρ‡Ρ‚ΠΎ собранный ΠΎΠ±Ρ€Π°Π· доступСн Π² OKD. Для этого ΠΎΡ‚ΠΊΡ€ΠΎΠ΅ΠΌ Π² Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π΅ URL со списком ΠΎΠ±Ρ€Π°Π·ΠΎΠ² ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π΅Π³ΠΎ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° (здСсь {project} β€” имя ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° Π²Π½ΡƒΡ‚Ρ€ΠΈ кластСра OpenShift, {OKD-WEBUI-URL} β€” URL Web консоли OpenShift) β€” https://{OKD-WEBUI-URL}/console/project/{project}/browse/images/{image-name}.

Для запуска Π·Π°Π΄Π°Ρ‡ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ создан сСрвисный Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ с привилСгиями запуска ΠΏΠΎΠ΄ΠΎΠ² ΠΏΠΎΠ΄ root (Π² дальнСйшСм обсудим этот ΠΌΠΎΠΌΠ΅Π½Ρ‚):

oc create sa spark -n {project}
oc adm policy add-scc-to-user anyuid -z spark -n {project}

Π’Ρ‹ΠΏΠΎΠ»Π½ΠΈΠΌ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ spark-submit для ΠΏΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΠΈ Π·Π°Π΄Π°Ρ‡ΠΈ Spark Π² кластСрС OKD, ΡƒΠΊΠ°Π·Π°Π² созданный сСрвисный Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ ΠΈ ΠΎΠ±Ρ€Π°Π· Docker:

 /opt/spark/bin/spark-submit --name spark-test --class org.apache.spark.examples.SparkPi --conf spark.executor.instances=3 --conf spark.kubernetes.authenticate.driver.serviceAccountName=spark --conf spark.kubernetes.namespace={project} --conf spark.submit.deployMode=cluster --conf spark.kubernetes.container.image={docker-registry-url}/{repo}/{image-name}:{tag} --conf spark.master=k8s://https://{OKD-API-URL}  local:///opt/spark/examples/target/scala-2.11/jars/spark-examples_2.11-2.4.5.jar

Π—Π΄Π΅ΡΡŒ:

—name β€” имя Π·Π°Π΄Π°Ρ‡ΠΈ, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ ΡƒΡ‡Π°ΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ Π² Ρ„ΠΎΡ€ΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠΈ ΠΈΠΌΠ΅Π½ΠΈ ΠΏΠΎΠ΄ΠΎΠ² Kubernetes;

—class β€” класс исполняСмого Ρ„Π°ΠΉΠ»Π°, Π²Ρ‹Π·Ρ‹Π²Π°Π΅ΠΌΡ‹ΠΉ ΠΏΡ€ΠΈ запускС Π·Π°Π΄Π°Ρ‡ΠΈ;

—conf β€” ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΎΠ½Π½Ρ‹Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ Spark;

spark.executor.instances β€” количСство запускаСмых ΡΠΊΠ·Π΅ΠΊΡŒΡŽΡ‚ΠΎΡ€ΠΎΠ² Spark;

spark.kubernetes.authenticate.driver.serviceAccountName β€” имя слуТСбной ΡƒΡ‡Ρ‘Ρ‚Π½ΠΎΠΉ записи Kubernetes, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΠΎΠΉ ΠΏΡ€ΠΈ запускС ΠΏΠΎΠ΄ΠΎΠ² (для опрСдСлСния контСкста бСзопасности ΠΈ возмоТностСй ΠΏΡ€ΠΈ взаимодСйствии с API Kubernetes);

spark.kubernetes.namespace β€” пространство ΠΈΠΌΡ‘Π½ Kubernetes, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Π±ΡƒΠ΄ΡƒΡ‚ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒΡΡ ΠΏΠΎΠ΄Ρ‹ Π΄Ρ€Π°ΠΉΠ²Π΅Ρ€Π° ΠΈ ΡΠΊΠ·Π΅ΠΊΡŒΡŽΡ‚Π΅Ρ€ΠΎΠ²;

spark.submit.deployMode β€” способ запуска Spark (для стандартного spark-submit ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Β«clusterΒ», для Spark Operator ΠΈ Π±ΠΎΠ»Π΅Π΅ ΠΏΠΎΠ·Π΄Π½ΠΈΡ… вСрсий Spark Β«clientΒ»);

spark.kubernetes.container.image β€” ΠΎΠ±Ρ€Π°Π· Docker, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹ΠΉ для запуска ΠΏΠΎΠ΄ΠΎΠ²;

spark.master β€” URL API Kubernetes (указываСтся внСшний Ρ‚Π°ΠΊ ΠΎΠ±Ρ€Π°Ρ‰Π΅Π½ΠΈΠ΅ происходит с локальной ΠΌΠ°ΡˆΠΈΠ½Ρ‹);

local:// β€” ΠΏΡƒΡ‚ΡŒ Π΄ΠΎ исполняСмого Ρ„Π°ΠΉΠ»Π° Spark Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΎΠ±Ρ€Π°Π·Π° Docker.

ΠŸΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΈΠΌ Π² ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ OKD ΠΈ ΠΈΠ·ΡƒΡ‡Π°Π΅ΠΌ созданныС ΠΏΠΎΠ΄Ρ‹ β€” https://{OKD-WEBUI-URL}/console/project/{project}/browse/pods.

Для упрощСния процСсса Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ использован Π΅Ρ‰Ρ‘ ΠΎΠ΄ΠΈΠ½ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚, ΠΏΡ€ΠΈ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ создаётся ΠΎΠ±Ρ‰ΠΈΠΉ Π±Π°Π·ΠΎΠ²Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π· Spark, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹ΠΉ всСми Π·Π°Π΄Π°Ρ‡Π°ΠΌΠΈ для запуска, Π° ΡΠ½ΡΠΏΡˆΠΎΡ‚Ρ‹ исполняСмых Ρ„Π°ΠΉΠ»ΠΎΠ² ΠΏΡƒΠ±Π»ΠΈΠΊΡƒΡŽΡ‚ΡΡ Π²ΠΎ внСшнСС Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Hadoop) ΠΈ ΡƒΠΊΠ°Π·Ρ‹Π²Π°ΡŽΡ‚ΡΡ ΠΏΡ€ΠΈ Π²Ρ‹Π·ΠΎΠ²Π΅ spark-submit Π² Π²ΠΈΠ΄Π΅ ссылки. Π’ этом случаС ΠΌΠΎΠΆΠ½ΠΎ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Π΅ вСрсии Π·Π°Π΄Π°Ρ‡ Spark Π±Π΅Π· пСрСсборки ΠΎΠ±Ρ€Π°Π·ΠΎΠ² Docker, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ для ΠΏΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΠΈ ΠΎΠ±Ρ€Π°Π·ΠΎΠ², Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, WebHDFS. ΠžΡ‚ΠΏΡ€Π°Π²Π»ΡΠ΅ΠΌ запрос Π½Π° созданиС Ρ„Π°ΠΉΠ»Π° (здСсь {host} β€” хост сСрвиса WebHDFS, {port} β€” ΠΏΠΎΡ€Ρ‚ сСрвиса WebHDFS, {path-to-file-on-hdfs} β€” ΠΆΠ΅Π»Π°Π΅ΠΌΡ‹ΠΉ ΠΏΡƒΡ‚ΡŒ ΠΊ Ρ„Π°ΠΉΠ»Ρƒ Π½Π° HDFS):

curl -i -X PUT "http://{host}:{port}/webhdfs/v1/{path-to-file-on-hdfs}?op=CREATE

ΠŸΡ€ΠΈ этом Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ ΠΎΡ‚Π²Π΅Ρ‚ Π²ΠΈΠ΄Π° (здСсь {location} β€” это URL, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π½ΡƒΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ для Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ Ρ„Π°ΠΉΠ»Π°):

HTTP/1.1 307 TEMPORARY_REDIRECT
Location: {location}
Content-Length: 0

Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ исполняСмый Ρ„Π°ΠΉΠ» Spark Π² HDFS (здСсь {path-to-local-file} β€” ΠΏΡƒΡ‚ΡŒ ΠΊ исполняСмому Ρ„Π°ΠΉΠ»Ρƒ Spark Π½Π° Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΌ хостС):

curl -i -X PUT -T {path-to-local-file} "{location}"

ПослС этого ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π΅Π»Π°Ρ‚ΡŒ spark-submit с использованиСм Ρ„Π°ΠΉΠ»Π° Spark, Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½Π½ΠΎΠ³ΠΎ Π½Π° HDFS (здСсь {class-name} β€” имя класса, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ трСбуСтся Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ для выполнСния Π·Π°Π΄Π°Ρ‡ΠΈ):

/opt/spark/bin/spark-submit --name spark-test --class {class-name} --conf spark.executor.instances=3 --conf spark.kubernetes.authenticate.driver.serviceAccountName=spark --conf spark.kubernetes.namespace={project} --conf spark.submit.deployMode=cluster --conf spark.kubernetes.container.image={docker-registry-url}/{repo}/{image-name}:{tag} --conf spark.master=k8s://https://{OKD-API-URL}  hdfs://{host}:{port}/{path-to-file-on-hdfs}

ΠŸΡ€ΠΈ этом Π½Π°Π΄ΠΎ Π·Π°ΠΌΠ΅Ρ‚ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ для доступа ΠΊ HDFS ΠΈ обСспСчСния Ρ€Π°Π±ΠΎΡ‚Ρ‹ Π·Π°Π΄Π°Ρ‡ΠΈ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΡ‚Ρ€Π΅Π±ΠΎΠ²Π°Ρ‚ΡŒΡΡ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Dockerfile ΠΈ скрипт entrypoint.sh β€” Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π² Dockerfile Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΈΠ²Ρƒ для копирования зависимых Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ Π² Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡŽ /opt/spark/jars ΠΈ Π²ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Ρ„Π°ΠΉΠ» ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ HDFS Π² SPARK_CLASSPATH Π² entrypoint.sh.

Π’Ρ‚ΠΎΡ€ΠΎΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ использования β€” Apache Livy

Π”Π°Π»Π΅Π΅, ΠΊΠΎΠ³Π΄Π° Π·Π°Π΄Π°Ρ‡Π° Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Π°Π½Π° ΠΈ трСбуСтся ΠΏΡ€ΠΎΡ‚Π΅ΡΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½Ρ‹ΠΉ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚, Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ‚ вопрос Π΅Ρ‘ запуска Π² Ρ€Π°ΠΌΠΊΠ°Ρ… процСсса CI/CD ΠΈ отслСТивания статусов Π΅Ρ‘ выполнСния. ΠšΠΎΠ½Π΅Ρ‡Π½ΠΎ, ΠΌΠΎΠΆΠ½ΠΎ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ Π΅Ρ‘ ΠΈ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ локального Π²Ρ‹Π·ΠΎΠ²Π° spark-submit, Π½ΠΎ это услоТняСт инфраструктуру CI/CD ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ установку ΠΈ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡŽ Spark Π½Π° Π°Π³Π΅Π½Ρ‚Π°Ρ…/Ρ€Π°Π½Π½Π΅Ρ€Π°Ρ… CI сСрвСра ΠΈ настройки доступа ΠΊ API Kubernetes. Для Π΄Π°Π½Π½ΠΎΠ³ΠΎ случая Ρ†Π΅Π»Π΅Π²ΠΎΠΉ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠ΅ΠΉ Π²Ρ‹Π±Ρ€Π°Π½ΠΎ использованиС Apache Livy Π² качСствС REST API для запуска Π·Π°Π΄Π°Ρ‡ Spark, Ρ€Π°Π·ΠΌΠ΅Ρ‰Ρ‘Π½Π½ΠΎΠ³ΠΎ Π²Π½ΡƒΡ‚Ρ€ΠΈ кластСра Kubernetes. Π‘ Π΅Π³ΠΎ ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΌΠΎΠΆΠ½ΠΎ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ Π·Π°Π΄Π°Ρ‡ΠΈ Spark Π½Π° кластСрС Kubernetes ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹Π΅ cURL запросы, Ρ‡Ρ‚ΠΎ Π»Π΅Π³ΠΊΠΎ Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΠ΅ΠΌΠΎ Π½Π° Π±Π°Π·Π΅ любого CI Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ, Π° Π΅Π³ΠΎ Ρ€Π°Π·ΠΌΠ΅Ρ‰Π΅Π½ΠΈΠ΅ Π²Π½ΡƒΡ‚Ρ€ΠΈ кластСра Kubernetes Ρ€Π΅ΡˆΠ°Π΅Ρ‚ вопрос Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ ΠΏΡ€ΠΈ взаимодСйствии с API Kubernetes.

ЗапускаСм Apache Spark Π½Π° Kubernetes

Π’Ρ‹Π΄Π΅Π»ΠΈΠΌ Π΅Π³ΠΎ Π² качСствС Π²Ρ‚ΠΎΡ€ΠΎΠ³ΠΎ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Π° использования β€” запуск Π·Π°Π΄Π°Ρ‡ Spark Π² Ρ€Π°ΠΌΠΊΠ°Ρ… процСсса CI/CD Π½Π° кластСрС Kubernetes Π² тСстовом ΠΊΠΎΠ½Ρ‚ΡƒΡ€Π΅.

НСмного ΠΏΡ€ΠΎ Apache Livy β€” ΠΎΠ½ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ ΠΊΠ°ΠΊ HTTP сСрвСр, ΠΏΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²Π»ΡΡŽΡ‰ΠΈΠΉ Web интСрфСйс ΠΈ RESTful API, ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‰ΠΈΠΉ ΡƒΠ΄Π°Π»Ρ‘Π½Π½ΠΎ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ spark-submit, ΠΏΠ΅Ρ€Π΅Π΄Π°Π² Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹. Π’Ρ€Π°Π΄ΠΈΡ†ΠΈΠΎΠ½Π½ΠΎ ΠΎΠ½ поставлялся Π² составС дистрибутива HDP, Π½ΠΎ Ρ‚Π°ΠΊΠΆΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Ρ€Π°Π·Π²Ρ‘Ρ€Π½ΡƒΡ‚ Π² OKD ΠΈΠ»ΠΈ любой Π΄Ρ€ΡƒΠ³ΠΎΠΉ инсталляции Kubernetes с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π΅Π³ΠΎ манифСста ΠΈ Π½Π°Π±ΠΎΡ€Π° ΠΎΠ±Ρ€Π°Π·ΠΎΠ² Docker, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, этого β€” github.com/ttauveron/k8s-big-data-experiments/tree/master/livy-spark-2.3. Для нашСго случая Π±Ρ‹Π» собран Π°Π½Π°Π»ΠΎΠ³ΠΈΡ‡Π½Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π· Docker, Π²ΠΊΠ»ΡŽΡ‡Π°ΡŽΡ‰ΠΈΠΉ Π² сСбя Spark вСрсии 2.4.5 ΠΈΠ· ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π³ΠΎ Dockerfile:

FROM java:8-alpine

ENV SPARK_HOME=/opt/spark
ENV LIVY_HOME=/opt/livy
ENV HADOOP_CONF_DIR=/etc/hadoop/conf
ENV SPARK_USER=spark

WORKDIR /opt

RUN apk add --update openssl wget bash && 
    wget -P /opt https://downloads.apache.org/spark/spark-2.4.5/spark-2.4.5-bin-hadoop2.7.tgz && 
    tar xvzf spark-2.4.5-bin-hadoop2.7.tgz && 
    rm spark-2.4.5-bin-hadoop2.7.tgz && 
    ln -s /opt/spark-2.4.5-bin-hadoop2.7 /opt/spark

RUN wget http://mirror.its.dal.ca/apache/incubator/livy/0.7.0-incubating/apache-livy-0.7.0-incubating-bin.zip && 
    unzip apache-livy-0.7.0-incubating-bin.zip && 
    rm apache-livy-0.7.0-incubating-bin.zip && 
    ln -s /opt/apache-livy-0.7.0-incubating-bin /opt/livy && 
    mkdir /var/log/livy && 
    ln -s /var/log/livy /opt/livy/logs && 
    cp /opt/livy/conf/log4j.properties.template /opt/livy/conf/log4j.properties

ADD livy.conf /opt/livy/conf
ADD spark-defaults.conf /opt/spark/conf/spark-defaults.conf
ADD entrypoint.sh /entrypoint.sh

ENV PATH="/opt/livy/bin:${PATH}"

EXPOSE 8998

ENTRYPOINT ["/entrypoint.sh"]
CMD ["livy-server"]

Π‘ΠΎΠ·Π΄Π°Π½Π½Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π· ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ собран ΠΈ Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½ Π² ΠΈΠΌΠ΅ΡŽΡ‰ΠΈΠΉΡΡ Ρƒ вас Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ Docker, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΠΈΠΉ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ OKD. Для Π΅Π³ΠΎ развёртывания ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ манифСст ({registry-url} β€” URL рССстра ΠΎΠ±Ρ€Π°Π·ΠΎΠ² Docker, {image-name} β€” имя ΠΎΠ±Ρ€Π°Π·Π° Docker, {tag} β€” Ρ‚Π΅Π³ ΠΎΠ±Ρ€Π°Π·Π° Docker, {livy-url} β€” ΠΆΠ΅Π»Π°Π΅ΠΌΡ‹ΠΉ URL, ΠΏΠΎ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌΡƒ Π±ΡƒΠ΄Π΅Ρ‚ доступСн сСрвСр Livy; манифСст Β«RouteΒ» примСняСтся Π² случаС, Ссли Π² качСствС дистрибутива Kubernetes ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Red Hat OpenShift, Π² ΠΏΡ€ΠΎΡ‚ΠΈΠ²Π½ΠΎΠΌ случаС ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ манифСст Ingress ΠΈΠ»ΠΈ Service Ρ‚ΠΈΠΏΠ° NodePort):

---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    component: livy
  name: livy
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      component: livy
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        component: livy
    spec:
      containers:
        - command:
            - livy-server
          env:
            - name: K8S_API_HOST
              value: localhost
            - name: SPARK_KUBERNETES_IMAGE
              value: 'gnut3ll4/spark:v1.0.14'
          image: '{registry-url}/{image-name}:{tag}'
          imagePullPolicy: Always
          name: livy
          ports:
            - containerPort: 8998
              name: livy-rest
              protocol: TCP
          resources: {}
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          volumeMounts:
            - mountPath: /var/log/livy
              name: livy-log
            - mountPath: /opt/.livy-sessions/
              name: livy-sessions
            - mountPath: /opt/livy/conf/livy.conf
              name: livy-config
              subPath: livy.conf
            - mountPath: /opt/spark/conf/spark-defaults.conf
              name: spark-config
              subPath: spark-defaults.conf
        - command:
            - /usr/local/bin/kubectl
            - proxy
            - '--port'
            - '8443'
          image: 'gnut3ll4/kubectl-sidecar:latest'
          imagePullPolicy: Always
          name: kubectl
          ports:
            - containerPort: 8443
              name: k8s-api
              protocol: TCP
          resources: {}
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      serviceAccount: spark
      serviceAccountName: spark
      terminationGracePeriodSeconds: 30
      volumes:
        - emptyDir: {}
          name: livy-log
        - emptyDir: {}
          name: livy-sessions
        - configMap:
            defaultMode: 420
            items:
              - key: livy.conf
                path: livy.conf
            name: livy-config
          name: livy-config
        - configMap:
            defaultMode: 420
            items:
              - key: spark-defaults.conf
                path: spark-defaults.conf
            name: livy-config
          name: spark-config
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: livy-config
data:
  livy.conf: |-
    livy.spark.deploy-mode=cluster
    livy.file.local-dir-whitelist=/opt/.livy-sessions/
    livy.spark.master=k8s://http://localhost:8443
    livy.server.session.state-retain.sec = 8h
  spark-defaults.conf: 'spark.kubernetes.container.image        "gnut3ll4/spark:v1.0.14"'
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: livy
  name: livy
spec:
  ports:
    - name: livy-rest
      port: 8998
      protocol: TCP
      targetPort: 8998
  selector:
    component: livy
  sessionAffinity: None
  type: ClusterIP
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  labels:
    app: livy
  name: livy
spec:
  host: {livy-url}
  port:
    targetPort: livy-rest
  to:
    kind: Service
    name: livy
    weight: 100
  wildcardPolicy: None

ПослС Π΅Π³ΠΎ примСнСния ΠΈ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎΠ³ΠΎ запуска ΠΏΠΎΠ΄Π° графичСский интСрфСйс Livy доступСн ΠΏΠΎ ссылкС: http://{livy-url}/ui. Π‘ ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Livy ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΎΠΏΡƒΠ±Π»ΠΈΠΊΠΎΠ²Π°Ρ‚ΡŒ Π½Π°ΡˆΡƒ Π·Π°Π΄Π°Ρ‡Ρƒ Spark, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ REST запрос, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΈΠ· Postman. ΠŸΡ€ΠΈΠΌΠ΅Ρ€ ΠΊΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΠΈ с запросами прСдставлСн Π½ΠΈΠΆΠ΅ (Π² массивС Β«argsΒ» ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Ρ‹ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΎΠ½Π½Ρ‹Π΅ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹ с ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΌΠΈ, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹ΠΌΠΈ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ запускаСмой Π·Π°Π΄Π°Ρ‡ΠΈ):

{
    "info": {
        "_postman_id": "be135198-d2ff-47b6-a33e-0d27b9dba4c8",
        "name": "Spark Livy",
        "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
    },
    "item": [
        {
            "name": "1 Submit job with jar",
            "request": {
                "method": "POST",
                "header": [
                    {
                        "key": "Content-Type",
                        "value": "application/json"
                    }
                ],
                "body": {
                    "mode": "raw",
                    "raw": "{nt"file": "local:///opt/spark/examples/target/scala-2.11/jars/spark-examples_2.11-2.4.5.jar", nt"className": "org.apache.spark.examples.SparkPi",nt"numExecutors":1,nt"name": "spark-test-1",nt"conf": {ntt"spark.jars.ivy": "/tmp/.ivy",ntt"spark.kubernetes.authenticate.driver.serviceAccountName": "spark",ntt"spark.kubernetes.namespace": "{project}",ntt"spark.kubernetes.container.image": "{docker-registry-url}/{repo}/{image-name}:{tag}"nt}n}"
                },
                "url": {
                    "raw": "http://{livy-url}/batches",
                    "protocol": "http",
                    "host": [
                        "{livy-url}"
                    ],
                    "path": [
                        "batches"
                    ]
                }
            },
            "response": []
        },
        {
            "name": "2 Submit job without jar",
            "request": {
                "method": "POST",
                "header": [
                    {
                        "key": "Content-Type",
                        "value": "application/json"
                    }
                ],
                "body": {
                    "mode": "raw",
                    "raw": "{nt"file": "hdfs://{host}:{port}/{path-to-file-on-hdfs}", nt"className": "{class-name}",nt"numExecutors":1,nt"name": "spark-test-2",nt"proxyUser": "0",nt"conf": {ntt"spark.jars.ivy": "/tmp/.ivy",ntt"spark.kubernetes.authenticate.driver.serviceAccountName": "spark",ntt"spark.kubernetes.namespace": "{project}",ntt"spark.kubernetes.container.image": "{docker-registry-url}/{repo}/{image-name}:{tag}"nt},nt"args": [ntt"HADOOP_CONF_DIR=/opt/spark/hadoop-conf",ntt"MASTER=k8s://https://kubernetes.default.svc:8443"nt]n}"
                },
                "url": {
                    "raw": "http://{livy-url}/batches",
                    "protocol": "http",
                    "host": [
                        "{livy-url}"
                    ],
                    "path": [
                        "batches"
                    ]
                }
            },
            "response": []
        }
    ],
    "event": [
        {
            "listen": "prerequest",
            "script": {
                "id": "41bea1d0-278c-40c9-ad42-bf2e6268897d",
                "type": "text/javascript",
                "exec": [
                    ""
                ]
            }
        },
        {
            "listen": "test",
            "script": {
                "id": "3cdd7736-a885-4a2d-9668-bd75798f4560",
                "type": "text/javascript",
                "exec": [
                    ""
                ]
            }
        }
    ],
    "protocolProfileBehavior": {}
}

Π’Ρ‹ΠΏΠΎΠ»Π½ΠΈΠΌ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ запрос ΠΈΠ· ΠΊΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΠΈ, ΠΏΠ΅Ρ€Π΅ΠΉΠ΄Ρ‘ΠΌ Π² интСрфСйс OKD ΠΈ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΠΌ, Ρ‡Ρ‚ΠΎ Π·Π°Π΄Π°Ρ‡Π° ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ Π·Π°ΠΏΡƒΡ‰Π΅Π½Π° β€” https://{OKD-WEBUI-URL}/console/project/{project}/browse/pods. ΠŸΡ€ΠΈ этом Π² интСрфСйсС Livy (http://{livy-url}/ui) появится сСссия, Π² Ρ€Π°ΠΌΠΊΠ°Ρ… ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ API Livy ΠΈΠ»ΠΈ графичСского интСрфСйса ΠΌΠΎΠΆΠ½ΠΎ ΠΎΡ‚ΡΠ»Π΅ΠΆΠΈΠ²Π°Ρ‚ΡŒ Ρ…ΠΎΠ΄ выполнСния Π·Π°Π΄Π°Ρ‡ΠΈ ΠΈ ΠΈΠ·ΡƒΡ‡Π°Ρ‚ΡŒ Π»ΠΎΠ³ΠΈ сСссии.

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΏΠΎΠΊΠ°ΠΆΠ΅ΠΌ ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌ Ρ€Π°Π±ΠΎΡ‚Ρ‹ Livy. Для этого ΠΈΠ·ΡƒΡ‡ΠΈΠΌ ΠΆΡƒΡ€Π½Π°Π»Ρ‹ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π° Livy Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΏΠΎΠ΄Π° с сСрвСром Livy β€” https://{OKD-WEBUI-URL}/console/project/{project}/browse/pods/{livy-pod-name}?tab=logs. Из Π½ΠΈΡ… Π²ΠΈΠ΄Π½ΠΎ, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΈ Π²Ρ‹Π·ΠΎΠ²Π΅ REST API Livy Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π΅ с ΠΈΠΌΠ΅Π½Π΅ΠΌ Β«livyΒ» выполняСтся spark-submit, Π°Π½Π°Π»ΠΎΠ³ΠΈΡ‡Π½Ρ‹ΠΉ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΠΎΠΌΡƒ Π½Π°ΠΌΠΈ Π²Ρ‹ΡˆΠ΅ (здСсь {livy-pod-name} β€” имя созданного ΠΏΠΎΠ΄Π° с сСрвСром Livy). Π’ ΠΊΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΠΈ Ρ‚Π°ΠΊΠΆΠ΅ прСдставлСн Π²Ρ‚ΠΎΡ€ΠΎΠΉ запрос, ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‰ΠΈΠΉ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ Π·Π°Π΄Π°Ρ‡ΠΈ с ΡƒΠ΄Π°Π»Ρ‘Π½Π½Ρ‹ΠΌ Ρ€Π°Π·ΠΌΠ΅Ρ‰Π΅Π½ΠΈΠ΅ΠΌ исполняСмого Ρ„Π°ΠΉΠ»Π° Spark с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ сСрвСра Livy.

Π’Ρ€Π΅Ρ‚ΠΈΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ использования β€” Spark Operator

Π’Π΅ΠΏΠ΅Ρ€ΡŒ, ΠΊΠΎΠ³Π΄Π° Π·Π°Π΄Π°Ρ‡Π° протСстирована, встаёт вопрос Π΅Ρ‘ рСгулярного запуска. Нативным способом для рСгулярного запуска Π·Π°Π΄Π°Ρ‡ Π² кластСрС Kubernetes являСтся ΡΡƒΡ‰Π½ΠΎΡΡ‚ΡŒ CronJob ΠΈ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π΅Ρ‘, Π½ΠΎ Π² Π΄Π°Π½Π½Ρ‹ΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚ Π±ΠΎΠ»ΡŒΡˆΡƒΡŽ ΠΏΠΎΠΏΡƒΠ»ΡΡ€Π½ΠΎΡΡ‚ΡŒ ΠΈΠΌΠ΅Π΅Ρ‚ использованиС ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΠ² для управлСния прилоТСниями Π² Kubernetes ΠΈ для Spark сущСствуСт достаточно Π·Ρ€Π΅Π»Ρ‹ΠΉ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ, Π² Ρ‚ΠΎΠΌ числС, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Π² Ρ€Π΅ΡˆΠ΅Π½ΠΈΡΡ… Enterprise уровня (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Lightbend FastData Platform). ΠœΡ‹ Ρ€Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡƒΠ΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π΅Π³ΠΎ β€” тСкущая ΡΡ‚Π°Π±ΠΈΠ»ΡŒΠ½Π°Ρ вСрсия Spark (2.4.5) ΠΈΠΌΠ΅Π΅Ρ‚ достаточно ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½Π½Ρ‹Π΅ возмоТности ΠΏΠΎ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ запуска Π·Π°Π΄Π°Ρ‡ Spark Π² Kubernetes, ΠΏΡ€ΠΈ этом Π² ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ ΠΌΠ°ΠΆΠΎΡ€Π½ΠΎΠΉ вСрсии (3.0.0) заявлСна полноцСнная ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° Kubernetes, Π½ΠΎ Π΄Π°Ρ‚Π° Π΅Ρ‘ Π²Ρ‹Ρ…ΠΎΠ΄Π° остаётся нСизвСстной. Spark Operator компСнсируСт этот нСдостаток, добавляя Π²Π°ΠΆΠ½Ρ‹Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΌΠΎΠ½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ConfigMap с ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠ΅ΠΉ доступа ΠΊ Hadoop Π² ΠΏΠΎΠ΄Ρ‹ Spark) ΠΈ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ рСгулярного запуска Π·Π°Π΄Π°Ρ‡ΠΈ ΠΏΠΎ Ρ€Π°ΡΠΏΠΈΡΠ°Π½ΠΈΡŽ.

ЗапускаСм Apache Spark Π½Π° Kubernetes
Π’Ρ‹Π΄Π΅Π»ΠΈΠΌ Π΅Π³ΠΎ Π² качСствС Ρ‚Ρ€Π΅Ρ‚ΡŒΠ΅Π³ΠΎ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Π° использования β€” рСгулярный запуск Π·Π°Π΄Π°Ρ‡ Spark Π½Π° кластСрС Kubernetes Π² ΠΏΡ€ΠΎΠ΄ΡƒΠΊΡ‚ΠΈΠ²Π½ΠΎΠΌ ΠΊΠΎΠ½Ρ‚ΡƒΡ€Π΅.

Spark Operator ΠΈΠΌΠ΅Π΅Ρ‚ ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚Ρ‹ΠΉ исходный ΠΊΠΎΠ΄ ΠΈ разрабатываСтся Π² Ρ€Π°ΠΌΠΊΠ°Ρ… Google Cloud Platform β€” github.com/GoogleCloudPlatform/spark-on-k8s-operator. Π•Π³ΠΎ установка ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ ΠΏΡ€ΠΎΠΈΠ·Π²Π΅Π΄Π΅Π½Π° 3 способами:

  1. Π’ Ρ€Π°ΠΌΠΊΠ°Ρ… установки Lightbend FastData Platform/Cloudflow;
  2. Π‘ ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Helm:
    helm repo add incubator http://storage.googleapis.com/kubernetes-charts-incubator
    helm install incubator/sparkoperator --namespace spark-operator
    	

  3. ΠŸΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ΠΌ манифСстов ΠΈΠ· ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠ³ΠΎ рСпозитория (https://github.com/GoogleCloudPlatform/spark-on-k8s-operator/tree/master/manifest). ΠŸΡ€ΠΈ этом стоит ΠΎΡ‚ΠΌΠ΅Ρ‚ΠΈΡ‚ΡŒ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π΅ β€” Π² состав Cloudflow Π²Ρ…ΠΎΠ΄ΠΈΡ‚ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ с вСрсиСй API v1beta1. Если ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Π΄Π°Π½Π½Ρ‹ΠΉ Ρ‚ΠΈΠΏ установки, Ρ‚ΠΎ описания манифСстов ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Spark Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒΡΡ Π½Π° основС ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΠ² ΠΈΠ· Ρ‚Π΅Π³ΠΎΠ² Π² Git с ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π΅ΠΉ вСрсиСй API, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Β«v1beta1-0.9.0-2.4.0Β». Π’Π΅Ρ€ΡΠΈΡŽ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Π° ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π² описании CRD, входящСго Π² состав ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Π° Π² словарС Β«versionsΒ»:
    oc get crd sparkapplications.sparkoperator.k8s.io -o yaml
    	

Если ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ установлСн ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½ΠΎ, Ρ‚ΠΎ Π² ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π΅ΠΌ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π΅ появится Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹ΠΉ ΠΏΠΎΠ΄ с ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΠΌ Spark (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, cloudflow-fdp-sparkoperator Π² пространствС Cloudflow для установки Cloudflow) ΠΈ появится ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ Ρ‚ΠΈΠΏ рСсурсов Kubernetes с ΠΈΠΌΠ΅Π½Π΅ΠΌ Β«sparkapplicationsΒ». Π˜Π·ΡƒΡ‡ΠΈΡ‚ΡŒ ΠΈΠΌΠ΅ΡŽΡ‰ΠΈΠ΅ΡΡ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Spark ΠΌΠΎΠΆΠ½ΠΎ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ:

oc get sparkapplications -n {project}

Для запуска Π·Π°Π΄Π°Ρ‡ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Spark Operator трСбуСтся ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ 3 Π²Π΅Ρ‰ΠΈ:

  • ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΎΠ±Ρ€Π°Π· Docker, Π²ΠΊΠ»ΡŽΡ‡Π°ΡŽΡ‰ΠΈΠΉ Π² сСбя всС Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ, Π° Ρ‚Π°ΠΊΠΆΠ΅ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΎΠ½Π½Ρ‹Π΅ ΠΈ исполняСмыС Ρ„Π°ΠΉΠ»Ρ‹. Π’ Ρ†Π΅Π»Π΅Π²ΠΎΠΉ ΠΊΠ°Ρ€Ρ‚ΠΈΠ½Π΅ это ΠΎΠ±Ρ€Π°Π·, созданный Π½Π° этапС CI/CD ΠΈ протСстированный Π½Π° тСстовом кластСрС;
  • ΠΎΠΏΡƒΠ±Π»ΠΈΠΊΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠ±Ρ€Π°Π· Docker Π² рССстр, доступный ΠΈΠ· кластСра Kubernetes;
  • ΡΡ„ΠΎΡ€ΠΌΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ манифСст с Ρ‚ΠΈΠΏΠΎΠΌ Β«SparkApplicationΒ» ΠΈ описаниСм запускаСмой Π·Π°Π΄Π°Ρ‡ΠΈ. ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ манифСстов доступны Π² ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠΌ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, github.com/GoogleCloudPlatform/spark-on-k8s-operator/blob/v1beta1-0.9.0-2.4.0/examples/spark-pi.yaml). Π‘Ρ‚ΠΎΠΈΡ‚ ΠΎΡ‚ΠΌΠ΅Ρ‚ΠΈΡ‚ΡŒ Π²Π°ΠΆΠ½Ρ‹Π΅ ΠΌΠΎΠΌΠ΅Π½Ρ‚Ρ‹ ΠΊΠ°ΡΠ°Ρ‚Π΅Π»ΡŒΠ½ΠΎ манифСста:
    1. Π² словарС Β«apiVersionΒ» Π΄ΠΎΠ»ΠΆΠ½Π° Π±Ρ‹Ρ‚ΡŒ ΡƒΠΊΠ°Π·Π°Π½Π° вСрсия API, ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π°Ρ вСрсии ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Π°;
    2. Π² словарС Β«metadata.namespaceΒ» Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ ΡƒΠΊΠ°Π·Π°Π½ΠΎ пространство ΠΈΠΌΡ‘Π½, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Π±ΡƒΠ΄Π΅Ρ‚ Π·Π°ΠΏΡƒΡ‰Π΅Π½ΠΎ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅;
    3. Π² словарС Β«spec.imageΒ» Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ ΡƒΠΊΠ°Π·Π°Π½ адрСс созданного ΠΎΠ±Ρ€Π°Π·Π° Docker Π² доступном рССстрС;
    4. Π² словарС Β«spec.mainClassΒ» Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ ΡƒΠΊΠ°Π·Π°Π½ класс Π·Π°Π΄Π°Ρ‡ΠΈ Spark, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ трСбуСтся Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈ запускС процСсса;
    5. Π² словарС Β«spec.mainApplicationFileΒ» Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ ΡƒΠΊΠ°Π·Π°Π½ ΠΏΡƒΡ‚ΡŒ ΠΊ исполняСмому jar Ρ„Π°ΠΉΠ»Ρƒ;
    6. Π² словарС Β«spec.sparkVersionΒ» Π΄ΠΎΠ»ΠΆΠ½Π° Π±Ρ‹Ρ‚ΡŒ ΡƒΠΊΠ°Π·Π°Π½Π° ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΠ°Ρ вСрсия Spark;
    7. Π² словарС Β«spec.driver.serviceAccountΒ» Π΄ΠΎΠ»ΠΆΠ½Π° Π±Ρ‹Ρ‚ΡŒ ΡƒΠΊΠ°Π·Π°Π½Π° сСрвисная учётная запись Π²Π½ΡƒΡ‚Ρ€ΠΈ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π΅Π³ΠΎ пространства ΠΈΠΌΡ‘Π½ Kubernetes, которая Π±ΡƒΠ΄Π΅Ρ‚ использована для запуска прилоТСния;
    8. Π² словарС Β«spec.executorΒ» Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ ΡƒΠΊΠ°Π·Π°Π½ΠΎ количСство рСсурсов, выдСляСмых ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡŽ;
    9. Π² словарС Β«spec.volumeMountsΒ» Π΄ΠΎΠ»ΠΆΠ½Π° Π±Ρ‹Ρ‚ΡŒ ΡƒΠΊΠ°Π·Π°Π½Π° локальная дирСктория, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Π±ΡƒΠ΄ΡƒΡ‚ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒΡΡ Π»ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹ Π·Π°Π΄Π°Ρ‡ΠΈ Spark.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ формирования манифСста (здСсь {spark-service-account} β€” сСрвисный Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ Π²Π½ΡƒΡ‚Ρ€ΠΈ кластСра Kubernetes для запуска Π·Π°Π΄Π°Ρ‡ Spark):

apiVersion: "sparkoperator.k8s.io/v1beta1"
kind: SparkApplication
metadata:
  name: spark-pi
  namespace: {project}
spec:
  type: Scala
  mode: cluster
  image: "gcr.io/spark-operator/spark:v2.4.0"
  imagePullPolicy: Always
  mainClass: org.apache.spark.examples.SparkPi
  mainApplicationFile: "local:///opt/spark/examples/jars/spark-examples_2.11-2.4.0.jar"
  sparkVersion: "2.4.0"
  restartPolicy:
    type: Never
  volumes:
    - name: "test-volume"
      hostPath:
        path: "/tmp"
        type: Directory
  driver:
    cores: 0.1
    coreLimit: "200m"
    memory: "512m"
    labels:
      version: 2.4.0
    serviceAccount: {spark-service-account}
    volumeMounts:
      - name: "test-volume"
        mountPath: "/tmp"
  executor:
    cores: 1
    instances: 1
    memory: "512m"
    labels:
      version: 2.4.0
    volumeMounts:
      - name: "test-volume"
        mountPath: "/tmp"

Π’ Π΄Π°Π½Π½ΠΎΠΌ манифСстС ΡƒΠΊΠ°Π·Π°Π½Π° сСрвисная учётная запись, для ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ трСбуСтся Π΄ΠΎ ΠΏΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΠΈ манифСста ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ привязки Ρ€ΠΎΠ»Π΅ΠΉ, ΠΏΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²Π»ΡΡŽΡ‰ΠΈΠ΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ ΠΏΡ€Π°Π²Π° доступа для взаимодСйствия прилоТСния Spark с API Kubernetes (Ссли Π½ΡƒΠΆΠ½ΠΎ). Π’ нашСм случаС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡŽ Π½ΡƒΠΆΠ½Ρ‹ ΠΏΡ€Π°Π²Π° Π½Π° созданиС Pod’ΠΎΠ². Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡƒΡŽ привязку Ρ€ΠΎΠ»ΠΈ:

oc adm policy add-role-to-user edit system:serviceaccount:{project}:{spark-service-account} -n {project}

Π’Π°ΠΊΠΆΠ΅ стоит ΠΎΡ‚ΠΌΠ΅Ρ‚ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ Π² спСцификации Π΄Π°Π½Π½ΠΎΠ³ΠΎ манифСста ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ ΡƒΠΊΠ°Π·Π°Π½ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ Β«hadoopConfigMapΒ», ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ позволяСт ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ ConfigMap с ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠ΅ΠΉ Hadoop Π±Π΅Π· нСобходимости ΠΏΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠ³ΠΎ помСщСния ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π΅Π³ΠΎ Ρ„Π°ΠΉΠ»Π° Π² ΠΎΠ±Ρ€Π°Π· Docker. Π’Π°ΠΊΠΆΠ΅ ΠΎΠ½ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ΠΈΡ‚ для рСгулярного запуска Π·Π°Π΄Π°Ρ‡ β€” с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π° Β«scheduleΒ» ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ ΡƒΠΊΠ°Π·Π°Π½ΠΎ расписаниС запуска Π΄Π°Π½Π½ΠΎΠΉ Π·Π°Π΄Π°Ρ‡ΠΈ.

ПослС этого сохраняСм наш манифСст Π² Ρ„Π°ΠΉΠ» spark-pi.yaml ΠΈ примСняСм Π΅Π³ΠΎ ΠΊ Π½Π°ΡˆΠ΅ΠΌΡƒ кластСру Kubernetes:

oc apply -f spark-pi.yaml

ΠŸΡ€ΠΈ этом создастся ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Ρ‚ΠΈΠΏΠ° Β«sparkapplicationsΒ»:

oc get sparkapplications -n {project}
> NAME       AGE
> spark-pi   22h

ΠŸΡ€ΠΈ этом Π±ΡƒΠ΄Π΅Ρ‚ создан ΠΏΠΎΠ΄ с ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ, статус ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Ρ‚ΡŒΡΡ Π² созданном Β«sparkapplicationsΒ». Π•Π³ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ:

oc get sparkapplications spark-pi -o yaml -n {project}

По Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠΈ Π·Π°Π΄Π°Ρ‡ΠΈ POD ΠΏΠ΅Ρ€Π΅ΠΉΠ΄Ρ‘Ρ‚ Π² статус Β«CompletedΒ», ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Ρ‚Π°ΠΊΠΆΠ΅ обновится Π² Β«sparkapplicationsΒ». Π›ΠΎΠ³ΠΈ прилоТСния ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π² Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π΅ ΠΈΠ»ΠΈ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ (здСсь {sparkapplications-pod-name} β€” имя ΠΏΠΎΠ΄Π° Π·Π°ΠΏΡƒΡ‰Π΅Π½Π½ΠΎΠΉ Π·Π°Π΄Π°Ρ‡ΠΈ):

oc logs {sparkapplications-pod-name} -n {project}

Π’Π°ΠΊΠΆΠ΅ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Π·Π°Π΄Π°Ρ‡Π°ΠΌΠΈ Spark ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ осущСствлСно с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ спСциализированной ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹ sparkctl. Для Π΅Ρ‘ установки ΠΊΠ»ΠΎΠ½ΠΈΡ€ΡƒΠ΅ΠΌ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ с Π΅Ρ‘ исходным ΠΊΠΎΠ΄ΠΎΠΌ, установим Go ΠΈ собСрём Π΄Π°Π½Π½ΡƒΡŽ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρƒ:

git clone https://github.com/GoogleCloudPlatform/spark-on-k8s-operator.git
cd spark-on-k8s-operator/
wget https://dl.google.com/go/go1.13.3.linux-amd64.tar.gz
tar -xzf go1.13.3.linux-amd64.tar.gz
sudo mv go /usr/local
mkdir $HOME/Projects
export GOROOT=/usr/local/go
export GOPATH=$HOME/Projects
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH
go -version
cd sparkctl
go build -o sparkctl
sudo mv sparkctl /usr/local/bin

Π˜Π·ΡƒΡ‡ΠΈΠΌ список Π·Π°ΠΏΡƒΡ‰Π΅Π½Π½Ρ‹Ρ… Π·Π°Π΄Π°Ρ‡ Spark:

sparkctl list -n {project}

Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ описаниС для Π·Π°Π΄Π°Ρ‡ΠΈ Spark:

vi spark-app.yaml

apiVersion: "sparkoperator.k8s.io/v1beta1"
kind: SparkApplication
metadata:
  name: spark-pi
  namespace: {project}
spec:
  type: Scala
  mode: cluster
  image: "gcr.io/spark-operator/spark:v2.4.0"
  imagePullPolicy: Always
  mainClass: org.apache.spark.examples.SparkPi
  mainApplicationFile: "local:///opt/spark/examples/jars/spark-examples_2.11-2.4.0.jar"
  sparkVersion: "2.4.0"
  restartPolicy:
    type: Never
  volumes:
    - name: "test-volume"
      hostPath:
        path: "/tmp"
        type: Directory
  driver:
    cores: 1
    coreLimit: "1000m"
    memory: "512m"
    labels:
      version: 2.4.0
    serviceAccount: spark
    volumeMounts:
      - name: "test-volume"
        mountPath: "/tmp"
  executor:
    cores: 1
    instances: 1
    memory: "512m"
    labels:
      version: 2.4.0
    volumeMounts:
      - name: "test-volume"
        mountPath: "/tmp"

Запустим ΠΎΠΏΠΈΡΠ°Π½Π½ΡƒΡŽ Π·Π°Π΄Π°Ρ‡Ρƒ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ sparkctl:

sparkctl create spark-app.yaml -n {project}

Π˜Π·ΡƒΡ‡ΠΈΠΌ список Π·Π°ΠΏΡƒΡ‰Π΅Π½Π½Ρ‹Ρ… Π·Π°Π΄Π°Ρ‡ Spark:

sparkctl list -n {project}

Π˜Π·ΡƒΡ‡ΠΈΠΌ список событий Π·Π°ΠΏΡƒΡ‰Π΅Π½Π½ΠΎΠΉ Π·Π°Π΄Π°Ρ‡ΠΈ Spark:

sparkctl event spark-pi -n {project} -f

Π˜Π·ΡƒΡ‡ΠΈΠΌ статус Π·Π°ΠΏΡƒΡ‰Π΅Π½Π½ΠΎΠΉ Π·Π°Π΄Π°Ρ‡ΠΈ Spark:

sparkctl status spark-pi -n {project}

Π’ Π·Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ Ρ…ΠΎΡ‚Π΅Π»ΠΎΡΡŒ Π±Ρ‹ Ρ€Π°ΡΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ ΠΎΠ±Π½Π°Ρ€ΡƒΠΆΠ΅Π½Π½Ρ‹Π΅ минусы эксплуатации Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ ΡΡ‚Π°Π±ΠΈΠ»ΡŒΠ½ΠΎΠΉ вСрсии Spark (2.4.5) Π² Kubernetes:

  1. ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ ΠΈ, ΠΏΠΎΠΆΠ°Π»ΡƒΠΉ, Π³Π»Π°Π²Π½Ρ‹ΠΉ минус β€” это отсутствиС Data Locality. НСсмотря Π½Π° всС нСдостатки YARN Π±Ρ‹Π»ΠΈ ΠΈ ΠΏΠ»ΡŽΡΡ‹ Π² Π΅Π³ΠΎ использовании, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏ доставки ΠΊΠΎΠ΄Π° ΠΊ Π΄Π°Π½Π½Ρ‹ΠΌ (Π° Π½Π΅ Π΄Π°Π½Π½Ρ‹Ρ… ΠΊ ΠΊΠΎΠ΄Ρƒ). Благодаря Π΅ΠΌΡƒ Π·Π°Π΄Π°Ρ‡ΠΈ Spark Π²Ρ‹ΠΏΠΎΠ»Π½ΡΠ»ΠΈΡΡŒ Π½Π° ΡƒΠ·Π»Π°Ρ…, Π³Π΄Π΅ Ρ€Π°ΡΠΏΠΎΠ»Π°Π³Π°Π»ΠΈΡΡŒ Π΄Π°Π½Π½Ρ‹Π΅, ΡƒΡ‡Π°ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ Π² вычислСниях, ΠΈ Π·Π°ΠΌΠ΅Ρ‚Π½ΠΎ ΡƒΠΌΠ΅Π½ΡŒΡˆΠ°Π»ΠΎΡΡŒ врСмя Π½Π° доставку Π΄Π°Π½Π½Ρ‹Ρ… ΠΏΠΎ сСти. ΠŸΡ€ΠΈ использовании Kubernetes ΠΌΡ‹ сталкиваСмся с Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒΡŽ пСрСмСщСния ΠΏΠΎ сСти Π΄Π°Π½Π½Ρ‹Ρ…, задСйствованных Π² Ρ€Π°Π±ΠΎΡ‚Π΅ Π·Π°Π΄Π°Ρ‡ΠΈ. Π’ случаС, Ссли ΠΎΠ½ΠΈ достаточно большиС, Ρ‚ΠΎ врСмя выполнСния Π·Π°Π΄Π°Ρ‡ΠΈ ΠΌΠΎΠΆΠ΅Ρ‚ сущСствСнно ΡƒΠ²Π΅Π»ΠΈΡ‡ΠΈΡ‚ΡŒΡΡ, Π° Ρ‚Π°ΠΊΠΆΠ΅ ΠΏΠΎΡ‚Ρ€Π΅Π±ΠΎΠ²Π°Ρ‚ΡŒΡΡ достаточно большой ΠΎΠ±ΡŠΡ‘ΠΌ дискового пространства, Π²Ρ‹Π΄Π΅Π»Π΅Π½Π½ΠΎΠ³ΠΎ экзСмплярам Π·Π°Π΄Π°Ρ‡ΠΈ Spark для ΠΈΡ… Π²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠ³ΠΎ хранСния. Π”Π°Π½Π½Ρ‹ΠΉ нСдостаток ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ сниТСн Π·Π° счёт использования спСциализированных ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ½Ρ‹Ρ… срСдств, ΠΎΠ±Π΅ΡΠΏΠ΅Ρ‡ΠΈΠ²Π°ΡŽΡ‰ΠΈΡ… Π»ΠΎΠΊΠ°Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹Ρ… Π² Kubernetes (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Alluxio), Π½ΠΎ это фактичСски ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒ хранСния ΠΏΠΎΠ»Π½ΠΎΠΉ ΠΊΠΎΠΏΠΈΠΈ Π΄Π°Π½Π½Ρ‹Ρ… Π½Π° ΡƒΠ·Π»Π°Ρ… кластСра Kubernetes.
  2. Π’Ρ‚ΠΎΡ€ΠΎΠΉ Π²Π°ΠΆΠ½Ρ‹ΠΉ минус β€” это Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡ‚ΡŒ. По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, связанныС с обСспСчСниСм бСзопасности ΠΊΠ°ΡΠ°Ρ‚Π΅Π»ΡŒΠ½ΠΎ запуска Π·Π°Π΄Π°Ρ‡ Spark ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π΅Π½Ρ‹, Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ использования Kerberos Π² ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠΉ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ Π½Π΅ ΠΎΡ…Π²Π°Ρ‡Π΅Π½ (хотя ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ появились Π² вСрсии 3.0.0, Ρ‡Ρ‚ΠΎ ΠΏΠΎΡ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠΉ ΠΏΡ€ΠΎΡ€Π°Π±ΠΎΡ‚ΠΊΠΈ), Π° Π² Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ ΠΏΠΎ ΠΎΠ±Π΅ΡΠΏΠ΅Ρ‡Π΅Π½ΠΈΡŽ бСзопасности ΠΏΡ€ΠΈ использовании Spark (https://spark.apache.org/docs/2.4.5/security.html) Π² качСствС Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰ ΠΊΠ»ΡŽΡ‡Π΅ΠΉ Ρ„ΠΈΠ³ΡƒΡ€ΠΈΡ€ΡƒΡŽΡ‚ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ YARN, Mesos ΠΈ Standalone Cluster. ΠŸΡ€ΠΈ этом ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ, ΠΏΠΎΠ΄ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌ Π·Π°ΠΏΡƒΡΠΊΠ°ΡŽΡ‚ΡΡ Π·Π°Π΄Π°Ρ‡ΠΈ Spark, Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ ΡƒΠΊΠ°Π·Π°Π½ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ β€” ΠΌΡ‹ лишь Π·Π°Π΄Π°Ρ‘ΠΌ ΡΠ΅Ρ€Π²ΠΈΡΠ½ΡƒΡŽ ΡƒΡ‡Ρ‘Ρ‚Π½ΡƒΡŽ запись, ΠΏΠΎΠ΄ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ ΠΏΠΎΠ΄, Π° ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ выбираСтся исходя ΠΈΠ· настроСнных ΠΏΠΎΠ»ΠΈΡ‚ΠΈΠΊ бСзопасности. Π’ связи с этим Π»ΠΈΠ±ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ root, Ρ‡Ρ‚ΠΎ Π½Π΅ бСзопасно Π² ΠΏΡ€ΠΎΠ΄ΡƒΠΊΡ‚ΠΈΠ²Π½ΠΎΠΌ ΠΎΠΊΡ€ΡƒΠΆΠ΅Π½ΠΈΠΈ, Π»ΠΈΠ±ΠΎ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ с случайным UID, Ρ‡Ρ‚ΠΎ Π½Π΅ΡƒΠ΄ΠΎΠ±Π½ΠΎ ΠΏΡ€ΠΈ распрСдСлСнии ΠΏΡ€Π°Π² доступа ΠΊ Π΄Π°Π½Π½Ρ‹ΠΌ (Ρ€Π΅ΡˆΠ°Π΅ΠΌΠΎ созданиСм PodSecurityPolicies ΠΈ ΠΈΡ… привязкой ΠΊ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΌ слуТСбным ΡƒΡ‡Ρ‘Ρ‚Π½Ρ‹ΠΌ записям). На Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚ Ρ€Π΅ΡˆΠ°Π΅Ρ‚ΡΡ Π»ΠΈΠ±ΠΎ ΠΏΠΎΠΌΠ΅Ρ‰Π΅Π½ΠΈΠ΅ΠΌ всСх Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Ρ… Ρ„Π°ΠΉΠ»ΠΎΠ² нСпосрСдствСнно Π² ΠΎΠ±Ρ€Π°Π· Docker, Π»ΠΈΠ±ΠΎ ΠΌΠΎΠ΄ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠ΅ΠΉ скрипта запуска Spark для использования ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌΠ° хранСния ΠΈ получСния сСкрСтов, принятого Π² Π’Π°ΡˆΠ΅ΠΉ ΠΎΡ€Π³Π°Π½ΠΈΠ·Π°Ρ†ΠΈΠΈ.
  3. Запуск Π·Π°Π΄Π°Ρ‡ Spark с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Kubernetes ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½ΠΎ Π΄ΠΎ сих ΠΏΠΎΡ€ находится Π² ΡΠΊΡΠΏΠ΅Ρ€ΠΈΠΌΠ΅Π½Ρ‚Π°Π»ΡŒΠ½ΠΎΠΌ Ρ€Π΅ΠΆΠΈΠΌΠ΅ ΠΈ Π² Π±ΡƒΠ΄ΡƒΡ‰Π΅ΠΌ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ‹ Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ измСнСния Π² ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹Ρ… Π°Ρ€Ρ‚Π΅Ρ„Π°ΠΊΡ‚Π°Ρ… (ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΎΠ½Π½Ρ‹Ρ… Ρ„Π°ΠΉΠ»Π°Ρ…, Π±Π°Π·ΠΎΠ²Ρ‹Ρ… ΠΎΠ±Ρ€Π°Π·ΠΎΠ² Docker ΠΈ скриптах запуска). И Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ β€” ΠΏΡ€ΠΈ ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΊΠ΅ ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»Π° Ρ‚Π΅ΡΡ‚ΠΈΡ€ΠΎΠ²Π°Π»ΠΈΡΡŒ вСрсии 2.3.0 ΠΈ 2.4.5, ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ сущСствСнно ΠΎΡ‚Π»ΠΈΡ‡Π°Π»ΠΎΡΡŒ.

Π‘ΡƒΠ΄Π΅ΠΌ ΠΆΠ΄Π°Ρ‚ΡŒ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΉ β€” Π½Π΅Π΄Π°Π²Π½ΠΎ Π²Ρ‹ΡˆΠ»Π° свСТая вСрсия Spark (3.0.0), ΠΏΡ€ΠΈΠ½Ρ‘ΡΡˆΠ°Ρ ΠΎΡ‰ΡƒΡ‚ΠΈΠΌΡ‹Π΅ измСнСния Π² Ρ€Π°Π±ΠΎΡ‚Ρƒ Spark Π½Π° Kubernetes, Π½ΠΎ ΡΠΎΡ…Ρ€Π°Π½ΠΈΠ²ΡˆΠ°Ρ ΡΠΊΡΠΏΠ΅Ρ€ΠΈΠΌΠ΅Π½Ρ‚Π°Π»ΡŒΠ½Ρ‹ΠΉ статус ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΈ Π΄Π°Π½Π½ΠΎΠ³ΠΎ ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€Π° рСсурсов. Π’ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ, ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ обновлСния Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ позволят Π² ΠΏΠΎΠ»Π½ΠΎΠΉ ΠΌΠ΅Ρ€Π΅ Ρ€Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΡ‚ΠΊΠ°Π·Π°Ρ‚ΡŒΡΡ ΠΎΡ‚ YARN ΠΈ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ Π·Π°Π΄Π°Ρ‡ΠΈ Spark Π½Π° Kubernetes, Π½Π΅ опасаясь Π·Π° Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡ‚ΡŒ Π’Π°ΡˆΠ΅ΠΉ систСмы ΠΈ Π±Π΅Π· нСобходимости ΡΠ°ΠΌΠΎΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎΠΉ Π΄ΠΎΡ€Π°Π±ΠΎΡ‚ΠΊΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½Ρ‹Ρ… ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ².

Fin.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com