Running Apache Spark-ը Kubernetes-ում

Հարգելի ընթերցողներ, բարի կեսօր: Այսօր մենք մի փոքր կխոսենք Apache Spark-ի և դրա զարգացման հեռանկարների մասին:

Running Apache Spark-ը Kubernetes-ում

Big Data-ի ժամանակակից աշխարհում Apache Spark-ը դե ֆակտո ստանդարտ է տվյալների խմբաքանակի մշակման առաջադրանքների մշակման համար: Բացի այդ, այն նաև օգտագործվում է հոսքային հավելվածներ ստեղծելու համար, որոնք աշխատում են միկրո խմբաքանակի հայեցակարգում, մշակում և առաքում են տվյալները փոքր մասերում (Spark Structured Streaming): Եվ ավանդաբար այն եղել է Hadoop-ի ընդհանուր փաթեթի մի մասը՝ օգտագործելով YARN-ը (կամ որոշ դեպքերում Apache Mesos-ը) որպես ռեսուրսների կառավարիչ: Մինչև 2020 թվականը, դրա ավանդական ձևով օգտագործումը հարցականի տակ է ընկերությունների մեծ մասի համար՝ Hadoop-ի պատշաճ բաշխումների բացակայության պատճառով. HDP-ի և CDH-ի զարգացումը կանգ է առել, CDH-ն լավ զարգացած չէ և ունի բարձր արժեք, իսկ մնացած Hadoop մատակարարները կա՛մ դադարել է գոյություն ունենալ, կա՛մ մշուշոտ ապագա է ունեցել: Հետևաբար, Kubernetes-ի միջոցով Apache Spark-ի գործարկումը մեծ հետաքրքրություն է առաջացնում համայնքի և խոշոր ընկերությունների շրջանում. դառնալով ստանդարտ կոնտեյներների կազմակերպման և ռեսուրսների կառավարման մեջ մասնավոր և հանրային ամպերում, այն լուծում է YARN-ում Spark-ի առաջադրանքների ռեսուրսների անհարմար պլանավորման խնդիրը և ապահովում: կայուն զարգացող հարթակ՝ բազմաթիվ առևտրային և բաց բաշխումներով բոլոր չափերի և շերտերի ընկերությունների համար: Բացի այդ, հանրաճանաչության հետևանքով մեծամասնությունն արդեն հասցրել է ձեռք բերել մի քանի սեփական ինստալացիա և մեծացրել է դրանց օգտագործման փորձը, ինչը հեշտացնում է այդ քայլը:

Սկսած 2.3.0 տարբերակից, Apache Spark-ը պաշտոնական աջակցություն ստացավ Kubernetes կլաստերում առաջադրանքների կատարման համար, և այսօր մենք կխոսենք այս մոտեցման ներկայիս հասունության, դրա օգտագործման տարբեր տարբերակների և թակարդների մասին, որոնք կհանդիպեն իրականացման ընթացքում:

Նախ, եկեք նայենք Apache Spark-ի վրա հիմնված առաջադրանքների և հավելվածների մշակման գործընթացին և առանձնացնենք բնորոշ դեպքերը, երբ դուք պետք է առաջադրանք կատարեք Kubernetes կլաստերի վրա: Այս գրառումը պատրաստելիս OpenShift-ն օգտագործվում է որպես բաշխում և տրվելու են հրամանների տողի (oc) ծրագրին համապատասխան հրամաններ: Kubernetes-ի այլ բաշխումների համար կարող են օգտագործվել ստանդարտ Kubernetes հրամանի տողերի համապատասխան հրամանները (kubectl) կամ դրանց անալոգները (օրինակ՝ oc adm քաղաքականության համար):

Առաջին օգտագործման դեպք - կայծ-ներկայացնել

Առաջադրանքների և հավելվածների մշակման ընթացքում մշակողը պետք է առաջադրանքներ գործարկի տվյալների փոխակերպումը վրիպազերծելու համար: Տեսականորեն, կոճղերը կարող են օգտագործվել այս նպատակների համար, սակայն վերջնական համակարգերի իրական (թեև թեստային) օրինակների մասնակցությամբ մշակումն ապացուցվել է, որ ավելի արագ և ավելի լավ է այս դասի առաջադրանքներում: Այն դեպքում, երբ մենք վրիպազերծում ենք վերջնական համակարգերի իրական օրինակների վրա, հնարավոր է երկու սցենար.

  • մշակողը կատարում է Spark առաջադրանքը տեղում՝ ինքնուրույն ռեժիմով.

    Running Apache Spark-ը Kubernetes-ում

  • մշակողը կատարում է Spark առաջադրանքը Kubernetes կլաստերի վրա՝ թեստային օղակում:

    Running Apache Spark-ը Kubernetes-ում

Առաջին տարբերակը գոյության իրավունք ունի, բայց ենթադրում է մի շարք թերություններ.

  • Յուրաքանչյուր ծրագրավորող պետք է ապահովվի աշխատավայրից իրեն անհրաժեշտ վերջնական համակարգերի բոլոր ատյաններում մուտքի հնարավորություն.
  • մշակվող առաջադրանքը գործարկելու համար աշխատանքային մեքենայի վրա պահանջվում է բավարար քանակությամբ ռեսուրսներ:

Երկրորդ տարբերակը չունի այս թերությունները, քանի որ Kubernetes կլաստերի օգտագործումը թույլ է տալիս Ձեզ հատկացնել անհրաժեշտ ռեսուրսների լողավազան առաջադրանքների կատարման համար և ապահովել նրան անհրաժեշտ մուտք դեպի վերջնական համակարգի օրինակներ՝ ճկուն կերպով ապահովելով դրան մուտք՝ օգտագործելով Kubernetes դերային մոդելը: զարգացման թիմի բոլոր անդամները: Եկեք ընդգծենք այն որպես առաջին օգտագործման դեպք՝ գործարկել Spark-ի առաջադրանքները տեղական ծրագրավորող մեքենայից Kubernetes կլաստերի վրա փորձարկման օղակում:

Եկեք ավելին խոսենք Spark-ի տեղադրման գործընթացի մասին՝ տեղական գործարկելու համար: Spark-ն օգտագործելու համար անհրաժեշտ է տեղադրել այն.

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

Մենք հավաքում ենք անհրաժեշտ փաթեթները Kubernetes-ի հետ աշխատելու համար.

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

Ամբողջական կառուցումը շատ ժամանակ է պահանջում, և Docker պատկերներ ստեղծելու և դրանք Kubernetes կլաստերի վրա գործարկելու համար ձեզ իսկապես անհրաժեշտ են միայն jar ֆայլեր «assembly/» գրացուցակից, այնպես որ կարող եք կառուցել միայն այս ենթածրագիրը.

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

Spark-ի աշխատատեղերը Kubernetes-ում գործարկելու համար դուք պետք է ստեղծեք Docker պատկեր՝ որպես հիմնական պատկեր օգտագործելու համար: Այստեղ 2 հնարավոր մոտեցում կա.

  • Ստեղծված Docker պատկերը ներառում է գործարկվող Spark առաջադրանքի կոդը;
  • Ստեղծված պատկերը ներառում է միայն Spark-ը և անհրաժեշտ կախվածությունները, գործարկվող կոդը գտնվում է հեռակա կարգով (օրինակ՝ HDFS-ում):

Նախ, եկեք կառուցենք Docker պատկեր, որը պարունակում է Spark առաջադրանքի փորձնական օրինակ: Docker պատկերներ ստեղծելու համար Spark-ն ունի «docker-image-tool» կոչվող օգտակար ծրագիր: Եկեք ուսումնասիրենք դրա վերաբերյալ օգնությունը.

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

Դրա օգնությամբ դուք կարող եք ստեղծել Docker պատկերներ և դրանք վերբեռնել հեռավոր ռեգիստրներում, բայց լռելյայն այն ունի մի շարք թերություններ.

  • առանց ձախողման ստեղծում է միանգամից 3 Docker պատկեր՝ Spark-ի, PySpark-ի և R-ի համար;
  • թույլ չի տալիս նշել պատկերի անունը:

Հետևաբար, մենք կօգտագործենք այս օգտակար ծրագրի փոփոխված տարբերակը, որը տրված է ստորև.

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

Նրա օգնությամբ մենք հավաքում ենք Spark-ի հիմնական պատկերը, որը պարունակում է թեստային առաջադրանք՝ Pi-ն հաշվարկելու համար Spark-ի միջոցով (այստեղ {docker-registry-url}-ը ձեր Docker պատկերի ռեեստրի URL-ն է, {repo}-ը ռեեստրի ներսում գտնվող պահեստի անվանումն է, որը համընկնում է նախագծին OpenShift-ում, {image-name} - պատկերի անվանումը (եթե օգտագործվում է պատկերների եռաստիճան տարանջատում, օրինակ, ինչպես Red Hat OpenShift պատկերների ինտեգրված ռեեստրում), {tag} - այս պիտակը պատկերի տարբերակը):

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

Մուտք գործեք OKD կլաստեր՝ օգտագործելով վահանակի կոմունալ ծրագիրը (այստեղ {OKD-API-URL} OKD կլաստերի API URL-ն է).

oc login {OKD-API-URL}

Եկեք ստանանք ընթացիկ օգտագործողի նշանը Docker Registry-ում թույլտվության համար.

oc whoami -t

Մուտք գործեք OKD կլաստերի ներքին Docker ռեգիստր (մենք օգտագործում ենք նախորդ հրամանի միջոցով ստացված նշանը որպես գաղտնաբառ).

docker login {docker-registry-url}

Եկեք վերբեռնենք հավաքված Docker պատկերը Docker Registry OKD:

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

Եկեք ստուգենք, որ հավաքված պատկերը հասանելի է OKD-ով: Դա անելու համար բրաուզերում բացեք URL-ը համապատասխան նախագծի պատկերների ցանկով (այստեղ {project}-ը նախագծի անվանումն է OpenShift կլաստերի ներսում, {OKD-WEBUI-URL}-ը OpenShift վեբ վահանակի URL-ն է: ) - https://{OKD-WEBUI-URL}/console /project/{project}/browse/images/{image-name}:

Առաջադրանքները գործարկելու համար պետք է ստեղծվի ծառայության հաշիվ՝ pods որպես root գործարկելու արտոնություններով (այս կետը կքննարկենք ավելի ուշ).

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

Եկեք գործարկենք spark-submit հրամանը՝ Spark առաջադրանքը OKD կլաստերում հրապարակելու համար՝ նշելով ստեղծված ծառայության հաշիվը և 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

Այստեղ:

— անունը — առաջադրանքի անվանումը, որը կմասնակցի Kubernetes pods-ի անվան ձևավորմանը.

— class — գործարկվող ֆայլի դաս, որը կանչվում է առաջադրանքի մեկնարկի ժամանակ.

—conf — կայծի կազմաձևման պարամետրեր;

spark.executor.instances — գործարկվող Spark կատարողների թիվը;

spark.kubernetes.authenticate.driver.serviceAccountName - Kubernetes ծառայության հաշվի անվանումը, որն օգտագործվում է pods գործարկելու ժամանակ (անվտանգության համատեքստը և հնարավորությունները սահմանելու համար Kubernetes API-ի հետ շփվելիս);

spark.kubernetes.namespace — Kubernetes-ի անվանատարածք, որտեղ կգործարկվեն վարորդի և կատարողի pods;

spark.submit.deployMode — Spark-ի գործարկման մեթոդ (ստանդարտ spark-submit-ի համար օգտագործվում է «կլաստերը», Spark օպերատորի և Spark «հաճախորդի» հետագա տարբերակների համար);

spark.kubernetes.container.image - Դոկերի պատկեր, որն օգտագործվում է փոդներ գործարկելու համար;

spark.master — Kubernetes API URL (արտաքին նշված է, որպեսզի մուտքը տեղի ունենա տեղական մեքենայից);

local://-ը Docker պատկերի ներսում Spark գործարկվող ուղին է:

Մենք գնում ենք համապատասխան OKD նախագիծ և ուսումնասիրում ենք ստեղծված փոդերը՝ https://{OKD-WEBUI-URL}/console/project/{project}/browse/pods:

Մշակման գործընթացը պարզեցնելու համար կարող է օգտագործվել մեկ այլ տարբերակ, որում ստեղծվում է Spark-ի ընդհանուր բազային պատկերը, որն օգտագործվում է բոլոր առաջադրանքների համար, և գործարկվող ֆայլերի նկարները հրապարակվում են արտաքին պահեստում (օրինակ՝ Hadoop) և նշված է զանգի ժամանակ: կայծ-ներկայացնել որպես հղում: Այս դեպքում դուք կարող եք գործարկել Spark առաջադրանքների տարբեր տարբերակներ՝ առանց Docker պատկերները վերակառուցելու՝ օգտագործելով, օրինակ, WebHDFS-ը՝ պատկերներ հրապարակելու համար: Մենք հարցում ենք ուղարկում ֆայլ ստեղծելու համար (այստեղ {host}-ը WebHDFS ծառայության հոսթն է, {port}-ը WebHDFS ծառայության պորտն է, {path-to-file-on-hdfs}-ը ֆայլի ցանկալի ուղին է։ HDFS-ում):

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

Դուք կստանաք այսպիսի պատասխան (այստեղ {location} այն URL-ն է, որը պետք է օգտագործվի ֆայլը ներբեռնելու համար).

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

Ներբեռնեք Spark գործարկվող ֆայլը HDFS-ում (այստեղ {path-to-local-file}-ն ընթացիկ հոսթի վրա Spark գործարկվող ֆայլի ուղին է).

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

Դրանից հետո մենք կարող ենք կատարել spark-submit՝ օգտագործելով HDFS-ում վերբեռնված Spark ֆայլը (այստեղ {class-name} այն դասի անունն է, որը պետք է գործարկվի՝ առաջադրանքն ավարտելու համար).

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

Հարկ է նշել, որ HDFS մուտք գործելու և առաջադրանքն ապահովելու համար ձեզ կարող է անհրաժեշտ լինել փոխել Dockerfile-ը և entrypoint.sh սկրիպտը. ավելացնել հրահանգ Dockerfile-ին՝ կախված գրադարանները պատճենելու համար /opt/spark/jars գրացուցակում և ներառել HDFS կազմաձևման ֆայլը SPARK_CLASSPATH-ում մուտքի կետում: sh.

Երկրորդ օգտագործման դեպք - Apache Livy

Ավելին, երբ առաջադրանքը մշակվում է և արդյունքը պետք է փորձարկվի, հարց է առաջանում այն ​​գործարկել որպես CI/CD գործընթացի մաս և հետևել դրա կատարման կարգավիճակին: Իհարկե, դուք կարող եք այն գործարկել՝ օգտագործելով տեղական spark-submit call, բայց դա բարդացնում է CI/CD ենթակառուցվածքը, քանի որ այն պահանջում է տեղադրել և կարգավորել Spark-ը CI սերվերի գործակալների/գործակալների վրա և մուտք գործել Kubernetes API: Այս դեպքում, թիրախային իրականացումը ընտրել է Apache Livy-ն օգտագործել որպես REST API՝ Spark առաջադրանքները գործարկելու համար, որոնք տեղակայված են Kubernetes կլաստերի ներսում: Նրա օգնությամբ դուք կարող եք գործարկել Spark-ի առաջադրանքները Kubernetes կլաստերի վրա՝ օգտագործելով սովորական cURL հարցումներ, որոնք հեշտությամբ իրականացվում են ցանկացած CI լուծման հիման վրա, և դրա տեղադրումը Kubernetes կլաստերի ներսում լուծում է նույնականացման խնդիրը Kubernetes API-ի հետ շփվելիս:

Running Apache Spark-ը Kubernetes-ում

Եկեք ընդգծենք այն որպես երկրորդ օգտագործման դեպք. Spark առաջադրանքների կատարումը որպես CI/CD գործընթացի մաս Kubernetes կլաստերի վրա փորձնական հանգույցում:

Մի փոքր Apache Livy-ի մասին. այն աշխատում է որպես HTTP սերվեր, որն ապահովում է վեբ ինտերֆեյս և RESTful API, որը թույլ է տալիս հեռակա գործարկել spark-submit-ը՝ փոխանցելով անհրաժեշտ պարամետրերը: Ավանդաբար այն առաքվել է որպես HDP բաշխման մաս, բայց կարող է նաև տեղակայվել OKD-ում կամ Kubernetes-ի ցանկացած այլ տեղադրում՝ օգտագործելով համապատասխան մանիֆեստը և Docker պատկերների մի շարք, ինչպիսին է այս մեկը. github.com/ttauveron/k8s-big-data-experiments/tree/master/livy-spark-2.3. Մեր դեպքի համար կառուցվել է նմանատիպ Docker պատկեր, ներառյալ Spark 2.4.5 տարբերակը հետևյալ 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"]

Ստեղծված պատկերը կարող է կառուցվել և վերբեռնվել ձեր գոյություն ունեցող Docker պահոցում, ինչպիսին է ներքին OKD պահոցը: Այն տեղադրելու համար օգտագործեք հետևյալ մանիֆեստը ({registry-url} - Docker պատկերի ռեեստրի URL, {image-name} - Docker պատկերի անունը, {tag} - Docker պատկերի պիտակ, {livy-url} - ցանկալի URL, որտեղ սերվերը հասանելի կլինի Livy-ին, «Route» մանիֆեստն օգտագործվում է, եթե Red Hat OpenShift-ն օգտագործվում է որպես Kubernetes բաշխում, հակառակ դեպքում օգտագործվում է NodePort տիպի համապատասխան Ingress կամ Service մանիֆեստը):

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

Այն կիրառելուց և pod-ը հաջողությամբ գործարկելուց հետո Livy գրաֆիկական ինտերֆեյսը հասանելի է հետևյալ հղումով՝ http://{livy-url}/ui: Livy-ի հետ մենք կարող ենք հրապարակել մեր Spark առաջադրանքը՝ օգտագործելով REST հարցումը, օրինակ, Փոստատարից: Ստորև ներկայացված է հարցումներով հավաքածուի օրինակ (գործարկված առաջադրանքի գործարկման համար անհրաժեշտ փոփոխականներով կազմաձևման փաստարկները կարող են փոխանցվել «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": {}
}

Եկեք կատարենք հավաքածուի առաջին հարցումը, անցնենք OKD միջերես և ստուգենք, որ առաջադրանքը հաջողությամբ գործարկվել է. https://{OKD-WEBUI-URL}/console/project/{project}/browse/pods: Միևնույն ժամանակ, Livy ինտերֆեյսում (http://{livy-url}/ui) կհայտնվի նիստ, որի շրջանակներում, օգտագործելով Livy API կամ գրաֆիկական ինտերֆեյսը, կարող եք հետևել առաջադրանքի առաջընթացին և ուսումնասիրել նիստը: գերաններ.

Հիմա եկեք ցույց տանք, թե ինչպես է աշխատում Լիվին: Դա անելու համար եկեք ուսումնասիրենք Livy կոնտեյների տեղեկամատյանները պատի ներսում Livy սերվերով - https://{OKD-WEBUI-URL}/console/project/{project}/browse/pods/{livy-pod-name }?tab=logs. Դրանցից մենք կարող ենք տեսնել, որ Livy REST API-ն «livy» անունով կոնտեյներով կանչելիս կատարվում է spark-submit, որը նման է վերևում օգտագործվածին (այստեղ {livy-pod-name} ստեղծված պատի անունն է: Livy սերվերի հետ): Հավաքածուն ներկայացնում է նաև երկրորդ հարցումը, որը թույլ է տալիս գործարկել առաջադրանքներ, որոնք հեռակա կարգով հյուրընկալում են Spark գործարկվող՝ օգտագործելով Livy սերվեր:

Երրորդ օգտագործման դեպք - Spark Operator

Այժմ, երբ առաջադրանքը փորձարկվել է, այն պարբերաբար գործարկելու հարց է առաջանում։ Kubernetes կլաստերում առաջադրանքները կանոնավոր կերպով գործարկելու բնիկ եղանակը CronJob-ն է, և դուք կարող եք օգտագործել այն, բայց այս պահին Kubernetes-ում հավելվածները կառավարելու օպերատորների օգտագործումը շատ տարածված է, և Spark-ի համար կա բավականին հասուն օպերատոր, որը նույնպես օգտագործվում է Enterprise մակարդակի լուծումներում (օրինակ՝ Lightbend FastData Platform): Մենք խորհուրդ ենք տալիս օգտագործել այն. Spark-ի ներկայիս կայուն տարբերակը (2.4.5) ունի բավականին սահմանափակ կազմաձևման տարբերակներ՝ Spark առաջադրանքները Kubernetes-ում գործարկելու համար, մինչդեռ հաջորդ հիմնական տարբերակը (3.0.0) հայտարարում է լիարժեք աջակցություն Kubernetes-ին, սակայն դրա թողարկման ամսաթիվը մնում է անհայտ: . Spark Operator-ը փոխհատուցում է այս թերությունը՝ ավելացնելով կազմաձևման կարևոր ընտրանքներ (օրինակ՝ տեղադրելով ConfigMap Hadoop մուտքի կոնֆիգուրացիայով Spark pods) և կանոնավոր պլանավորված առաջադրանքն իրականացնելու հնարավորությամբ:

Running Apache Spark-ը Kubernetes-ում
Եկեք ընդգծենք այն որպես երրորդ օգտագործման դեպք՝ պարբերաբար կատարելով Spark առաջադրանքները Kubernetes կլաստերի վրա՝ արտադրական օղակում:

Spark Operator-ը բաց կոդով է և մշակվել է Google Cloud Platform-ում. github.com/GoogleCloudPlatform/spark-on-k8s-operator. Դրա տեղադրումը կարող է իրականացվել 3 եղանակով.

  1. Որպես Lightbend FastData Platform/Cloudflow տեղադրման մաս;
  2. Օգտագործելով սահնակ.
    helm repo add incubator http://storage.googleapis.com/kubernetes-charts-incubator
    helm install incubator/sparkoperator --namespace spark-operator
    	

  3. Օգտագործելով մանիֆեստներ պաշտոնական պահոցից (https://github.com/GoogleCloudPlatform/spark-on-k8s-operator/tree/master/manifest): Արժե նշել հետևյալը. Cloudflow-ը ներառում է օպերատոր API v1beta1 տարբերակով: Եթե ​​տեղադրման այս տեսակն օգտագործվում է, Spark հավելվածի մանիֆեստի նկարագրությունները պետք է հիմնված լինեն Git-ի պիտակների վրա՝ համապատասխան API տարբերակով, օրինակ՝ «v1beta1-0.9.0-2.4.0»: Օպերատորի տարբերակը կարելի է գտնել «տարբերակներ» բառարանում օպերատորի մեջ ներառված CRD-ի նկարագրության մեջ.
    oc get crd sparkapplications.sparkoperator.k8s.io -o yaml
    	

Եթե ​​օպերատորը ճիշտ է տեղադրված, ապա համապատասխան նախագծում կհայտնվի Spark օպերատորի հետ ակտիվ pod (օրինակ՝ cloudflow-fdp-sparkoperator Cloudflow տարածքում՝ Cloudflow տեղադրման համար) և կհայտնվի համապատասխան Kubernetes ռեսուրսի տեսակ՝ «sparkapplications» անունով: . Դուք կարող եք ուսումնասիրել առկա Spark հավելվածները հետևյալ հրամանով.

oc get sparkapplications -n {project}

Spark Operator-ի միջոցով առաջադրանքները կատարելու համար անհրաժեշտ է անել 3 բան.

  • ստեղծել Docker պատկեր, որը ներառում է բոլոր անհրաժեշտ գրադարանները, ինչպես նաև կազմաձևման և գործարկվող ֆայլերը: Թիրախային նկարում սա պատկեր է, որը ստեղծվել է CI/CD փուլում և փորձարկվել է թեստային կլաստերի վրա.
  • հրապարակել Docker պատկերը ռեեստրում, որը հասանելի է Kubernetes կլաստերից.
  • ստեղծել մանիֆեստ «SparkApplication» տիպով և գործարկվելիք առաջադրանքի նկարագրությամբ: Մագիստրատների օրինակները հասանելի են պաշտոնական պահոցում (օրինակ. github.com/GoogleCloudPlatform/spark-on-k8s-operator/blob/v1beta1-0.9.0-2.4.0/examples/spark-pi.yaml) Մանիֆեստի վերաբերյալ կարևոր կետեր կան.
    1. «apiVersion» բառարանը պետք է նշի օպերատորի տարբերակին համապատասխան API տարբերակը.
    2. «metadata.namespace» բառարանը պետք է նշի այն անվանատարածքը, որտեղ կգործարկվի հավելվածը.
    3. «spec.image» բառարանը պետք է պարունակի ստեղծված Docker պատկերի հասցեն հասանելի ռեեստրում.
    4. «spec.mainClass» բառարանը պետք է պարունակի Spark առաջադրանքների դասը, որը պետք է գործարկվի, երբ գործընթացը սկսվի.
    5. «spec.mainApplicationFile» բառարանը պետք է պարունակի գործարկվող jar ֆայլի ուղին.
    6. «spec.sparkVersion» բառարանը պետք է նշի օգտագործվող Spark-ի տարբերակը.
    7. «spec.driver.serviceAccount» բառարանը պետք է նշի ծառայության հաշիվը համապատասխան Kubernetes անվանատարածքում, որը կօգտագործվի հավելվածը գործարկելու համար.
    8. «spec.executor» բառարանը պետք է նշի հավելվածին հատկացված ռեսուրսների քանակը.
    9. «spec.volumeMounts» բառարանը պետք է նշի տեղական գրացուցակը, որտեղ կստեղծվեն տեղական Spark առաջադրանքների ֆայլերը:

Մանիֆեստի ստեղծման օրինակ (այստեղ {spark-service-account}-ը ծառայողական հաշիվ է Kubernetes կլաստերի ներսում 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"

Այս մանիֆեստը սահմանում է ծառայության հաշիվ, որի համար, նախքան մանիֆեստը հրապարակելը, դուք պետք է ստեղծեք անհրաժեշտ դերային կապեր, որոնք ապահովում են Spark հավելվածի մուտքի անհրաժեշտ իրավունքները Kubernetes API-ի հետ փոխազդելու համար (անհրաժեշտության դեպքում): Մեր դեպքում հավելվածին պետք են իրավունքներ Pods ստեղծելու համար։ Եկեք ստեղծենք անհրաժեշտ դերակատարումը.

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

Հարկ է նաև նշել, որ այս մանիֆեստի հստակեցումը կարող է ներառել «hadoopConfigMap» պարամետր, որը թույլ է տալիս նշել ConfigMap-ը Hadoop-ի կազմաձևով՝ առանց համապատասխան ֆայլը Docker-ի պատկերում նախապես տեղադրելու: Այն նաև հարմար է առաջադրանքները պարբերաբար կատարելու համար. օգտագործելով «ժամանակացույց» պարամետրը, կարելի է նշել տվյալ առաջադրանքի կատարման ժամանակացույցը:

Դրանից հետո մենք պահում ենք մեր մանիֆեստը spark-pi.yaml ֆայլում և կիրառում այն ​​մեր Kubernetes կլաստերի վրա.

oc apply -f spark-pi.yaml

Սա կստեղծի «sparkapplications» տեսակի օբյեկտ.

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

Այս դեպքում կստեղծվի հավելվածով պատիճ, որի կարգավիճակը կցուցադրվի ստեղծված «sparkapplications»-ում: Դուք կարող եք դիտել այն հետևյալ հրամանով.

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

Առաջադրանքն ավարտելուց հետո POD-ը կանցնի «Ավարտված» կարգավիճակին, որը նույնպես կթարմացվի «sparkapplications»-ում: Հավելվածների տեղեկամատյանները կարելի է դիտել զննարկիչում կամ օգտագործելով հետևյալ հրամանը (այստեղ {sparkapplications-pod-name} գործող առաջադրանքի պատի անունն է).

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

Spark-ի առաջադրանքները կարող են կառավարվել նաև sparkctl-ի մասնագիտացված ծրագրի միջոցով: Այն տեղադրելու համար կլոնավորեք պահեստն իր սկզբնական կոդով, տեղադրեք Go և ստեղծեք այս օգտակար ծրագիրը.

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

Եկեք քննենք Spark առաջադրանքների ցանկը.

sparkctl list -n {project}

Եկեք ստեղծենք 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"

Եկեք գործարկենք նկարագրված առաջադրանքը, օգտագործելով sparkctl:

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

Եկեք քննենք Spark առաջադրանքների ցանկը.

sparkctl list -n {project}

Եկեք քննենք մեկնարկած Spark առաջադրանքի իրադարձությունների ցանկը.

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

Եկեք քննենք գործարկվող Spark առաջադրանքի կարգավիճակը.

sparkctl status spark-pi -n {project}

Եզրափակելով, ես կցանկանայի դիտարկել Կուբերնետեսում Spark-ի (2.4.5) ներկայիս կայուն տարբերակը օգտագործելու հայտնաբերված թերությունները.

  1. Առաջին և, հավանաբար, գլխավոր թերությունը տվյալների տեղայնության բացակայությունն է։ Չնայած YARN-ի բոլոր թերություններին, կային նաև առավելություններ այն օգտագործելու համար, օրինակ՝ կոդը տվյալներին փոխանցելու սկզբունքը (այլ ոչ թե տվյալների կոդ): Դրա շնորհիվ Spark-ի առաջադրանքները կատարվել են այն հանգույցների վրա, որտեղ տեղակայված են եղել հաշվարկներում ներգրավված տվյալները, և զգալիորեն կրճատվել է ցանցով տվյալների առաքման ժամանակը: Kubernetes-ն օգտագործելիս մենք բախվում ենք առաջադրանքի հետ կապված տվյալները ցանցով տեղափոխելու անհրաժեշտության հետ: Եթե ​​դրանք բավականաչափ մեծ են, առաջադրանքի կատարման ժամանակը կարող է զգալիորեն աճել, ինչպես նաև պահանջել բավականին մեծ քանակությամբ սկավառակի տարածություն, որը հատկացված է Spark առաջադրանքների օրինակներին՝ դրանց ժամանակավոր պահպանման համար: Այս թերությունը կարելի է մեղմել՝ օգտագործելով մասնագիտացված ծրագրակազմ, որն ապահովում է տվյալների տեղայնությունը Kubernetes-ում (օրինակ՝ Alluxio), բայց դա իրականում նշանակում է Kubernetes կլաստերի հանգույցների վրա տվյալների ամբողջական պատճենը պահելու անհրաժեշտություն:
  2. Երկրորդ կարևոր թերությունը անվտանգությունն է։ Լռելյայնորեն, Spark-ի առաջադրանքների հետ կապված անվտանգության հետ կապված գործառույթներն անջատված են, Kerberos-ի օգտագործումը չի ընդգրկված պաշտոնական փաստաթղթերում (չնայած համապատասխան տարբերակները ներդրվել են 3.0.0 տարբերակում, որը կպահանջի լրացուցիչ աշխատանք), և անվտանգության փաստաթղթերը օգտագործելով Spark-ը (https ://spark.apache.org/docs/2.4.5/security.html) միայն YARN-ը, Mesos-ը և Standalone Cluster-ը հայտնվում են որպես հիմնական խանութներ: Միևնույն ժամանակ, այն օգտատերը, որի ներքո գործարկվում են Spark-ի առաջադրանքները, չի կարող ուղղակիորեն նշվել. մենք նշում ենք միայն ծառայության հաշիվը, որի տակ այն կաշխատի, և օգտագործողը ընտրվում է կազմաձևված անվտանգության քաղաքականության հիման վրա: Այս առումով կամ օգտագործվում է արմատային օգտատերը, որն անվտանգ չէ արտադրողական միջավայրում, կամ պատահական UID-ով օգտվող, որը անհարմար է տվյալների մուտքի իրավունքը բաշխելիս (դա կարելի է լուծել՝ ստեղծելով PodSecurityPolicies և կապելով դրանք համապատասխան ծառայությունների հաշիվներ): Ներկայումս լուծումն այն է, որ կա՛մ բոլոր անհրաժեշտ ֆայլերը տեղադրել անմիջապես Docker պատկերի մեջ, կա՛մ փոփոխել Spark-ի գործարկման սցենարը՝ ձեր կազմակերպությունում ընդունված գաղտնիքները պահելու և առբերելու մեխանիզմն օգտագործելու համար:
  3. Kubernetes-ի միջոցով Spark-ի գործարկումը պաշտոնապես դեռ փորձնական ռեժիմում է, և ապագայում կարող են զգալի փոփոխություններ լինել օգտագործվող արտեֆակտներում (կազմաձևման ֆայլեր, Docker բազայի պատկերներ և գործարկման սկրիպտներ): Եվ իսկապես, նյութը պատրաստելիս փորձարկվել են 2.3.0 և 2.4.5 տարբերակները, վարքագիծը զգալիորեն տարբերվել է։

Սպասենք թարմացումներին. վերջերս թողարկվեց Spark-ի նոր տարբերակը (3.0.0), որը զգալի փոփոխություններ բերեց Spark-ի աշխատանքում Kubernetes-ում, բայց պահպանեց այս ռեսուրսների կառավարչի աջակցության փորձնական կարգավիճակը: Հավանաբար, հաջորդ թարմացումները իսկապես հնարավորություն կտան ամբողջությամբ խորհուրդ տալ հրաժարվել YARN-ից և կատարել Spark առաջադրանքները Kubernetes-ում՝ առանց վախենալու ձեր համակարգի անվտանգության համար և առանց ֆունկցիոնալ բաղադրիչները ինքնուրույն փոփոխելու անհրաժեշտության:

Վերջ

Source: www.habr.com

Добавить комментарий