Pagpadagan sa Apache Spark sa Kubernetes

Dear readers, maayong hapon. Karon maghisgot kami gamay bahin sa Apache Spark ug ang mga prospect sa pag-uswag niini.

Pagpadagan sa Apache Spark sa Kubernetes

Sa modernong kalibutan sa Big Data, ang Apache Spark mao ang de facto nga sumbanan alang sa pagpalambo sa mga buluhaton sa pagproseso sa datos sa batch. Dugang pa, gigamit usab kini sa paghimo sa mga aplikasyon sa streaming nga nagtrabaho sa konsepto sa micro batch, pagproseso ug pag-upload sa datos sa gagmay nga mga bahin (Spark Structured Streaming). Ug sa naandan kini nahimong bahin sa kinatibuk-ang Hadoop stack, gamit ang YARN (o, sa pipila ka mga kaso, Apache Mesos) isip manager sa kapanguhaan. Pagka 2020, ang paggamit niini sa tradisyonal nga porma niini alang sa kadaghanan sa mga kompanya naa sa ilawom sa usa ka dako nga pangutana tungod sa kakulang sa disente nga mga pag-apod-apod sa Hadoop - ang pag-uswag sa HDP ug CDH mihunong, ang CDH wala maugmad ug adunay taas nga gasto, ug ang nahabilin sa Hadoop Ang mga tighatag wala na maglungtad o adunay dili klaro nga kaugmaon. Busa, ang komunidad ug dagkong mga kompaniya mas interesado sa pagpadagan sa Apache Spark gamit ang Kubernetes - nga nahimong sumbanan sa container orchestration ug pagdumala sa kahinguhaan sa pribado ug publikong mga panganod, kini nagsulbad sa problema sa dili kombenyente nga pagplano sa kahinguhaan alang sa mga buluhaton sa Spark sa YARN ug naghatag ug makanunayon nga paagi. nagpalambo nga plataporma nga adunay daghang komersyal ug bukas nga gigikanan nga pag-apod-apod alang sa mga kompanya sa tanan nga gidak-on. Dugang pa, sa balud sa pagkapopular, kadaghanan nakahimo na sa pag-angkon og usa ka magtiayon nga mga instalasyon sa ilang kaugalingon ug nagtukod og kahanas sa paggamit niini, nga nagpayano sa paglihok.

Sugod sa bersyon 2.3.0, ang Apache Spark nakadawat og opisyal nga suporta alang sa pagpadagan sa mga buluhaton sa usa ka Kubernetes cluster, ug karon atong hisgutan ang kasamtangan nga pagkahamtong niini nga pamaagi, lain-laing mga kapilian sa paggamit niini, ug mga lit-ag nga masugatan sa panahon sa pagpatuman.

Una sa tanan, atong tan-awon ang proseso sa pagpalambo sa mga buluhaton ug mga aplikasyon base sa Apache Spark ug i-highlight ang kasagarang mga kaso diin gusto nimong magpadagan sa usa ka buluhaton sa usa ka Kubernetes cluster. Sa pag-andam niini nga post, ang OpenShift gigamit isip usa ka pag-apod-apod ug ang mga sugo nga may kalabutan sa iyang command line utility (oc) ihatag. Para sa ubang mga distribusyon sa Kubernetes, ang angay nga mga sugo sa standard Kubernetes command line utility (kubectl) o ang mga katumbas niini (pananglitan, para sa oc adm policy) mahimong gamiton.

Ang unang kaso sa paggamit mao ang spark-submit

Atol sa pag-uswag sa mga buluhaton ug aplikasyon, ang developer kinahanglan nga magpadagan sa mga buluhaton aron ma-debug ang pagbag-o sa datos. Sa teoriya, ang mga stub mahimong magamit alang niini nga mga katuyoan, apan ang pag-uswag nga naglambigit sa tinuod (bisan pagsulay) nga mga higayon sa mga sistema sa katapusan napamatud-an nga mas paspas ug mas maayo niini nga klase sa mga buluhaton. Sa kaso kung nag-debug kami sa tinuud nga mga higayon sa mga sistema sa katapusan, posible ang duha nga mga senaryo sa trabaho:

  • ang developer nagpadagan sa Spark nga buluhaton sa lokal sa standalone mode;

    Pagpadagan sa Apache Spark sa Kubernetes

  • ang usa ka developer nagpadagan sa usa ka Spark nga buluhaton sa usa ka Kubernetes cluster sa usa ka test loop.

    Pagpadagan sa Apache Spark sa Kubernetes

Ang una nga kapilian adunay katungod nga maglungtad, apan adunay daghang mga kakulangan:

  • alang sa matag developer, gikinahanglan ang paghatag og access gikan sa trabahoan ngadto sa tanang mga higayon sa end system nga iyang gikinahanglan;
  • igo nga mga kapanguhaan ang gikinahanglan sa makina sa produksiyon aron mapadagan ang buluhaton nga gipalambo.

Ang ikaduha nga kapilian wala niini nga mga kakulangan, tungod kay ang paggamit sa usa ka Kubernetes cluster nagtugot kanimo sa paggahin sa gikinahanglan nga pundok sa mga kahinguhaan aron sa pagpadagan sa mga buluhaton ug paghatag niini sa gikinahanglan nga pag-access sa mga higayon sa mga end system, nga flexible nga naghatag og access niini gamit ang Kubernetes role model alang sa tanang miyembro sa development team. Ato kining ipasiugda isip unang kaso sa paggamit - pagpadagan sa mga buluhaton sa Spark gikan sa usa ka lokal nga makina sa developer sa usa ka Kubernetes cluster sa usa ka test circuit.

Atong tan-awon pag-ayo ang proseso sa pag-set up sa Spark nga modagan sa lokal. Sa pagsugod sa paggamit sa Spark, kinahanglan nimo nga i-install kini:

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

Gikolekta namo ang gikinahanglan nga mga pakete alang sa pagtrabaho uban sa Kubernetes:

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

Ang usa ka bug-os nga pagtukod nagkinahanglan og daghang panahon, ug sa pagkatinuod, ang mga garapon lamang gikan sa "assembly/" nga direktoryo ang gikinahanglan aron makahimo og mga hulagway sa Docker ug ipadagan kini sa usa ka Kubernetes cluster, mao nga kini nga subproject lamang ang mahimo:

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

Ang pagpadagan sa mga buluhaton sa Spark sa Kubernetes nanginahanglan kanimo nga maghimo usa ka imahe sa Docker aron magamit ingon usa ka base nga imahe. Adunay 2 nga posible nga mga pamaagi dinhi:

  • Ang namugna nga Docker nga imahe naglakip sa Spark task executable code;
  • Ang gibuhat nga imahe naglakip lamang sa Spark ug sa gikinahanglan nga mga dependency, ang executable code gi-host sa layo (pananglitan, sa HDFS).

Una, maghimo kita usa ka imahe sa Docker nga adunay sulud nga kaso sa pagsulay sa Spark task. Aron makahimo og mga imahe sa Docker, ang Spark adunay katugbang nga utility nga gitawag nga "docker-image-tool". Atong tun-an kini alang sa tabang:

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

Mahimo kini gamiton sa paghimo og mga imahe sa Docker ug i-upload kini sa hilit nga mga rehistro, apan sa default kini adunay daghang mga disbentaha:

  • sa walay pakyas nagmugna og 3 ka Docker nga mga hulagway sa makausa - para sa Spark, PySpark ug R;
  • wala magtugot kanimo sa pagpiho sa usa ka ngalan sa imahe.

Busa, mogamit kami usa ka giusab nga bersyon sa kini nga utility, nga gihatag sa ubos:

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

Uban sa tabang niini, nagtukod kami usa ka sukaranan nga imahe sa Spark nga adunay sulud nga pagsulay alang sa pagkalkula sa numero nga Pi gamit ang Spark (dinhi {docker-registry-url} ang URL sa imong rehistro sa imahe sa Docker, {repo} ang ngalan sa repositoryo sa sulod. ang registry, nga mohaum sa proyekto sa OpenShift , {image-name} — image name (kon ang tulo-ka-level nga image separation gigamit, pananglitan, sama sa Red Hat OpenShift integrated image registry), {tag} — tag niini nga hulagway bersyon):

./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

Pagtugot sa OKD cluster gamit ang console utility (dinhi ang {OKD-API-URL} mao ang OKD cluster API URL):

oc login {OKD-API-URL}

Atong kuhaon ang kasamtangan nga token sa tiggamit alang sa pagtugot sa Docker Registry:

oc whoami -t

Pagtugot sa internal nga Docker Registry sa OKD cluster (gigamit namo ang token nga nakuha gamit ang miaging command isip password):

docker login {docker-registry-url}

Pag-upload sa gitukod nga imahe sa Docker sa Docker Registry OKD:

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

Atong susihon nga ang gitukod nga imahe anaa sa OKD. Aron mahimo kini, ablihi ang URL nga adunay lista sa mga imahe sa katugbang nga proyekto sa browser (dinhi ang {proyekto} ang ngalan sa proyekto sulod sa OpenShift cluster, {OKD-WEBUI-URL} mao ang URL sa OpenShift Web Console ) — https://{OKD-WEBUI-URL}/console /project/{project}/browse/images/{image-name}.

Aron makadagan ang mga buluhaton, kinahanglan nga maghimo usa ka account sa serbisyo nga adunay mga pribilehiyo sa pagpadagan sa mga pod ingon gamut (atong hisgutan kini nga punto sa ulahi):

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

Atong padaganon ang spark-submit command aron imantala ang Spark task ngadto sa OKD cluster, nga nagtino sa gibuhat nga service account ug sa Docker image:

 /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

Здесь:

--ngalan - ang ngalan sa buluhaton nga moapil sa pagporma sa ngalan sa mga Kubernetes pod;

--class — klase sa executable file nga gitawag kung magsugod ang buluhaton;

--conf - Mga parametro sa pagsumpo sa Spark;

spark.executor.instances - gidaghanon sa mga Spark executor nga modagan

spark.kubernetes.authenticate.driver.serviceAccountName - Ang ngalan sa account sa serbisyo sa Kubernetes nga gigamit sa pagpadagan sa Pods (aron ipasabot ang konteksto sa seguridad ug mga kapabilidad sa dihang nakig-interact sa Kubernetes API)

spark.kubernetes.namespace - ang Kubernetes namespace diin ang mga driver ug executor pod modagan;

spark.submit.deployMode - unsaon pagsugod sa Spark (alang sa standard nga spark-submit gamit ang "cluster", para sa Spark Operator ug sa ulahi nga mga bersyon sa Spark "kliyente");

Ang spark.kubernetes.container.image mao ang Docker image nga gigamit sa pagpadagan sa Pods.

spark.master - Kubernetes API URL (gipiho ang gawas aron ang tawag gihimo gikan sa lokal nga makina);

local: // mao ang agianan sa Spark executable sulod sa Docker image.

Moadto kami sa katugbang nga proyekto sa OKD ug tun-an ang gibuhat nga mga pod - https://{OKD-WEBUI-URL}/console/project/{project}/browse/pods.

Aron pasimplehon ang proseso sa pag-uswag, mahimo’g magamit ang lain nga kapilian, diin gihimo ang usa ka sagad nga base nga imahe sa Spark, gigamit sa tanan nga mga buluhaton nga pagdagan, ug ang mga snapshot sa mga executable nga file gipatik sa gawas nga pagtipig (pananglitan, Hadoop) ug gipiho kung nagtawag sa spark. -isumite ingon usa ka link. Sa kini nga kaso, mahimo nimong ipadagan ang lainlaing mga bersyon sa mga buluhaton sa Spark nga wala magtukod pag-usab sa mga imahe sa Docker gamit, pananglitan, WebHDFS aron ma-publish ang mga imahe. Nagpadala kami usa ka hangyo nga maghimo usa ka file (dinhi ang {host} mao ang host sa serbisyo sa WebHDFS, ang {port} mao ang pantalan sa serbisyo sa WebHDFS, {path-to-file-on-hdfs} ang gusto nga agianan sa file sa HDFS):

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

Mobalik kini og tubag sa porma (dinhi ang {lokasyon} mao ang URL nga gamiton sa pag-download sa file):

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

I-upload ang Spark executable sa HDFS (diin ang {path-to-local-file} mao ang dalan paingon sa Spark executable sa kasamtangang host):

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

Human niana, mahimo namong i-spark-submit gamit ang Spark file nga gi-upload sa HDFS (dinhi ang {class-name} mao ang ngalan sa klase nga kinahanglang padagan aron makompleto ang buluhaton):

/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}

Sa parehas nga oras, kinahanglan nga matikdan nga aron ma-access ang HDFS ug mahimo ang buluhaton, mahimo’g kinahanglan nga usbon ang Dockerfile ug ang entrypoint.sh nga script - pagdugang usa ka direktiba sa Dockerfile aron kopyahon ang nagsalig nga mga librarya sa /opt /spark/jars directory ug iapil ang HDFS configuration file sa SPARK_CLASSPATH sa entrypoint. sh.

Ang ikaduha nga kaso sa paggamit mao ang Apache Livy

Dugang pa, kung ang buluhaton naugmad ug gikinahanglan nga sulayan ang resulta nga nakuha, ang pangutana mitungha sa paglansad niini isip bahin sa proseso sa CI / CD ug pagsubay sa kahimtang sa pagpatuman niini. Siyempre, mahimo nimo kini ipadagan sa usa ka lokal nga tawag sa pag-spark-submit, apan kini nagpakomplikado sa imprastraktura sa CI / CD tungod kay kini nanginahanglan sa pag-install ug pag-configure sa Spark sa mga ahente / runner sa CI server ug ang pag-configure sa pag-access sa mga Kubernetes API. Alang niini nga kaso, gipili sa target nga pagpatuman ang paggamit sa Apache Livy isip REST API alang sa pagpadagan sa mga buluhaton sa Spark nga gi-host sulod sa usa ka Kubernetes cluster. Uban niini, mahimo nimong ipadagan ang mga buluhaton sa Spark sa usa ka cluster sa Kubernetes gamit ang regular nga mga hangyo sa cURL, nga dali nga gipatuman base sa bisan unsang solusyon sa CI, ug ang pagbutang niini sa sulod sa cluster sa Kubernetes nagsulbad sa isyu sa pag-authenticate kung nakig-uban sa Kubernetes API.

Pagpadagan sa Apache Spark sa Kubernetes

Ato kining pilion isip ikaduhang kaso sa paggamit - pagpadagan sa mga buluhaton sa Spark isip kabahin sa proseso sa CI/CD sa usa ka Kubernetes cluster sa usa ka test circuit.

Usa ka gamay bahin sa Apache Livy - kini naglihok ingon usa ka HTTP server nga naghatag usa ka interface sa Web ug usa ka RESTful API nga nagtugot kanimo sa layo nga paglansad sa spark-submit pinaagi sa pagpasa sa kinahanglan nga mga parameter. Tradisyonal kini nga gipadala isip bahin sa pag-apod-apod sa HDP, apan mahimo usab nga i-deploy sa OKD o bisan unsang uban pang pag-install sa Kubernetes gamit ang angay nga pagpakita ug usa ka set sa mga imahe sa Docker, sama niini - github.com/ttauveron/k8s-big-data-experiments/tree/master/livy-spark-2.3. Alang sa among kaso, usa ka susama nga imahe sa Docker ang gitukod, lakip ang Spark nga bersyon 2.4.5 gikan sa mosunud nga 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"]

Ang namugna nga hulagway mahimong matukod ug ma-upload sa usa ka Docker repository nga naa nimo, sama sa internal OKD repository. Sa pag-deploy niini, gigamit ang mosunod nga manifest ({registry-url} mao ang URL sa Docker image registry, {image-name} mao ang ngalan sa Docker image, {tag} mao ang tag sa Docker image, {livy -url} mao ang gitinguha nga URL diin ang server mahimong magamit nga Livy; ang "Route" nga pagpakita gigamit kung ang Red Hat OpenShift gigamit ingon nga pag-apod-apod sa Kubernetes, kung dili ang katugbang nga Ingress o Serbisyo nga pagpakita sa tipo nga NodePort gigamit):

---
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

Human sa paggamit niini ug malampuson nga pagpadagan sa pod, ang Livy GUI anaa sa: http://{livy-url}/ui. Uban ni Livy, mahimo namon nga imantala ang among buluhaton sa Spark gamit ang usa ka REST nga hangyo gikan sa Postman, pananglitan. Usa ka pananglitan sa usa ka koleksyon nga adunay mga hangyo gipresentar sa ubos (ang mga argumento sa pag-configure nga adunay mga variable nga gikinahanglan alang sa trabaho sa gilunsad nga buluhaton mahimong ipasa sa "args" array):

{
    "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": {}
}

Atong ipatuman ang unang hangyo gikan sa koleksyon, adto sa OKD interface ug susiha nga ang buluhaton malampuson nga gilunsad - https://{OKD-WEBUI-URL}/console/project/{project}/browse/pods. Sa samang higayon, usa ka sesyon ang makita sa Livy interface (http://{livy-url}/ui), diin, gamit ang Livy API o usa ka graphical interface, mahimo nimong bantayan ang pag-uswag sa buluhaton ug tun-an ang mga log sa sesyon.

Karon ipakita nato kung giunsa ni Livy ang pagtrabaho. Aron mahimo kini, atong susihon ang mga log sa Livy nga sudlanan sulod sa pod gamit ang Livy server - https://{OKD-WEBUI-URL}/console/project/{project}/browse/pods/{livy-pod-name }?tab=mga troso. Makita nimo gikan kanila nga kung nagtawag sa Livy REST API sa usa ka sudlanan nga ginganlag "livy", usa ka spark-submit ang gihimo, parehas sa among gigamit sa ibabaw (dinhi ang {livy-pod-name} ang ngalan sa gibuhat nga pod uban sa Livy server). Naghatag usab ang koleksyon og ikaduha nga pangutana nga nagtugot kanimo sa pagpadagan sa mga buluhaton nga adunay hilit nga pag-host sa Spark executable gamit ang Livy server.

Ikatulo nga kaso sa paggamit - Spark Operator

Karon nga ang buluhaton nasulayan na, ang pangutana mitungha sa regular nga paglansad niini. Ang lumad nga paagi sa regular nga pagpadagan sa mga buluhaton sa usa ka Kubernetes cluster mao ang CronJob entity ug mahimo nimo kini gamiton, apan sa pagkakaron ang paggamit sa mga operators alang sa pagdumala sa mga aplikasyon sa Kubernetes popular kaayo ug adunay usa ka medyo hamtong nga operator alang sa Spark, nga, taliwala sa ubang mga butang, gigamit sa Enterprise-level nga mga solusyon (pananglitan, Lightbend FastData Platform). Among girekomendar ang paggamit niini - ang kasamtangan nga stable nga bersyon sa Spark (2.4.5) adunay limitado nga mga opsyon alang sa pag-configure sa paglunsad sa Spark nga mga buluhaton sa Kubernetes, samtang ang sunod nga mayor nga bersyon (3.0.0) nag-angkon sa hingpit nga suporta alang sa Kubernetes, apan ang petsa sa pagpagawas niini nagpabilin nga wala mailhi. Ang Spark Operator naghimo niini pinaagi sa pagdugang sa importante nga mga opsyon sa pag-configure (sama sa pag-mount sa usa ka ConfigMap nga adunay Hadoop access configuration ngadto sa Spark Pods) ug ang abilidad sa pagpadagan sa usa ka naka-iskedyul nga buluhaton sa usa ka regular nga basehan.

Pagpadagan sa Apache Spark sa Kubernetes
Atong i-isa kini isip ikatulo nga kaso sa paggamit - kanunay nga nagpadagan sa mga buluhaton sa Spark sa usa ka Kubernetes cluster sa usa ka production loop.

Ang Spark Operator kay bukas nga tinubdan ug naugmad sulod sa Google Cloud Platform − github.com/GoogleCloudPlatform/spark-on-k8s-operator. Mahimo kining i-install sa 3 ka paagi:

  1. Isip bahin sa pag-instalar sa Lightbend FastData Platform/Cloudflow;
  2. Uban sa Helms:
    helm repo add incubator http://storage.googleapis.com/kubernetes-charts-incubator
    helm install incubator/sparkoperator --namespace spark-operator
    	

  3. Gamit ang mga manifests gikan sa opisyal nga repository (https://github.com/GoogleCloudPlatform/spark-on-k8s-operator/tree/master/manifest). Sa samang higayon, angay nga hinumdoman ang mosunod - Cloudflow naglakip sa usa ka operator nga adunay API nga bersyon sa v1beta1. Kung kini nga klase sa pag-install gigamit, nan ang Spark application manifest nga mga paghulagway kinahanglan ibase sa mga pananglitan gikan sa mga tag sa Git nga adunay angay nga bersyon sa API, pananglitan, "v1beta1-0.9.0-2.4.0". Ang bersyon sa operator mahimong tan-awon sa paghulagway sa CRD nga bahin sa operator sa "bersyon" nga diksyonaryo:
    oc get crd sparkapplications.sparkoperator.k8s.io -o yaml
    	

Kung husto ang pag-install sa operator, nan ang katugbang nga proyekto adunay usa ka aktibo nga Pod kauban ang Spark operator (pananglitan, cloudflow-fdp-sparkoperator sa Cloudflow space para sa pag-install sa Cloudflow) ug ang katugbang nga tipo sa kapanguhaan sa Kubernetes nga ginganlag "sparkapplications" makita. Mahimo nimong susihon ang magamit nga mga aplikasyon sa Spark gamit ang mosunud nga mando:

oc get sparkapplications -n {project}

Aron makadagan ang mga buluhaton gamit ang Spark Operator, kinahanglan nimong buhaton ang 3 ka butang:

  • paghimo usa ka imahe sa Docker nga naglakip sa tanan nga kinahanglan nga mga librarya, ingon man ang pag-configure ug mga executable nga mga file. Sa target nga litrato, kini usa ka imahe nga gihimo sa yugto sa CI / CD ug gisulayan sa usa ka cluster sa pagsulay;
  • i-publish ang imahe sa Docker sa usa ka rehistro nga ma-access gikan sa cluster sa Kubernetes;
  • paghimo usa ka manifest nga adunay tipo nga "SparkApplication" ug usa ka paghulagway sa buluhaton nga ilunsad. Ang mga sample nga manifests anaa sa opisyal nga repository (pananglitan, github.com/GoogleCloudPlatform/spark-on-k8s-operator/blob/v1beta1-0.9.0-2.4.0/examples/spark-pi.yaml). Angay nga matikdan ang hinungdanon nga mga punto bahin sa manifesto:
    1. ang "apiVersion" nga diksyonaryo kinahanglan adunay sulud nga bersyon sa API nga katumbas sa bersyon sa operator;
    2. ang "metadata.namespace" nga diksyonaryo kinahanglan adunay sulod sa namespace diin ang aplikasyon ilunsad;
    3. ang "spec.image" nga diksyonaryo kinahanglan adunay sulud sa adres sa gibuhat nga imahe sa Docker sa magamit nga rehistro;
    4. ang "spec.mainClass" nga diksyonaryo kinahanglan nga adunay klase sa Spark nga buluhaton nga gusto nimo nga padagan kung magsugod ang proseso;
    5. ang "spec.mainApplicationFile" nga diksyonaryo kinahanglang adunay dalan paingon sa executable jar file;
    6. ang "spec.sparkVersion" nga diksyonaryo kinahanglan nga bersyon sa Spark nga gigamit;
    7. ang "spec.driver.serviceAccount" nga diksyonaryo kinahanglang adunay sulod sa service account sulod sa katugbang nga namespace sa Kubernetes nga gamiton sa pagpadagan sa aplikasyon;
    8. ang "spec.executor" nga diksyonaryo kinahanglan magpakita sa kantidad sa mga kapanguhaan nga gigahin sa aplikasyon;
    9. ang "spec.volumeMounts" nga diksyonaryo kinahanglan nga ibutang sa lokal nga direktoryo diin ang lokal nga Spark task files pagabuhaton.

Usa ka pananglitan sa paghimo og manifest (dinhi ang {spark-service-account} usa ka service account sulod sa Kubernetes cluster para sa pagpadagan sa mga buluhaton sa 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"

Kini nga manifest nagtino sa usa ka account sa serbisyo diin kinahanglan nimo nga maghimo sa gikinahanglan nga mga pagbugkos sa papel sa dili pa imantala ang manifest, nga naghatag sa gikinahanglan nga mga katungod sa pag-access alang sa Spark nga aplikasyon aron makig-uban sa Kubernetes API (kon gikinahanglan). Sa among kaso, ang aplikasyon nanginahanglan mga katungod sa paghimo og mga Pod. Himoon nato ang gikinahanglan nga role binding:

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

Angay usab nga hinumdoman nga ang parameter nga "hadoopConfigMap" mahimong matino sa espesipikasyon niini nga manifest, nga nagtugot kanimo sa pagtino sa usa ka ConfigMap nga adunay usa ka configuration sa Hadoop nga dili kinahanglan una nga ibutang ang katugbang nga file sa Docker nga imahe. Angayan usab kini alang sa regular nga paglansad sa mga buluhaton - gamit ang parameter nga "iskedyul", ang iskedyul sa paglansad niini nga buluhaton mahimong matino.

Human niana, among i-save ang among manifest sa spark-pi.yaml file ug i-apply kini sa among Kubernetes cluster:

oc apply -f spark-pi.yaml

Makahimo kini usa ka butang nga tipo nga "sparkapplications":

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

Maghimo kini og usa ka pod nga adunay usa ka aplikasyon kansang status ipakita sa gibuhat nga "sparkapplications". Kini mahimong tan-awon uban sa mosunod nga sugo:

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

Sa pagkompleto sa buluhaton, ang POD moadto sa "Nakumpleto" nga kahimtang, nga ma-update usab sa "sparkapplications". Ang mga log sa aplikasyon mahimong tan-awon sa browser o sa mosunod nga sugo (dinhi {sparkapplications-pod-name} ang ngalan sa nagdagan nga buluhaton pod):

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

Usab, ang mga buluhaton sa Spark mahimong madumala gamit ang espesyal nga sparkctl utility. Aron ma-install kini, among gi-clone ang repository gamit ang source code, i-install ang Go ug tukuron kini nga utility:

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

Atong susihon ang lista sa pagpadagan sa mga buluhaton sa Spark:

sparkctl list -n {project}

Maghimo kita og usa ka paghulagway alang sa buluhaton sa 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"

Atong daganon ang gihulagway nga buluhaton gamit ang sparkctl:

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

Atong susihon ang lista sa pagpadagan sa mga buluhaton sa Spark:

sparkctl list -n {project}

Atong susihon ang lista sa mga panghitabo sa nagdagan nga buluhaton sa Spark:

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

Atong susihon ang kahimtang sa nagdagan nga buluhaton sa Spark:

sparkctl status spark-pi -n {project}

Sa konklusyon, gusto nakong ikonsiderar ang nadiskobrehan nga mga disbentaha sa pag-operate sa kasamtangan nga stable nga bersyon sa Spark (2.4.5) sa Kubernetes:

  1. Ang una ug, tingali, ang nag-unang disbentaha mao ang kakulang sa Data Locality. Bisan pa sa tanan nga mga kakulangan sa YARN, adunay mga plus sa paggamit niini, pananglitan, ang prinsipyo sa paghatud sa code ngadto sa datos (kaysa data sa code). Salamat kaniya, ang mga buluhaton sa Spark gihimo sa mga node diin ang mga datos nga nahilambigit sa mga kalkulasyon nahimutang, ug ang oras sa paghatud sa datos sa tibuuk nga network namatikdan nga pagkunhod. Kung gigamit ang Kubernetes, nag-atubang kami sa panginahanglan nga ibalhin sa network ang datos nga nahilambigit sa buluhaton sa buluhaton. Kung sila igo nga kadako, nan ang oras sa pagpatuman sa buluhaton mahimo’g madugangan pag-ayo, ug usa ka igo nga kantidad sa espasyo sa disk ang gikinahanglan nga igahin sa mga higayon sa buluhaton sa Spark alang sa ilang temporaryo nga pagtipig. Kini nga disbentaha mahimong makunhuran pinaagi sa paggamit sa espesyal nga mga himan sa software nga naghatag lokalidad sa datos sa Kubernetes (pananglitan, Alluxio), apan kini sa tinuud nagpasabut nga kinahanglan nga tipigan ang usa ka kompleto nga kopya sa datos sa mga node sa cluster sa Kubernetes.
  2. Ang ikaduha nga mayor nga downside mao ang seguridad. Sa kasagaran, ang mga bahin nga may kalabotan sa seguridad bahin sa pagpadagan sa mga buluhaton sa Spark gi-disable, ang paggamit sa Kerberos wala nasakup sa opisyal nga dokumentasyon (bisan kung ang katugbang nga mga kapilian makita sa bersyon 3.0.0, nga magkinahanglan dugang nga trabaho), ug sa dokumentasyon sa seguridad kung kanus-a. gamit ang Spark (https://spark.apache.org/docs/2.4.5/security.html) lamang ang YARN, Mesos ug Standalone Cluster ang makita isip mga keystore. Sa parehas nga oras, ang tiggamit kung diin gilunsad ang mga buluhaton sa Spark dili direkta nga gitakda - gitakda ra namon ang account sa serbisyo kung diin kini molihok, ug gipili ang tiggamit base sa gi-configure nga mga palisiya sa seguridad. Bahin niini, bisan ang gamut nga tiggamit gigamit, nga dili luwas sa usa ka produktibo nga palibot, o usa ka tiggamit nga adunay usa ka random nga UID, nga dili kombenyente sa pag-apod-apod sa mga katungod sa pag-access sa datos (nadesisyonan pinaagi sa paghimo sa PodSecurityPolicies ug pag-link niini sa katugbang nga mga account sa serbisyo) . Sa pagkakaron, ang solusyon mao ang pagbutang sa tanang gikinahanglan nga mga file direkta ngadto sa Docker image, o pag-usab sa Spark startup script aron magamit ang mekanismo sa pagtipig ug pagkuha sa mga sekreto nga gidawat sa imong organisasyon.
  3. Ang pagpadagan sa mga buluhaton sa Spark kauban ang Kubernetes opisyal gihapon nga naa sa mode nga eksperimento ug mahimo’g adunay daghang mga pagbag-o sa gigamit nga artifact (mga file sa config, mga imahe sa base sa Docker, ug mga script sa pagsugod) sa umaabot. Ug sa pagkatinuod - sa dihang nag-andam sa materyal, ang mga bersyon 2.3.0 ug 2.4.5 gisulayan, ang kinaiya lahi kaayo.

Maghulat kita alang sa mga update - bag-o lang gipagawas ang usa ka bag-ong bersyon sa Spark (3.0.0), nga nagdala sa mahikap nga mga pagbag-o sa trabaho sa Spark sa Kubernetes, apan gipadayon ang eksperimento nga kahimtang sa suporta alang sa kini nga manager sa kapanguhaan. Tingali ang sunod nga mga pag-update mahimo gyud nga posible nga hingpit nga irekomenda nga biyaan ang YARN ug pagpadagan sa mga buluhaton sa Spark sa Kubernetes nga wala’y kahadlok sa seguridad sa imong sistema ug wala’y kinahanglan nga pagpino sa imong kaugalingon nga mga sangkap.

Katapusan

Source: www.habr.com

Idugang sa usa ka comment