Это первая часть серии постов о запуске Spark на Kubernetes. Подробнее о преимуществах использования этого подхода вы можете прочитать в этом посте на Spot.io.
К концу этого поста у вас будет локальная среда, готовая к использованию minikube для запуска spark.
Создание локального окружения
За исключением автомасштабирования, которое я буду моделировать с помощью AWS EKS, Cluster Autoscaler и Karpenter, мы будем использовать эту локальную среду для работы со spark на протяжении всего цикла статей. Пост о масштабируемости будет опубликован в ближайшее время.
Вы должны установить minikube, чтобы использовать его локально. Процедура очень проста, а официальная документация доступна здесь.
Совет: я настоятельно рекомендую установить этот плагин, если вы используете ohmyzsh, поскольку он предоставляет вам альтернативу алиасингу популярных команд kubectl.
Давайте создадим многоузловой кластер с 2 узлами после установки minikube
minikube start --nodes 2 -p my-local-cluster
Возможно, вам интересно, почему существует два локальных узла, и ответ заключается в том, что Kubernetes позволяет нам указать, на какой узел мы можем устанавливать наши приложения.
В этом посте мы смоделируем небольшую производственную среду, а в следующем посте драйвер spark будет работать на узлах ON_DEMAND, а исполнители — на узлах SPOT. В результате мы сможем сократить расходы на облако.
Вы можете убедиться, что все получилось, посмотрев на этот вывод в консоли.
Представьте себе следующий гипотетический сценарий: my-local-cluster — это экземпляр ON_DEMAND, а my-local-cluster-m02 — экземпляр SPOT.
Создайте пространство имен обработки, из которого будет выполняться наше задание spark.
$ k create namespace processing
Установка Spark
Прежде чем мы сможем использовать Spark на Kubernetes, необходимо установить оператор SparkOperator. Google создал этот оператор, который доступен на Github. В двух словах, оператор отвечает за мониторинг кластера на предмет определенных событий, связанных с заданием Spark, известным как kind: SparkApplication.
Самый простой способ установки — следовать документации, используя Helm, но мы можем настроить некоторые интересные функции, загрузив шлем SparkOperator
$ helm repo add spark-operator https://googlecloudplatform.github.io/spark-on-k8s-operator
$ helm pull spark-operator/spark-operator
Вы получите следующий результат
Давайте откроем файл values.yaml и внесем некоторые изменения.
...
sparkJobNamespace: "processing"
...
webhook:
enable: true
...
namespaceSelector: kubernetes.io/metadata.name=processing
...
nodeSelector:
kubernetes.io/hostname=my-local-cluster
sparkJobNamescape указывает, какое пространство имен будет использовать SparkOperator для получения событий spark job.
Поскольку в следующем посте мы будем управлять типами экземпляров для драйверов и исполнителей spark, webhook установлен в true. Сейчас не стоит беспокоиться.
Параметр nodeSelector указывает, на какой экземпляр узла будет установлен модуль SparkOperator. Нам нужно убедиться, что мы не потеряем капсулу spark-оператора, поэтому в нашем гипотетическом примере мы используем экземпляр ON_DEMAND.
Запуск для установки
$ helm install <chart-name> <chart-folder> -n <namespace>
$ helm install spark-operator spark-operator -n spark-operator --create-namespace
Теперь у нас установлен и работает SparkOperator.
Последним шагом будет настройка задания spark для запуска.
Пример задания spark, определенного с помощью файла YAML, приведен ниже. Как видите, мы определяем пространство имен обработки, в котором будут выполняться все наши задания spark, а SparkOperator будет получать от него события.
Кроме того, указан тип: SparkApplication.
apiVersion: "sparkoperator.k8s.io/v1beta2"
kind: SparkApplication
metadata:
name: my-job-with-operator
namespace: processing
spec:
type: Scala
mode: cluster
image: "tiagotxm/spark3.1:latest"
imagePullPolicy: Always
mainClass: org.apache.spark.examples.SparkPi
mainApplicationFile: "local:///opt/spark/examples/jars/spark-examples_2.12-3.1.1.jar"
sparkVersion: "3.1.1"
restartPolicy:
type: Never
volumes:
- name: "test-volume"
hostPath:
path: "/tmp"
type: Directory
driver:
cores: 1
coreLimit: "1200m"
memory: "512m"
labels:
version: 3.1.1
serviceAccount: spark-operator-spark
volumeMounts:
- name: "test-volume"
mountPath: "/tmp"
executor:
cores: 3
instances: 3
memory: "512m"
labels:
version: 3.1.1
volumeMounts:
- name: "test-volume"
mountPath: "/tmp"
Мы будем использовать образ spark и запустим простое задание spark, определенное в файле mainApplicationFile, который содержится в образе.
Давайте приступим к выполнению нашего простого задания.
$ k apply -f hello-spark-operator.yaml
Мы можем отслеживать запуск задания и все связанные с spark события, такие как создание драйвера prod и исполнителя.
$ kgpw -n processing
Также можно дважды проверить конечное состояние
$ k get sparkapplications -n processing
Заключение
В этом посте мы создали локальную среду для запуска заданий spark с двумя пространствами имен. SparkOperator был установлен в пространстве имен spark-operator, и теперь он обрабатывает события spark из пространства имен processing.
Надеюсь, этот пост был полезен, а полный пример вы можете найти в моем git-репозитории.
Спасибо за ваше время!
Вы также можете прочитать на Medium, если хотите
Присоединяйтесь ко мне: https://www.linkedin.com/in/tiagotxm/