Tmexxi Apache Spark fuq Kubernetes

Għeżież qarrejja, wara nofsinhar it-tajjeb. Illum ser nitkellmu ftit dwar Apache Spark u l-prospetti ta 'żvilupp tiegħu.

Tmexxi Apache Spark fuq Kubernetes

Fid-dinja moderna tal-Big Data, Apache Spark huwa l-istandard de facto għall-iżvilupp tal-kompiti tal-ipproċessar tad-dejta tal-lott. Barra minn hekk, jintuża wkoll biex jinħolqu applikazzjonijiet ta 'streaming li jaħdmu fil-kunċett ta' mikro lott, ipproċessar u dejta tat-tbaħħir f'porzjonijiet żgħar (Spark Structured Streaming). U tradizzjonalment kien parti mill-munzell ġenerali Hadoop, bl-użu tal-ĦJUT (jew f'xi każijiet Apache Mesos) bħala l-maniġer tar-riżorsi. Sal-2020, l-użu tiegħu fil-forma tradizzjonali tiegħu huwa inkwistjoni għall-biċċa l-kbira tal-kumpaniji minħabba n-nuqqas ta 'distribuzzjonijiet deċenti ta' Hadoop - l-iżvilupp ta 'HDP u CDH waqaf, CDH mhux żviluppat sew u għandu spiża għolja, u l-bqija tal-fornituri Hadoop għandhom jew ma baqgħux jeżistu jew għandhom futur imċajpar. Għalhekk, it-tnedija ta 'Apache Spark bl-użu ta' Kubernetes hija ta 'interess dejjem akbar fost il-komunità u kumpaniji kbar - issir standard fl-orkestrazzjoni tal-kontejners u l-ġestjoni tar-riżorsi fi sħab privati ​​u pubbliċi, issolvi l-problema bl-iskedar tar-riżorsi inkonvenjenti tal-kompiti Spark fuq YARN u jipprovdi pjattaforma li qed tiżviluppa b'mod kostanti b'ħafna distribuzzjonijiet kummerċjali u miftuħa għal kumpaniji ta 'kull daqs u strixxi. Barra minn hekk, fid-dawl tal-popolarità, il-biċċa l-kbira diġà rnexxielhom jakkwistaw koppja ta 'installazzjonijiet tagħhom stess u żiedu l-għarfien espert tagħhom fl-użu tiegħu, li jissimplifika l-moviment.

Nibda bil-verżjoni 2.3.0, Apache Spark kiseb appoġġ uffiċjali għat-tmexxija tal-kompiti fi cluster Kubernetes u llum, se nitkellmu dwar il-maturità attwali ta 'dan l-approċċ, diversi għażliet għall-użu tiegħu u żvantaġġi li se jiltaqgħu magħhom waqt l-implimentazzjoni.

L-ewwelnett, ejja nħarsu lejn il-proċess ta 'żvilupp ta' kompiti u applikazzjonijiet ibbażati fuq Apache Spark u jenfasizzaw każijiet tipiċi li fihom għandek bżonn tmexxi kompitu fuq cluster Kubernetes. Fit-tħejjija ta 'din il-kariga, OpenShift jintuża bħala distribuzzjoni u se jingħataw kmandi rilevanti għall-utilità tal-linja tal-kmand tiegħu (oc). Għal distribuzzjonijiet Kubernetes oħra, jistgħu jintużaw il-kmandi korrispondenti mill-utilità standard tal-linja tal-kmand Kubernetes (kubectl) jew l-analogi tagħhom (per eżempju, għall-politika oc adm).

L-ewwel użu każ - spark-submit

Matul l-iżvilupp tal-kompiti u l-applikazzjonijiet, l-iżviluppatur jeħtieġ li jmexxi l-kompiti biex jiddebuggja t-trasformazzjoni tad-dejta. Teoretikament, stubs jistgħu jintużaw għal dawn l-għanijiet, iżda l-iżvilupp bil-parteċipazzjoni ta 'istanzi reali (għalkemm tat-test) ta' sistemi finali wera li huwa aktar mgħaġġel u aħjar f'din il-klassi ta 'kompiti. Fil-każ meta niddibaggjaw fuq każijiet reali ta 'sistemi finali, żewġ xenarji huma possibbli:

  • l-iżviluppatur imexxi kompitu Spark lokalment fil-modalità waħedha;

    Tmexxi Apache Spark fuq Kubernetes

  • żviluppatur imexxi kompitu Spark fuq cluster Kubernetes f'linja tat-test.

    Tmexxi Apache Spark fuq Kubernetes

L-ewwel għażla għandha dritt li teżisti, iżda tinvolvi għadd ta' żvantaġġi:

  • Kull żviluppatur għandu jiġi pprovdut b'aċċess mill-post tax-xogħol għall-istanzi kollha tas-sistemi finali li għandu bżonn;
  • ammont suffiċjenti ta 'riżorsi huwa meħtieġ fuq il-magna tax-xogħol biex tmexxi l-kompitu li qed jiġi żviluppat.

It-tieni għażla m'għandhiex dawn l-iżvantaġġi, peress li l-użu ta 'cluster Kubernetes jippermettilek talloka l-ġabra ta' riżorsi meħtieġa għat-tmexxija tal-kompiti u tipprovdiha bl-aċċess meħtieġ għall-istanzi tas-sistema finali, billi tipprovdi aċċess għaliha b'mod flessibbli bl-użu tal-mudell Kubernetes għal il-membri kollha tat-tim tal-iżvilupp. Ejja nenfasizzawh bħala l-ewwel każ ta 'użu - tnedija ta' kompiti Spark minn magna ta 'żviluppatur lokali fuq cluster Kubernetes f'ċirkwit tat-test.

Ejja nitkellmu aktar dwar il-proċess tat-twaqqif ta' Spark biex jaħdem lokalment. Biex tibda tuża Spark trid tinstallah:

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

Aħna niġbru l-pakketti meħtieġa biex naħdmu ma' Kubernetes:

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

Bini sħiħ jieħu ħafna ħin, u biex toħloq immaġini Docker u tmexxihom fuq cluster Kubernetes, verament għandek bżonn biss fajls tal-vażetti mid-direttorju "assemblaġġ/", sabiex tkun tista' tibni dan is-sottoproġett biss:

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

Biex tmexxi l-impjiegi Spark fuq Kubernetes, trid toħloq immaġni Docker biex tużaha bħala immaġni bażi. Hemm 2 approċċi possibbli hawnhekk:

  • L-immaġni Docker iġġenerata tinkludi l-kodiċi tal-kompitu Spark eżekutibbli;
  • L-immaġni maħluqa tinkludi biss Spark u d-dipendenzi meħtieġa, il-kodiċi eżekutibbli huwa ospitat mill-bogħod (per eżempju, f'HDFS).

L-ewwel, ejja nibnu immaġni Docker li jkun fiha eżempju tat-test ta 'kompitu Spark. Biex toħloq immaġini Docker, Spark għandha utilità msejħa "docker-image-tool". Ejja nistudjaw l-għajnuna fuqha:

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

Bl-għajnuna tagħha, tista 'toħloq immaġini Docker u ttella' f'reġistri remoti, iżda awtomatikament għandha numru ta' żvantaġġi:

  • mingħajr nuqqas joħloq 3 immaġini Docker f'daqqa - għal Spark, PySpark u R;
  • ma jippermettix li tispeċifika isem ta' immaġini.

Għalhekk, se nużaw verżjoni modifikata ta 'din l-utilità mogħtija hawn taħt:

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

Bl-għajnuna tagħha, aħna niġbru immaġini Spark bażika li fiha kompitu tat-test għall-kalkolu ta' Pi bl-użu ta' Spark (hawnhekk {docker-registry-url} huwa l-URL tar-reġistru tal-immaġni Docker tiegħek, {repo} huwa l-isem tar-repożitorju ġewwa r-reġistru, li jaqbel mal-proġett f'OpenShift , {image-name} - isem tal-immaġini (jekk tintuża separazzjoni ta' immaġini fi tliet livelli, pereżempju, bħal fir-reġistru integrat tal-immaġini Red Hat OpenShift), {tag} - tikketta ta' dan verżjoni tal-immaġni):

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

Idħol fil-cluster OKD billi tuża l-utilità tal-console (hawnhekk {OKD-API-URL} hija l-URL tal-API tal-cluster OKD):

oc login {OKD-API-URL}

Ejja nġibu t-token tal-utent attwali għall-awtorizzazzjoni fir-Reġistru Docker:

oc whoami -t

Idħol fir-Reġistru Docker intern tal-cluster OKD (nużaw it-token miksub billi tuża l-kmand preċedenti bħala l-password):

docker login {docker-registry-url}

Ejja ntellgħu l-immaġni Docker immuntata fir-Reġistru Docker OKD:

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

Ejja niċċekkjaw li l-immaġni immuntata hija disponibbli f'OKD. Biex tagħmel dan, iftaħ il-URL fil-browser b'lista ta 'immaġini tal-proġett korrispondenti (hawn {proġett} huwa l-isem tal-proġett ġewwa l-cluster OpenShift, {OKD-WEBUI-URL} huwa l-URL tal-console Web OpenShift ) - https://{OKD-WEBUI-URL}/console /project/{project}/browse/images/{image-name}.

Biex tmexxi l-kompiti, għandu jinħoloq kont tas-servizz bil-privileġġi biex imexxu l-imżiewed bħala root (se niddiskutu dan il-punt aktar tard):

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

Ejja nħaddmu l-kmand tal-ispark-submit biex tippubblika kompitu Spark lill-cluster OKD, billi tispeċifika l-kont tas-servizz maħluq u l-immaġni 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

Hawnhekk:

—isem — l-isem tal-kompitu li se jipparteċipa fil-formazzjoni tal-isem tal-imżiewed Kubernetes;

—class — klassi tal-fajl eżekutibbli, imsejjaħ meta jibda l-kompitu;

—conf — Parametri tal-konfigurazzjoni tal-ispark;

spark.executor.instances — in-numru ta' eżekuturi ta' Spark li għandhom jitniedu;

spark.kubernetes.authenticate.driver.serviceAccountName - l-isem tal-kont tas-servizz Kubernetes użat meta tniedi pods (biex jiddefinixxi l-kuntest tas-sigurtà u l-kapaċitajiet meta jinteraġixxu mal-API Kubernetes);

spark.kubernetes.namespace — Spazju tal-isem Kubernetes li fih se jiġu varati l-pods tas-sewwieq u l-eżekutur;

spark.submit.deployMode — metodu ta' tnedija ta' Spark (għall-"cluster" standard ta' spark-submit jintuża, għal Spark Operator u verżjonijiet aktar tard ta' Spark "klijent");

spark.kubernetes.container.image - Immaġini Docker użata għat-tnedija tal-miżwed;

spark.master — Kubernetes API URL (esterna hija speċifikata sabiex l-aċċess iseħħ mill-magna lokali);

local:// hija t-triq għall-eżekutibbli Spark ġewwa l-immaġni Docker.

Immorru għall-proġett OKD korrispondenti u nistudjaw il-miżwed maħluqa - https://{OKD-WEBUI-URL}/console/project/{project}/browse/pods.

Biex tissimplifika l-proċess ta 'żvilupp, tista' tintuża għażla oħra, li fiha tinħoloq immaġni bażi komuni ta 'Spark, użata mill-kompiti kollha biex imexxu, u snapshots ta' fajls eżekutibbli huma ppubblikati għal ħażna esterna (per eżempju, Hadoop) u speċifikati meta ssejjaħ. spark-submit bħala link. F'dan il-każ, tista 'tmexxi verżjonijiet differenti tal-kompiti Spark mingħajr ma terġa' tibni immaġini Docker, billi tuża, pereżempju, WebHDFS biex tippubblika immaġini. Nibagħtu talba biex noħolqu fajl (hawn {host} huwa l-host tas-servizz WebHDFS, {port} huwa l-port tas-servizz WebHDFS, {path-to-file-on-hdfs} huwa l-mogħdija mixtieqa għall-fajl fuq HDFS):

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

Inti ser tirċievi tweġiba bħal din (hawn {location} huwa l-URL li jeħtieġ li jintuża biex tniżżel il-fajl):

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

Tgħabbi l-fajl eżekutibbli Spark f'HDFS (hawnhekk {path-to-local-file} hija l-mogħdija għall-fajl eżekutibbli Spark fuq l-ospitant attwali):

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

Wara dan, nistgħu nagħmlu spark-submit billi tuża l-fajl Spark imtella fuq HDFS (hawn {class-name} huwa l-isem tal-klassi li jeħtieġ li tiġi mnedija biex jitlesta l-kompitu):

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

Għandu jiġi nnutat li sabiex taċċessa l-HDFS u tiżgura li l-kompitu jaħdem, jista’ jkollok bżonn tibdel id-Dockerfile u l-iskrittura entrypoint.sh - żid direttiva mad-Dockerfile biex tikkopja libreriji dipendenti fid-direttorju /opt/spark/jars u inkludi l-fajl tal-konfigurazzjoni HDFS fi SPARK_CLASSPATH fil-punt tad-dħul.

It-tieni każ ta' użu - Apache Livy

Barra minn hekk, meta kompitu jiġi żviluppat u r-riżultat jeħtieġ li jiġi ttestjat, tqum il-kwistjoni tat-tnedija tiegħu bħala parti mill-proċess CI/CD u t-traċċar tal-istatus tal-eżekuzzjoni tiegħu. Naturalment, tista 'tmexxiha billi tuża sejħa ta' sottomissjoni ta 'spark lokali, iżda dan jikkomplika l-infrastruttura CI/CD peress li teħtieġ l-installazzjoni u l-konfigurazzjoni ta' Spark fuq l-aġenti/runners tas-server CI u t-twaqqif tal-aċċess għall-API Kubernetes. Għal dan il-każ, l-implimentazzjoni fil-mira għażlet li tuża Apache Livy bħala API REST għat-tmexxija tal-kompiti Spark ospitati ġewwa cluster Kubernetes. Bl-għajnuna tagħha, tista 'tmexxi kompiti Spark fuq cluster Kubernetes billi tuża talbiet regolari ta' cURL, li hija implimentata faċilment ibbażata fuq kwalunkwe soluzzjoni CI, u t-tqegħid tagħha ġewwa l-cluster Kubernetes issolvi l-kwistjoni tal-awtentikazzjoni meta jinteraġixxi mal-API Kubernetes.

Tmexxi Apache Spark fuq Kubernetes

Ejja nenfasizzawh bħala t-tieni każ ta' użu - it-tmexxija tal-kompiti Spark bħala parti minn proċess CI/CD fuq cluster Kubernetes f'linja tat-test.

Ftit dwar Apache Livy - jaħdem bħala server HTTP li jipprovdi interface tal-Web u API RESTful li jippermettilek li tniedi spark-submit mill-bogħod billi tgħaddi l-parametri meħtieġa. Tradizzjonalment ġiet mibgħuta bħala parti minn distribuzzjoni HDP, iżda tista 'wkoll tiġi skjerata għal OKD jew kwalunkwe installazzjoni Kubernetes oħra billi tuża l-manifest xieraq u sett ta' stampi Docker, bħal din - github.com/ttauveron/k8s-big-data-experiments/tree/master/livy-spark-2.3. Għall-każ tagħna, inbniet immaġni Docker simili, inkluża l-verżjoni Spark 2.4.5 mid-Dockerfile li ġej:

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

L-immaġni ġġenerata tista 'tinbena u tittella' fir-repożitorju Docker eżistenti tiegħek, bħar-repożitorju intern OKD. Biex tużah, uża l-manifest li ġej ({registry-url} - URL tar-reġistru tal-immaġni Docker, {image-name} - Isem tal-immaġni Docker, {tag} - Tag tal-immaġni Docker, {livy-url} - URL mixtieq fejn il- server se jkun aċċessibbli Livy; il-manifest "Rotta" jintuża jekk jintuża Red Hat OpenShift bħala d-distribuzzjoni Kubernetes, inkella jintuża l-manifest Ingress jew Servizz korrispondenti tat-tip 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

Wara li tapplikaha u tniedi b'suċċess il-pod, l-interface grafika Livy hija disponibbli fil-link: http://{livy-url}/ui. Ma 'Livy, nistgħu nippubblikaw il-kompitu Spark tagħna billi tuża talba REST minn, pereżempju, Postman. Eżempju ta' ġabra b'talbiet huwa ppreżentat hawn taħt (argumenti ta' konfigurazzjoni b'varjabbli meħtieġa għat-tħaddim tal-kompitu mniedi jistgħu jiġu mgħoddija fil-firxa "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": {}
}

Ejja tesegwixxi l-ewwel talba mill-ġbir, mur l-interface OKD u ċċekkja li l-kompitu ġie mniedi b'suċċess - https://{OKD-WEBUI-URL}/console/project/{project}/browse/pods. Fl-istess ħin, se tidher sessjoni fl-interface Livy (http://{livy-url}/ui), li fiha, billi tuża l-API Livy jew interface grafiku, tista 'ssegwi l-progress tal-kompitu u tistudja s-sessjoni zkuk.

Issa ejja nuru kif jaħdem Livy. Biex tagħmel dan, ejja neżaminaw ir-zkuk tal-kontenitur Livy ġewwa l-pod bis-server Livy - https://{OKD-WEBUI-URL}/console/project/{project}/browse/pods/{livy-pod-name }?tab=zkuk. Minnhom nistgħu naraw li meta nsejħu l-API Livy REST f'kontenitur bl-isem "livy", titwettaq spark-submit, simili għal dak li użajna hawn fuq (hawn {livy-pod-name} huwa l-isem tal-pod maħluq mas-server Livy). Il-ġabra tintroduċi wkoll it-tieni mistoqsija li tippermettilek tmexxi kompiti li jospitaw mill-bogħod eżekutibbli Spark bl-użu ta 'server Livy.

It-tielet każ ta' użu - Spark Operator

Issa li l-kompitu ġie ttestjat, tqum il-kwistjoni li titħaddem regolarment. Il-mod indiġenu biex tmexxi regolarment il-kompiti fi cluster Kubernetes hija l-entità CronJob u tista 'tużaha, iżda bħalissa l-użu ta' operaturi biex jimmaniġġjaw applikazzjonijiet f'Kubernetes huwa popolari ħafna u għal Spark hemm operatur pjuttost matur, li huwa wkoll użati f'soluzzjonijiet fil-livell ta 'Intrapriża (per eżempju, Lightbend FastData Platform). Nirrakkomandaw li tużah - il-verżjoni stabbli attwali ta 'Spark (2.4.5) għandha għażliet ta' konfigurazzjoni pjuttost limitati għat-tmexxija tal-kompiti ta 'Spark f'Kubernetes, filwaqt li l-verżjoni ewlenija li jmiss (3.0.0) tiddikjara appoġġ sħiħ għal Kubernetes, iżda d-data tar-rilaxx tagħha għadha mhux magħrufa . Spark Operator jikkumpensa għal dan in-nuqqas billi jżid għażliet ta 'konfigurazzjoni importanti (per eżempju, l-immuntar ta' ConfigMap b'konfigurazzjoni ta 'aċċess Hadoop fuq Spark pods) u l-abbiltà li tmexxi kompitu skedat regolarment.

Tmexxi Apache Spark fuq Kubernetes
Ejja nenfasizzawh bħala t-tielet każ ta' użu - tħaddim regolari tal-kompiti Spark fuq cluster Kubernetes f'linja ta' produzzjoni.

Spark Operator huwa sors miftuħ u żviluppat fi ħdan il-Google Cloud Platform - github.com/GoogleCloudPlatform/spark-on-k8s-operator. L-installazzjoni tagħha tista 'ssir fi 3 modi:

  1. Bħala parti mill-installazzjoni Lightbend FastData Platform/Cloudflow;
  2. L-użu ta' Helm:
    helm repo add incubator http://storage.googleapis.com/kubernetes-charts-incubator
    helm install incubator/sparkoperator --namespace spark-operator
    	

  3. Bl-użu ta' manifesti mir-repożitorju uffiċjali (https://github.com/GoogleCloudPlatform/spark-on-k8s-operator/tree/master/manifest). Ta 'min jinnota dan li ġej - Cloudflow jinkludi operatur b'verżjoni API v1beta1. Jekk jintuża dan it-tip ta 'installazzjoni, id-deskrizzjonijiet tal-manifest tal-applikazzjoni Spark għandhom ikunu bbażati fuq tikketti ta' eżempju f'Git bil-verżjoni tal-API xierqa, pereżempju, "v1beta1-0.9.0-2.4.0". Il-verżjoni tal-operatur tista' tinstab fid-deskrizzjoni tas-CRD inkluża fl-operatur fid-dizzjunarju "verżjonijiet":
    oc get crd sparkapplications.sparkoperator.k8s.io -o yaml
    	

Jekk l-operatur ikun installat b'mod korrett, pod attiv mal-operatur Spark se jidher fil-proġett korrispondenti (per eżempju, cloudflow-fdp-sparkoperator fl-ispazju Cloudflow għall-installazzjoni Cloudflow) u tip ta 'riżorsi Kubernetes korrispondenti bl-isem "sparkapplications" se jidher. . Tista' tesplora l-applikazzjonijiet Spark disponibbli bil-kmand li ġej:

oc get sparkapplications -n {project}

Biex tmexxi l-kompiti billi tuża Spark Operator trid tagħmel 3 affarijiet:

  • toħloq immaġni Docker li tinkludi l-libreriji kollha meħtieġa, kif ukoll il-konfigurazzjoni u l-fajls eżekutibbli. Fl-istampa fil-mira, din hija immaġni maħluqa fl-istadju CI/CD u ttestjata fuq cluster tat-test;
  • tippubblika immaġni Docker għal reġistru aċċessibbli mill-cluster Kubernetes;
  • iġġenera manifest bit-tip "SparkApplication" u deskrizzjoni tal-kompitu li għandu jitnieda. Manifesti ta’ eżempju huma disponibbli fir-repożitorju uffiċjali (eż. github.com/GoogleCloudPlatform/spark-on-k8s-operator/blob/v1beta1-0.9.0-2.4.0/examples/spark-pi.yaml). Hemm punti importanti li wieħed jinnota dwar il-manifest:
    1. id-dizzjunarju “apiVersion” għandu jindika l-verżjoni tal-API li tikkorrispondi għall-verżjoni tal-operatur;
    2. id-dizzjunarju “metadata.namespace” għandu jindika l-ispazju tal-isem li fih se titnieda l-applikazzjoni;
    3. id-dizzjunarju “spec.image” għandu jkun fih l-indirizz tal-immaġni Docker maħluqa f’reġistru aċċessibbli;
    4. id-dizzjunarju "spec.mainClass" għandu jkun fih il-klassi tal-ħidma Spark li trid titħaddem meta jibda l-proċess;
    5. id-dizzjunarju "spec.mainApplicationFile" għandu jkun fih it-triq għall-fajl vażett eżekutibbli;
    6. id-dizzjunarju “spec.sparkVersion” għandu jindika l-verżjoni ta’ Spark li qed tintuża;
    7. id-dizzjunarju “spec.driver.serviceAccount” għandu jispeċifika l-kont tas-servizz fi ħdan l-ispazju tal-isem Kubernetes korrispondenti li se jintuża biex titħaddem l-applikazzjoni;
    8. id-dizzjunarju “spec.executor” għandu jindika n-numru ta’ riżorsi allokati għall-applikazzjoni;
    9. id-dizzjunarju "spec.volumeMounts" għandu jispeċifika d-direttorju lokali li fih se jinħolqu l-fajls lokali tal-ħidma Spark.

Eżempju tal-ġenerazzjoni ta' manifest (hawnhekk {spark-service-account} huwa kont tas-servizz ġewwa l-cluster Kubernetes għat-tmexxija tal-kompiti 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"

Dan il-manifest jispeċifika kont tas-servizz li għalih, qabel ma tippubblika l-manifest, trid toħloq l-irbit tar-rwoli meħtieġa li jipprovdu d-drittijiet ta’ aċċess meħtieġa għall-applikazzjoni Spark biex jinteraġixxu mal-API Kubernetes (jekk meħtieġ). Fil-każ tagħna, l-applikazzjoni teħtieġ drittijiet biex toħloq Pods. Ejja noħolqu r-rwol meħtieġ vinkolanti:

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

Ta 'min jinnota wkoll li din l-ispeċifikazzjoni manifest tista' tinkludi parametru "hadoopConfigMap", li jippermettilek tispeċifika ConfigMap bil-konfigurazzjoni Hadoop mingħajr ma jkollok l-ewwel tpoġġi l-fajl korrispondenti fl-immaġni Docker. Huwa adattat ukoll għat-tmexxija tal-kompiti regolarment - bl-użu tal-parametru "skeda", tista 'tiġi speċifikata skeda għat-tmexxija ta' kompitu partikolari.

Wara dan, insalvaw il-manifest tagħna fil-fajl spark-pi.yaml u napplikawh għall-cluster Kubernetes tagħna:

oc apply -f spark-pi.yaml

Dan se joħloq oġġett tat-tip "sparkapplications":

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

F'dan il-każ, se jinħoloq pod b'applikazzjoni, li l-istatus tiegħu jintwera fl-"sparkapplications" maħluqa. Tista' tarah bil-kmand li ġej:

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

Mat-tlestija tal-kompitu, il-POD se jimxi għall-istatus "Imlesta", li se jaġġorna wkoll fi "sparkapplications". Ir-reġistri tal-applikazzjonijiet jistgħu jidhru fil-browser jew billi tuża l-kmand li ġej (hawn {sparkapplications-pod-name} huwa l-isem tal-pod tal-kompitu li qed jaħdem):

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

Il-kompiti tal-ispark jistgħu wkoll jiġu ġestiti bl-użu tal-utilità speċjalizzata sparkctl. Biex tinstallah, ikklonja r-repożitorju bil-kodiċi tas-sors tiegħu, installa Go u ibni din l-utilità:

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

Ejja neżaminaw il-lista tal-ħidma ta' Spark:

sparkctl list -n {project}

Ejja noħolqu deskrizzjoni għall-kompitu 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"

Ejja nħaddmu l-kompitu deskritt billi tuża sparkctl:

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

Ejja neżaminaw il-lista tal-ħidma ta' Spark:

sparkctl list -n {project}

Ejja neżaminaw il-lista ta 'avvenimenti ta' kompitu Spark imniedi:

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

Ejja neżaminaw l-istatus tal-kompitu Spark li qed jaħdem:

sparkctl status spark-pi -n {project}

Bħala konklużjoni, nixtieq nikkunsidra l-iżvantaġġi skoperti li tuża l-verżjoni stabbli attwali ta 'Spark (2.4.5) f'Kubernetes:

  1. L-ewwel u, forsi, żvantaġġ ewlieni huwa n-nuqqas ta 'Data Lokalità. Minkejja n-nuqqasijiet kollha tal-ĦJUT, kien hemm ukoll vantaġġi għall-użu tiegħu, pereżempju, il-prinċipju ta 'twassil ta' kodiċi għal data (aktar milli data għal kodiċi). Grazzi għaliha, il-kompiti Spark ġew eżegwiti fuq in-nodi fejn kienet tinsab id-dejta involuta fil-kalkoli, u ż-żmien li ħadet biex titwassal id-dejta fuq in-netwerk tnaqqas b'mod sinifikanti. Meta nużaw Kubernetes, inħabbtu wiċċna mal-ħtieġa li nċaqalqu d-dejta involuta f'ħidma madwar in-netwerk. Jekk ikunu kbar biżżejjed, il-ħin tal-eżekuzzjoni tal-kompitu jista 'jiżdied b'mod sinifikanti, u jeħtieġ ukoll ammont pjuttost kbir ta' spazju fuq disk allokat għall-istanzi tal-kompitu Spark għall-ħażna temporanja tagħhom. Dan l-iżvantaġġ jista 'jiġi mtaffi bl-użu ta' softwer speċjalizzat li jiżgura l-lokalità tad-dejta f'Kubernetes (pereżempju, Alluxio), iżda dan fil-fatt ifisser il-ħtieġa li tinħażen kopja sħiħa tad-dejta fuq in-nodi tal-cluster Kubernetes.
  2. It-tieni żvantaġġ importanti huwa s-sigurtà. B'mod awtomatiku, il-karatteristiċi relatati mas-sigurtà rigward it-tħaddim tal-kompiti ta' Spark huma diżattivati, l-użu ta' Kerberos mhuwiex kopert fid-dokumentazzjoni uffiċjali (għalkemm l-għażliet korrispondenti ġew introdotti fil-verżjoni 3.0.0, li se teħtieġ xogħol addizzjonali), u d-dokumentazzjoni tas-sigurtà għal bl-użu ta 'Spark (https ://spark.apache.org/docs/2.4.5/security.html) biss YARN, Mesos u Standalone Cluster jidhru bħala ħwienet ewlenin. Fl-istess ħin, l-utent li taħtu jiġu mnedija l-kompiti Spark ma jistax jiġi speċifikat direttament - aħna nispeċifikaw biss il-kont tas-servizz li taħtu se jaħdem, u l-utent jintgħażel abbażi tal-politiki ta 'sigurtà kkonfigurati. F'dan ir-rigward, jew jintuża l-utent għerq, li mhuwiex sikur f'ambjent produttiv, jew utent b'UID każwali, li huwa inkonvenjenti meta jqassmu d-drittijiet ta 'aċċess għad-dejta (dan jista' jiġi solvut billi jinħolqu PodSecurityPolicies u jorbothom mal- kontijiet tas-servizz korrispondenti). Bħalissa, is-soluzzjoni hija li jew tpoġġi l-fajls kollha meħtieġa direttament fl-immaġni Docker, jew timmodifika l-iskrittura tat-tnedija ta 'Spark biex tuża l-mekkaniżmu għall-ħażna u l-irkupru ta' sigrieti adottati fl-organizzazzjoni tiegħek.
  3. It-tħaddim ta 'impjiegi Spark bl-użu ta' Kubernetes għadu uffiċjalment fil-modalità sperimentali u jista 'jkun hemm bidliet sinifikanti fl-artifacts użati (fajls ta' konfigurazzjoni, immaġini bażi Docker, u skripts ta 'tnedija) fil-futur. U tabilħaqq, meta tħejji l-materjal, il-verżjonijiet 2.3.0 u 2.4.5 ġew ittestjati, l-imġieba kienet differenti b'mod sinifikanti.

Ejja nistennew aġġornamenti - reċentement ġiet rilaxxata verżjoni ġdida ta 'Spark (3.0.0), li ġabet bidliet sinifikanti fix-xogħol ta' Spark fuq Kubernetes, iżda żammet l-istatus sperimentali ta 'appoġġ għal dan il-maniġer tar-riżorsi. Forsi l-aġġornamenti li jmiss se jagħmluha verament possibbli li tiġi rrakkomandata bis-sħiħ l-abbandun tal-YARN u t-tħaddim tal-kompiti Spark fuq Kubernetes mingħajr biża għas-sigurtà tas-sistema tiegħek u mingħajr il-ħtieġa li timmodifika b'mod indipendenti l-komponenti funzjonali.

Tmiem.

Sors: www.habr.com

Żid kumment