Ejecución de trabajos de Apache Spark en AKSRunning Apache Spark jobs on AKS

Apache Spark es un motor rápido para el procesamiento de datos a gran escala.Apache Spark is a fast engine for large-scale data processing. Desde la versión de Spark 2.3.0, Apache Spark admite la integración nativa con clústeres de Kubernetes.As of the Spark 2.3.0 release, Apache Spark supports native integration with Kubernetes clusters. Azure Kubernetes Service (AKS) es un entorno de Kubernetes administrado que se ejecuta en Azure.Azure Kubernetes Service (AKS) is a managed Kubernetes environment running in Azure. Este documento detalla la preparación y ejecución de trabajos de Apache Spark en un clúster de Azure Kubernetes Service (AKS).This document details preparing and running Apache Spark jobs on an Azure Kubernetes Service (AKS) cluster.

Requisitos previosPrerequisites

Para completar los pasos de este artículo, necesita lo siguiente.In order to complete the steps within this article, you need the following.

Creación de un clúster de AKSCreate an AKS cluster

Spark se usa para el procesamiento de datos a gran escala y requiere que los nodos Kubernetes tengan el tamaño adecuado para cumplir los requisitos de los recursos de Spark.Spark is used for large-scale data processing and requires that Kubernetes nodes are sized to meet the Spark resources requirements. Se recomienda un tamaño mínimo de Standard_D3_v2 para los nodos de Azure Kubernetes Service (AKS).We recommend a minimum size of Standard_D3_v2 for your Azure Kubernetes Service (AKS) nodes.

Si necesita un clúster de AKS que cumpla esta recomendación mínima, ejecute los siguientes comandos.If you need an AKS cluster that meets this minimum recommendation, run the following commands.

Cree un grupo de recursos para el clúster.Create a resource group for the cluster.

az group create --name mySparkCluster --location eastus

Cree una entidad de servicio para el clúster.Create a Service Principal for the cluster. Una vez creada, necesitará el appId y la contraseña de la entidad de servicio para el siguiente comando.After it is created, you will need the Service Principal appId and password for the next command.

az ad sp create-for-rbac --name SparkSP

Cree el clúster de AKS con nodos de tamaño Standard_D3_v2 y con los valores de appId y contraseña pasados como parámetros service-principal y client-secret.Create the AKS cluster with nodes that are of size Standard_D3_v2, and values of appId and password passed as service-principal and client-secret parameters.

az aks create --resource-group mySparkCluster --name mySparkCluster --node-vm-size Standard_D3_v2 --generate-ssh-keys --service-principal <APPID> --client-secret <PASSWORD>

Conéctese al clúster de AKS.Connect to the AKS cluster.

az aks get-credentials --resource-group mySparkCluster --name mySparkCluster

Si usa Azure Container Registry (ACR) para almacenar las imágenes del contenedor, configure la autenticación entre AKS y ACR.If you are using Azure Container Registry (ACR) to store container images, configure authentication between AKS and ACR. Consulte la documentación de autenticación de ACR para realizar estos pasos.See the ACR authentication documentation for these steps.

Compilación del código fuente de SparkBuild the Spark source

Antes de ejecutar trabajos de Spark en un clúster de AKS, es necesario compilar el código fuente de Spark y empaquetarlo en una imagen de contenedor.Before running Spark jobs on an AKS cluster, you need to build the Spark source code and package it into a container image. El código fuente de Spark incluye scripts que puede utilizar para completar este proceso.The Spark source includes scripts that can be used to complete this process.

Clone el repositorio del proyecto de Spark en el sistema de desarrollo.Clone the Spark project repository to your development system.

git clone -b branch-2.4 https://github.com/apache/spark

Cambie al directorio del repositorio clonado y guarde la ruta de acceso al código fuente de Spark en una variable.Change into the directory of the cloned repository and save the path of the Spark source to a variable.

cd spark
sparkdir=$(pwd)

Si tiene instaladas varias versiones del JDK, establezca JAVA_HOME para utilizar la versión 8 en la sesión actual.If you have multiple JDK versions installed, set JAVA_HOME to use version 8 for the current session.

export JAVA_HOME=`/usr/libexec/java_home -d 64 -v "1.8*"`

Ejecute el siguiente comando para compilar el código fuente de Spark con compatibilidad con Kubernetes.Run the following command to build the Spark source code with Kubernetes support.

./build/mvn -Pkubernetes -DskipTests clean package

El siguiente comando crea la imagen del contenedor de Spark y la inserta en un registro de imagen de contenedor.The following commands create the Spark container image and push it to a container image registry. Reemplace registry.example.com con el nombre de su registro de contenedor y v1 con la etiqueta que prefiera utilizar.Replace registry.example.com with the name of your container registry and v1 with the tag you prefer to use. Si usa Docker Hub, este valor es el nombre del registro.If using Docker Hub, this value is the registry name. Si utiliza Azure Container Registry (ACR), este valor es el nombre del servidor de inicio de sesión de ACR.If using Azure Container Registry (ACR), this value is the ACR login server name.

REGISTRY_NAME=registry.example.com
REGISTRY_TAG=v1
./bin/docker-image-tool.sh -r $REGISTRY_NAME -t $REGISTRY_TAG build

Inserte la imagen del contenedor en el registro de imagen de contenedor.Push the container image to your container image registry.

./bin/docker-image-tool.sh -r $REGISTRY_NAME -t $REGISTRY_TAG push

Preparación de un trabajo de SparkPrepare a Spark job

A continuación, prepare un trabajo de Spark.Next, prepare a Spark job. Se usa un archivo jar para contener el trabajo de Spark y es necesario para ejecutar el comando spark-submit.A jar file is used to hold the Spark job and is needed when running the spark-submit command. El archivo jar puede hacerse accesible a través de una dirección URL pública o preempaquetado dentro de una imagen de contenedor.The jar can be made accessible through a public URL or pre-packaged within a container image. En este ejemplo, se crea un archivo jar de ejemplo para calcular el valor de Pi.In this example, a sample jar is created to calculate the value of Pi. Este archivo jar, a continuación, se carga en Azure Storage.This jar is then uploaded to Azure storage. Si tiene un archivo jar existente, no dude en sustituirloIf you have an existing jar, feel free to substitute

Cree un directorio donde desea crear el proyecto para un trabajo de Spark.Create a directory where you would like to create the project for a Spark job.

mkdir myprojects
cd myprojects

Cree un nuevo proyecto de Scala desde una plantilla.Create a new Scala project from a template.

sbt new sbt/scala-seed.g8

Cuando se le solicite, escriba SparkPi como nombre del proyecto.When prompted, enter SparkPi for the project name.

name [Scala Seed Project]: SparkPi

Vaya al directorio del proyecto recién creado.Navigate to the newly created project directory.

cd sparkpi

Ejecute los comandos siguientes para agregar un complemento de SBT que permite empaquetar el proyecto como un archivo jar.Run the following commands to add an SBT plugin, which allows packaging the project as a jar file.

touch project/assembly.sbt
echo 'addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.10")' >> project/assembly.sbt

Ejecute estos comandos para copiar el código de ejemplo en el proyecto recién creado y agregar todas las dependencias necesarias.Run these commands to copy the sample code into the newly created project and add all necessary dependencies.

EXAMPLESDIR="src/main/scala/org/apache/spark/examples"
mkdir -p $EXAMPLESDIR
cp $sparkdir/examples/$EXAMPLESDIR/SparkPi.scala $EXAMPLESDIR/SparkPi.scala

cat <<EOT >> build.sbt
// https://mvnrepository.com/artifact/org.apache.spark/spark-sql
libraryDependencies += "org.apache.spark" %% "spark-sql" % "2.3.0" % "provided"
EOT

sed -ie 's/scalaVersion.*/scalaVersion := "2.11.11"/' build.sbt
sed -ie 's/name.*/name := "SparkPi",/' build.sbt

Para empaquetar el proyecto en un archivo jar, ejecute el siguiente comando.To package the project into a jar, run the following command.

sbt assembly

Después de empaquetarlo correctamente, debería ver una salida similar a la siguiente.After successful packaging, you should see output similar to the following.

[info] Packaging /Users/me/myprojects/sparkpi/target/scala-2.11/SparkPi-assembly-0.1.0-SNAPSHOT.jar ...
[info] Done packaging.
[success] Total time: 10 s, completed Mar 6, 2018 11:07:54 AM

Copia del trabajo a Azure StorageCopy job to storage

Cree una cuenta de Azure Storage y un contenedor para almacenar el archivo jar.Create an Azure storage account and container to hold the jar file.

RESOURCE_GROUP=sparkdemo
STORAGE_ACCT=sparkdemo$RANDOM
az group create --name $RESOURCE_GROUP --location eastus
az storage account create --resource-group $RESOURCE_GROUP --name $STORAGE_ACCT --sku Standard_LRS
export AZURE_STORAGE_CONNECTION_STRING=`az storage account show-connection-string --resource-group $RESOURCE_GROUP --name $STORAGE_ACCT -o tsv`

Cargue el archivo jar en la cuenta de Azure Storage con los siguientes comandos.Upload the jar file to the Azure storage account with the following commands.

CONTAINER_NAME=jars
BLOB_NAME=SparkPi-assembly-0.1.0-SNAPSHOT.jar
FILE_TO_UPLOAD=target/scala-2.11/SparkPi-assembly-0.1.0-SNAPSHOT.jar

echo "Creating the container..."
az storage container create --name $CONTAINER_NAME
az storage container set-permission --name $CONTAINER_NAME --public-access blob

echo "Uploading the file..."
az storage blob upload --container-name $CONTAINER_NAME --file $FILE_TO_UPLOAD --name $BLOB_NAME

jarUrl=$(az storage blob url --container-name $CONTAINER_NAME --name $BLOB_NAME | tr -d '"')

La variable jarUrl ahora contiene la ruta de acceso pública al archivo jar.Variable jarUrl now contains the publicly accessible path to the jar file.

Envío de un trabajo de SparkSubmit a Spark job

Inicie kube-proxy en otra línea de comandos con el código siguiente.Start kube-proxy in a separate command-line with the following code.

kubectl proxy

Vuelva hasta la raíz del repositorio de Spark.Navigate back to the root of Spark repository.

cd $sparkdir

Cree una cuenta de servicio que tenga permisos suficientes para ejecutar un trabajo.Create a service account that has sufficient permissions for running a job.

kubectl create serviceaccount spark
kubectl create clusterrolebinding spark-role --clusterrole=edit --serviceaccount=default:spark --namespace=default

Envíe el trabajo mediante spark-submit.Submit the job using spark-submit.

./bin/spark-submit \
  --master k8s://http://127.0.0.1:8001 \
  --deploy-mode cluster \
  --name spark-pi \
  --class org.apache.spark.examples.SparkPi \
  --conf spark.executor.instances=3 \
  --conf spark.kubernetes.authenticate.driver.serviceAccountName=spark \
  --conf spark.kubernetes.container.image=$REGISTRY_NAME/spark:$REGISTRY_TAG \
  $jarUrl

Esta operación inicia el trabajo de Spark, que transmite el estado del trabajo a la sesión de shell.This operation starts the Spark job, which streams job status to your shell session. Mientras se ejecuta el trabajo, puede ver el pod del controlador de Spark y los pod del ejecutor mediante el comando kubectl get pods.While the job is running, you can see Spark driver pod and executor pods using the kubectl get pods command. Abra una segunda sesión de terminal para ejecutar estos comandos.Open a second terminal session to run these commands.

kubectl get pods
NAME                                               READY     STATUS     RESTARTS   AGE
spark-pi-2232778d0f663768ab27edc35cb73040-driver   1/1       Running    0          16s
spark-pi-2232778d0f663768ab27edc35cb73040-exec-1   0/1       Init:0/1   0          4s
spark-pi-2232778d0f663768ab27edc35cb73040-exec-2   0/1       Init:0/1   0          4s
spark-pi-2232778d0f663768ab27edc35cb73040-exec-3   0/1       Init:0/1   0          4s

Mientras se ejecuta el trabajo, también puede acceder a la interfaz de usuario de Spark.While the job is running, you can also access the Spark UI. En la segunda sesión de terminal, use el comando kubectl port-forward para proporcionar acceso a la interfaz de usuario de Spark.In the second terminal session, use the kubectl port-forward command provide access to Spark UI.

kubectl port-forward spark-pi-2232778d0f663768ab27edc35cb73040-driver 4040:4040

Para acceder a la interfaz de usuario de Spark, abra la dirección 127.0.0.1:4040 en un explorador.To access Spark UI, open the address 127.0.0.1:4040 in a browser.

Interfaz de usuario de Spark

Obtención de los resultados y registros del trabajoGet job results and logs

Cuando haya finalizado el trabajo, el pod del controlador estará en un estado "Completado".After the job has finished, the driver pod will be in a "Completed" state. Puede obtener el nombre del pod con el siguiente comando.Get the name of the pod with the following command.

kubectl get pods --show-all

Salida:Output:

NAME                                               READY     STATUS      RESTARTS   AGE
spark-pi-2232778d0f663768ab27edc35cb73040-driver   0/1       Completed   0          1m

Use el comando kubectl logs para obtener los registros del pod del controlador de Spark.Use the kubectl logs command to get logs from the spark driver pod. Sustituya el nombre del pod por el nombre del pod del controlador.Replace the pod name with your driver pod's name.

kubectl logs spark-pi-2232778d0f663768ab27edc35cb73040-driver

En estos registros, puede ver el resultado del trabajo de Spark, que es el valor de Pi.Within these logs, you can see the result of the Spark job, which is the value of Pi.

Pi is roughly 3.152155760778804

Paquete jar con la imagen de contenedorPackage jar with container image

En el ejemplo anterior, el archivo jar de Spark se cargó en Azure Storage.In the above example, the Spark jar file was uploaded to Azure storage. Otra opción consiste en empaquetar el archivo jar en imágenes de Docker personalizadas.Another option is to package the jar file into custom-built Docker images.

Para ello, busque el archivo dockerfile de la imagen de Spark ubicado en el directorio $sparkdir/resource-managers/kubernetes/docker/src/main/dockerfiles/spark/.To do so, find the dockerfile for the Spark image located at $sparkdir/resource-managers/kubernetes/docker/src/main/dockerfiles/spark/ directory. Agregue una instrucción ADD al trabajo de Spark jar en algún lugar entre las declaraciones WORKDIR y ENTRYPOINT.Add an ADD statement for the Spark job jar somewhere between WORKDIR and ENTRYPOINT declarations.

Actualice la ruta de acceso del archivo jar con la ubicación del archivo SparkPi-assembly-0.1.0-SNAPSHOT.jar en el sistema de desarrollo.Update the jar path to the location of the SparkPi-assembly-0.1.0-SNAPSHOT.jar file on your development system. También puede utilizar su propio archivo jar personalizado.You can also use your own custom jar file.

WORKDIR /opt/spark/work-dir

ADD /path/to/SparkPi-assembly-0.1.0-SNAPSHOT.jar SparkPi-assembly-0.1.0-SNAPSHOT.jar

ENTRYPOINT [ "/opt/entrypoint.sh" ]

Compile e inserte la imagen con los scripts de Spark incluidos.Build and push the image with the included Spark scripts.

./bin/docker-image-tool.sh -r <your container repository name> -t <tag> build
./bin/docker-image-tool.sh -r <your container repository name> -t <tag> push

Cuando se ejecuta el trabajo, en lugar de indicar una dirección URL del archivo jar remoto, puede usar el esquema local:// con la ruta de acceso al archivo jar en la imagen de Docker.When running the job, instead of indicating a remote jar URL, the local:// scheme can be used with the path to the jar file in the Docker image.

./bin/spark-submit \
    --master k8s://https://<k8s-apiserver-host>:<k8s-apiserver-port> \
    --deploy-mode cluster \
    --name spark-pi \
    --class org.apache.spark.examples.SparkPi \
    --conf spark.executor.instances=3 \
    --conf spark.kubernetes.authenticate.driver.serviceAccountName=spark \
    --conf spark.kubernetes.container.image=<spark-image> \
    local:///opt/spark/work-dir/<your-jar-name>.jar

Advertencia

De la documentación de Spark: "Actualmente, el programador de Kubernetes es experimental.From Spark documentation: "The Kubernetes scheduler is currently experimental. En versiones futuras, puede haber cambios de comportamiento en la configuración, las imágenes de contenedor y los puntos de entrada."In future versions, there may be behavioral changes around configuration, container images and entrypoints".

Pasos siguientesNext steps

Consulte la documentación de Spark para más detalles.Check out Spark documentation for more details.