В предыдущей статье мы увидели, как запустить Spark Applications с оператором Spark. В этой статье мы увидим, как сделать то же самое, но родом с искрой. Сначала объясним различия между двумя способами развертывания вашего водителя на рабочих узлах.
Spark-toke в режиме кластера
В Режим кластера Ваше заявление подано от машины далеко от рабочих машин (например, на вашем ноутбуке). Вам нужно распределение Spark, установленное на этой машине, чтобы на самом деле запустить Spark-Отправить
скрипт В этом режиме скрипт выходит нормально, как только приложение было представлено. Затем водитель отсоединяется и может работать самостоятельно в кластере Куберанес. Вы можете распечатать журналы POD драйвера с Kubectl Logs
Команда, чтобы увидеть вывод приложения.
Можно использовать аутентификацию kubectl
Прокси для связи с API Kubernetes.
Локальный прокси может быть запущен:
kubectl proxy &
Если локальный прокси работает на localhost: 8001, удаленную кластер Kubernetes можно добраться до Spark-Отправить
Указав --master k8s://http://127.0.0.1: 8001
как аргумент для Spark-Отправить
Отказ
Spark – отправить в режиме клиента
В Режим клиента , Spark-Отправить
Команда напрямую передается со своими аргументами к контейнеру искры в POD драйвера. С Режим развертывания
Опция установить на клиент
Драйвер запущен прямо в пределах Spark-Отправить
процесс, который действует как клиент к кластеру. Вход и вывод приложения прикреплен к журналам от POD.
Кто что делает?
С «родной» искрой мы будем выполнять искровые приложения в клиентском режиме, чтобы не зависеть от локального распределения искры. В частности, пользователь создает ресурс POD драйвера с kubectl
и стручок водителя будет работать Spark-Отправить
В клиентском режиме внутренне для запуска водительской программы.
С искровой оператором, A Свечающее применение
должен установить .spec.deploymode.
к кластер
, как клиент
в настоящее время не реализован. За кулисами поведение точно так же, как и с собственной искрой: контроллер оператора встраивает распределение искры, которое играет роль планировщика Spark; Стручки водителя порождают от контроллера … а затем запустить Spark-Отправить
В клиентском режиме внутренне для запуска водительской программы. Но это глобально прозрачно для конечного пользователя.
Дополнительные детали того, как Свечания
запуска можно найти в Проектная документация Отказ
С коренной искрой основным ресурсом является драйвером POD. Для запуска программы PI пример, как с оператором Spark, POD драйвера должен быть создан с использованием данных в следующем файле YAML:
Pyspark-Pi-Driver-Pod.yaml
apiVersion: v1 kind: Pod metadata: labels: app-name: pyspark-pi-${PRIORITY_CLASS_NAME}${NAME_SUFFIX} spark-role: driver name: pyspark-pi-${PRIORITY_CLASS_NAME}${NAME_SUFFIX}-driver namespace: ${NAMESPACE} spec: containers: - name: pyspark-pi image: eu.gcr.io/yippee-spark-k8s/spark-py:3.0.1 imagePullPolicy: IfNotPresent ports: - containerPort: 5678 name: headless-svc - containerPort: 4040 name: web-ui resources: requests: memory: 512Mi cpu: 1 limits: cpu: 1200m env: # Overriding configuration directory - name: SPARK_CONF_DIR value: /spark-conf - name: SPARK_HOME value: /opt/spark # Configure all key-value pairs in ConfigMap as container environment variables envFrom: - configMapRef: name: pyspark-pi-${PRIORITY_CLASS_NAME}${NAME_SUFFIX}-cm args: - $(SPARK_HOME)/bin/spark-submit - /opt/spark/examples/src/main/python/pi.py - "10" volumeMounts: - name: spark-config mountPath: /spark-conf readOnly: true affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: type operator: In values: [${DRIVER_NODE_AFFINITIES}] priorityClassName: ${PRIORITY_CLASS_NAME} restartPolicy: OnFailure schedulerName: volcano serviceAccountName: ${SERVICE_ACCOUNT_NAME} volumes: # Add the executor pod template in read-only volume, for the driver to read - name: spark-config configMap: name: pyspark-pi-${PRIORITY_CLASS_NAME}${NAME_SUFFIX}-cm items: - key: spark-defaults.conf path: spark-defaults.conf - key: spark-env.sh path: spark-env.sh - key: executor-pod-template.yaml path: executor-pod-template.yaml
Не обращайте внимания на вариабельные заполнители уже сейчас Несмотря на то, что вы можете себе представить, для чего они могут быть использованы.
Как видите, драйвер POD зависит от других ресурсов Kubernetes. Мы подробно расскажем каждого из них.
Мы используем Configmap Для установки данных конфигурации искры отдельно от определения POD драйвера.
apiVersion: v1 kind: ConfigMap metadata: labels: app-name: spark-${PRIORITY_CLASS_NAME}${NAME_SUFFIX} name: spark-${PRIORITY_CLASS_NAME}${NAME_SUFFIX}-cm namespace: ${NAMESPACE} data: # Comma-separated list of .zip, .egg, or .py files dependencies for Python apps. # spark.submit.pyFiles can be used instead in spark-defaults.conf below. # PYTHONPATH: ... spark-env.sh: | #!/usr/bin/env bash export DUMMY=dummy echo "Here we are, ${DUMMY}!" spark-defaults.conf: | spark.master k8s://https://kubernetes.default spark.submit.deployMode client spark.executor.instances 2 spark.executor.cores 1 spark.executor.memory 512m spark.kubernetes.executor.container.image eu.gcr.io/yippee-spark-k8s/spark-py:3.0.1 spark.kubernetes.container.image.pullPolicy IfNotPresent spark.kubernetes.namespace spark-jobs # Must match the mount path of the ConfigMap volume in driver pod spark.kubernetes.executor.podTemplateFile /spark-conf/executor-pod-template.yaml spark.kubernetes.pyspark.pythonVersion 2 spark.kubernetes.driver.pod.name spark-${PRIORITY_CLASS_NAME}${NAME_SUFFIX}-driver spark.driver.host spark-${PRIORITY_CLASS_NAME}${NAME_SUFFIX}-driver-svc spark.driver.port 5678 # Config params for use with an ingress to expose the Web UI spark.ui.proxyBase /spark-${PRIORITY_CLASS_NAME}${NAME_SUFFIX} # spark.ui.proxyRedirectUri http://executor-pod-template.yaml: | apiVersion: v1 kind: Pod metadata: labels: app-name: spark-${PRIORITY_CLASS_NAME}${NAME_SUFFIX} spark-role: executor spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: type operator: In values: [${EXECUTOR_NODE_AFFINITIES}] priorityClassName: ${PRIORITY_CLASS_NAME} schedulerName: volcano
Шаблон POD исполнителя
Мы используем файл шаблона в Configmap
Чтобы определить конфигурацию POD исполнителя. Шаблоны Обычно используются для настройки Spark Pods, которые не могут быть настроены в противном случае, через Spark Properties или переменные среды. Таким образом, файлы шаблонов в основном содержат мелкозернируемую конфигурацию, связанную с развертыванием на уровне Kubernetes: здесь, аффинность узла и имя класса приоритета.
Чтобы сделать файл шаблона POD доступен для процесса отправки Spark, мы должны установить свойство искры Spark.kubernetes.executor.podtemplateFile
с его локальным путем в драйвере POD. Для этого файл будет автоматически установлен на том объеме водителя POD, когда он создан.
Коллекция мусора исполнителя
Мы также должны установить Spark.kubernetes.draver.pod.name.
Для исполнителей на имя драйвера POD. Когда это свойство установлено, Spark SCECTULER развернут Pods Исполнителя с помощью OlludherReference
, который, в свою очередь, будет гарантировать, что после удаления POD драйвера удаляется из кластера, все Pods исполнителя приложения также будут удалены.
В клиентском режиме водитель проходит внутри стручка. Искрыватели искры должны быть в состоянии подключиться к драйверу искры с помощью сетей Kubernetes. Для этого мы используем без головы Сервис, позволяющий регулировать POD драйвера из исполнителей устойчивым именем хоста. При развертывании службы без головы, мы гарантируем, что сервис будет соответствовать только для POD драйверов и никаких других стручков, назначая драйверу POD (достаточно) уникальную метку и, используя эту метку в селектор этикетки
безголового обслуживания. Затем мы можем перейти к исполняющим пользователям водительское имя хоста через Spark.driver.host
С именем службы и портом Spark Driver на spark.driver.port
Отказ
Spark-Driver-Svc.yaml
apiVersion: v1 kind: Service metadata: labels: app-name: spark-${PRIORITY_CLASS_NAME}${NAME_SUFFIX} name: spark-${PRIORITY_CLASS_NAME}${NAME_SUFFIX}-driver-svc namespace: spark-jobs spec: clusterIP: None ports: - name: 5678-5678 port: 5678 protocol: TCP targetPort: 5678 selector: app-name: spark-${PRIORITY_CLASS_NAME}${NAME_SUFFIX} spark-role: driver type: ClusterIP
Проходность
Зажигая UI доступна путем создания службы типа Clusterip
который обнажает интернет-интерфейс из стручка драйвера:
Spark-ui-svc.yaml
apiVersion: v1 kind: Service metadata: labels: app-name: spark-${PRIORITY_CLASS_NAME}${NAME_SUFFIX} name: spark-${PRIORITY_CLASS_NAME}${NAME_SUFFIX}-ui-svc namespace: spark-jobs spec: ports: - name: spark-driver-ui-port port: 4040 protocol: TCP targetPort: 4040 selector: app-name: spark-${PRIORITY_CLASS_NAME}${NAME_SUFFIX} spark-role: driver type: ClusterIP
С помощью этой услуги UI доступно только изнутри кластера. Затем мы должны создать Вход
выставлять пользовательский интерфейс вне кластера. Для работы входного ресурса на работу кластер должен иметь контроллер входа Бег. Вы можете выбрать Реализация контроллера входа Что лучше всего подходит для вашего кластера. Трафик и Nginx очень популярные варианты. Приведенный ниже проникновение настроен для Nginx:
Spark-ui-Ingress.yaml
apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: labels: app-name: spark-${PRIORITY_CLASS_NAME}${NAME_SUFFIX} name: spark-${PRIORITY_CLASS_NAME}${NAME_SUFFIX}-ui-ingress namespace: spark-jobs annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/rewrite-target: /$2 nginx.ingress.kubernetes.io/proxy-redirect-from: "http://$host/" nginx.ingress.kubernetes.io/proxy-redirect-to: "http://$host/spark-${PRIORITY_CLASS_NAME}${NAME_SUFFIX}/" spec: rules: - http: paths: - path: /spark-${PRIORITY_CLASS_NAME}${NAME_SUFFIX}(/|$)(.*) backend: serviceName: spark-${PRIORITY_CLASS_NAME}${NAME_SUFFIX}-ui-svc servicePort: 4040
Приступ подкрепленный как многие услуги, что и стручки драйверов, которые работают одновременно в кластере. Каждое UI должно быть адресовано уникальным путь
в проникновении. Оцененный путь напрямую получен от имени зажигания приложения с его уникальным идентификатором.
Интерфейс всегда доступен в http://
(Изнутри кластера), поскольку каждый POD драйвера присваивается уникальный IP и есть только один SparkContext
Бег в хосте POD (в противном случае UI будет связан с последовательными портами, начиная с 4040: 4041, 4042 и т. Д.).
Таким образом, в результате чего разные UIS, которые могут быть доступен в данном времени на одном хосте, отличаются только их назначенным номером порта. UI разработан по этому принципу, и все операции HTTP выполняются относительно того же корневого пути в URL, который … /
Отказ
Таким образом, для пользовательского интерфейса будет эффективно доступен через проникновение, мы должны настроить перенаправление HTTP с альтернативным корневым путем (тот, который настроен в проникновении). Чтобы работать гладко, сам пользовательский интерфейс должен знать об этом перенаправлении, установив Spark.ui.Proxybase
на этот корневой путь … И вот и все!
Оператор искры
Оператор поддерживает создание необязательного входа для веб-интерфейса Spark Web. Это может быть включено, установив Ingress-URL-формат
Флаг командной строки. Ingress-URL-формат
должен быть шаблон, как {{$ appname}}. {ingress_suffix}/{{$ appjects}}/{{$ appname}}
Отказ {ingress_suffix}
Следует заменяться пользователем, чтобы указать URL-адрес кластера, и оператор заменит {{$ appname}}
и {{$ appnamespace}}
с соответствующим значением. Обратите внимание, что входная поддержка требует, чтобы маршрутизатор URL-адреса кластера правильно установлен. Для е.Г. Если Ingress-URL-формат
это {{$ appname}}. Ingress.Cluster.com
это требует что-нибудь * .ingress.Cluster.com.
должен быть направлен на контроллер входа на кластере K8S.
Пример Оператора Spark Установите с Ingress-URL-формат
Флаг командной строки:
./helm install spark-operator incubator/sparkoperator --namespace spark-operator --set enableWebhook=true --set enableBatchScheduler=true --set ingressUrlFormat="\{\{\$appName\}\}.ingress.cluster.com"
Обратите внимание, что фигурные скобки должны быть сбережены.
Будущая работа
Я не мог включить вход за искровой оператор во время моих экспериментов, просто потому, что требуется имя DNS. Вместо этого тот же проникновение, что и для родной искры, «привилось» к Свечающее применение
, с маршрутизацией на основе путь.
Операция, предложенная оператором Spark, с маршрутизацией на основе подстановочных знаков HostName (например * .ingress.Cluster.com.
), тем не менее, интересно, так как он преодолел проблему перенаправления HTTP, описанных выше.
С помощью подстановочных знаков хоста и, следовательно, без перенаправления HTTP, служба пользовательского интерфейса может быть переключена на NodePort
Тип (сервис NodePort обнаруживает службу на IP каждого узла в статическом порту) и все еще будет совместимым с проникновением. Таким образом, интернет-интерфейс будет доступен за пределами кластера с помощью обоих попаданий с его внешним URL-адресом, и NodePort
Сервис на http://
Отказ Сервис типа NodePort
все еще актуален в частном облаке.
Мы используем Имя приложения
Этикетка до семантически группы все ресурсы Kubernetes, связанные с одним зажимом. В нашем случае эта этикетка обеспечивает уникальность, и мы не ожидаем, что множественные зажимательные приложения для несут одинаковое значение для этой этикетки (по крайней мере, в Maintefet Tame – время пространства имен
Для данного зажимного приложения все имена объектов затем выводятся из Имя приложения
Отказ Мы просто добавляем суффикс, который также квалифицирует тип объекта: -раживая
Для подвода драйвера -Ивер-SVC
Для службы водителя, -Уи-SVC
Для сервиса Spark UI, -у-проход
для зажигания ui вход, а -cm
для конфигурации.
Мы также устанавливаем этикетку искровая роль
на уровне стручка, чтобы дифференцировать драйверы от своих исполнителей.
Это именование и маркировка согласуются с оператором Spark. В результате искровые приложения могут быть обработаны и отфильтрованы таким же образом, независимо от того, запущены ли они с помощью оператора Spark или Spark-Sead. 👍.
Теперь нам удалось подражать тому же поведению, которое мы получили с оператором искры, вот то, что мы развернули в Кубейнетах:
Теперь, когда мы определили все наши ресурсы Kubernetes для Spark-Dover, мы собираемся получить наши руки на какой-нибудь код Python, чтобы организовать все это. Увидимся в третьей и окончательной статье в этой серии.
Оригинал: “https://dev.to/stack-labs/my-journey-with-spark-on-kubernetes-in-python-2-3-5e8j”