Kubernetes پر Apache Spark چل رہا ہے۔

پیارے قارئین، دوپہر بخیر۔ آج ہم Apache Spark اور اس کے ترقی کے امکانات کے بارے میں تھوڑی بات کریں گے۔

Kubernetes پر Apache Spark چل رہا ہے۔

بگ ڈیٹا کی جدید دنیا میں، Apache Spark بیچ ڈیٹا پروسیسنگ کے کاموں کو تیار کرنے کے لیے ڈی فیکٹو سٹینڈرڈ ہے۔ اس کے علاوہ، اس کا استعمال اسٹریمنگ ایپلی کیشنز بنانے کے لیے بھی کیا جاتا ہے جو مائیکرو بیچ کے تصور، پروسیسنگ اور چھوٹے حصوں میں ڈیٹا شپنگ (Spark Structured Streaming) میں کام کرتی ہیں۔ اور روایتی طور پر یہ مجموعی طور پر Hadoop اسٹیک کا حصہ رہا ہے، جس میں YARN (یا کچھ معاملات میں Apache Mesos) کو بطور ریسورس مینیجر استعمال کیا گیا ہے۔ 2020 تک، ہڈوپ کی معقول تقسیم کی کمی کی وجہ سے زیادہ تر کمپنیوں کے لیے اس کا روایتی شکل میں استعمال سوالیہ نشان ہے - HDP اور CDH کی ترقی رک گئی ہے، CDH اچھی طرح سے تیار نہیں ہے اور اس کی قیمت زیادہ ہے، اور باقی Hadoop سپلائرز یا تو وجود ختم ہو گیا یا مستقبل مدھم ہو گیا۔ لہذا، Kubernetes کا استعمال کرتے ہوئے Apache Spark کا آغاز کمیونٹی اور بڑی کمپنیوں کے درمیان دلچسپی کا باعث ہے - نجی اور عوامی بادلوں میں کنٹینر آرکیسٹریشن اور وسائل کے انتظام میں ایک معیاری بننا، یہ YARN پر Spark کے کاموں کی تکلیف دہ وسائل کے شیڈولنگ کے مسئلے کو حل کرتا ہے اور فراہم کرتا ہے۔ تمام سائز اور پٹیوں کی کمپنیوں کے لیے بہت سے تجارتی اور کھلی تقسیم کے ساتھ ایک مسلسل ترقی پذیر پلیٹ فارم۔ مزید برآں، مقبولیت کے تناظر میں، زیادہ تر نے پہلے ہی اپنی ایک دو تنصیبات حاصل کر لی ہیں اور اس کے استعمال میں اپنی مہارت میں اضافہ کر لیا ہے، جو اس اقدام کو آسان بناتا ہے۔

ورژن 2.3.0 کے ساتھ شروع کرتے ہوئے، Apache Spark نے Kubernetes کلسٹر میں کام چلانے کے لیے باضابطہ تعاون حاصل کیا اور آج، ہم اس نقطہ نظر کی موجودہ پختگی، اس کے استعمال کے لیے مختلف اختیارات اور عمل درآمد کے دوران پیش آنے والے نقصانات کے بارے میں بات کریں گے۔

سب سے پہلے، آئیے Apache Spark کی بنیاد پر کاموں اور ایپلی کیشنز کو تیار کرنے کے عمل کو دیکھتے ہیں اور مخصوص معاملات کو نمایاں کرتے ہیں جن میں آپ کو Kubernetes کلسٹر پر ٹاسک چلانے کی ضرورت ہوتی ہے۔ اس پوسٹ کی تیاری میں، OpenShift کو تقسیم کے طور پر استعمال کیا جاتا ہے اور اس کی کمانڈ لائن یوٹیلیٹی (oc) سے متعلقہ کمانڈز دی جائیں گی۔ دیگر Kubernetes کی تقسیم کے لیے، معیاری Kubernetes کمانڈ لائن یوٹیلیٹی (kubectl) سے متعلقہ کمانڈز یا ان کے analogues (مثال کے طور پر، oc adm پالیسی کے لیے) استعمال کیے جا سکتے ہیں۔

پہلا استعمال کیس - چنگاری جمع کروائیں۔

کاموں اور ایپلی کیشنز کی ترقی کے دوران، ڈویلپر کو ڈیٹا کی تبدیلی کو ڈیبگ کرنے کے لیے کام چلانے کی ضرورت ہوتی ہے۔ نظریاتی طور پر، سٹبس کو ان مقاصد کے لیے استعمال کیا جا سکتا ہے، لیکن اختتامی نظام کے حقیقی (اگرچہ ٹیسٹ کے باوجود) مثالوں کی شرکت کے ساتھ ترقی اس طبقے کے کاموں میں تیز اور بہتر ثابت ہوئی ہے۔ اس صورت میں جب ہم اختتامی نظام کی حقیقی مثالوں پر ڈیبگ کرتے ہیں، تو دو منظرنامے ممکن ہیں:

  • ڈویلپر ایک اسپارک ٹاسک کو مقامی طور پر اسٹینڈ اسٹون موڈ میں چلاتا ہے۔

    Kubernetes پر Apache Spark چل رہا ہے۔

  • ایک ڈویلپر ٹیسٹ لوپ میں کبرنیٹس کلسٹر پر اسپارک ٹاسک چلاتا ہے۔

    Kubernetes پر Apache Spark چل رہا ہے۔

پہلا آپشن موجود ہونے کا حق رکھتا ہے، لیکن اس میں بہت سے نقصانات شامل ہیں:

  • ہر ڈویلپر کو لازمی طور پر کام کی جگہ سے آخری سسٹم کی تمام مثالوں تک رسائی فراہم کی جانی چاہیے جس کی اسے ضرورت ہے۔
  • تیار کیے جانے والے کام کو چلانے کے لیے ورکنگ مشین پر وسائل کی کافی مقدار درکار ہوتی ہے۔

دوسرے آپشن میں یہ نقصانات نہیں ہیں، کیونکہ ایک Kubernetes کلسٹر کا استعمال آپ کو کاموں کو چلانے کے لیے ضروری وسائل کے پول کو مختص کرنے کی اجازت دیتا ہے اور اسے سسٹم کے اختتامی واقعات تک ضروری رسائی فراہم کرتا ہے، اس کے لیے Kubernetes رول ماڈل کا استعمال کرتے ہوئے لچکدار طریقے سے اس تک رسائی فراہم کرتا ہے۔ ترقیاتی ٹیم کے تمام ممبران۔ آئیے اسے استعمال کے پہلے کیس کے طور پر اجاگر کریں - ایک ٹیسٹ لوپ میں Kubernetes کلسٹر پر مقامی ڈویلپر مشین سے 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

ایک مکمل تعمیر میں کافی وقت لگتا ہے، اور ڈوکر امیجز بنانے اور انہیں کبرنیٹس کلسٹر پر چلانے کے لیے، آپ کو واقعی صرف "اسمبلی/" ڈائرکٹری سے جار فائلوں کی ضرورت ہوتی ہے، لہذا آپ صرف یہ سب پروجیکٹ بنا سکتے ہیں:

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

کبرنیٹس پر اسپارک جابز چلانے کے لیے، آپ کو بیس امیج کے طور پر استعمال کرنے کے لیے ایک ڈاکر امیج بنانے کی ضرورت ہے۔ یہاں 2 ممکنہ نقطہ نظر ہیں:

  • تیار کردہ ڈاکر امیج میں قابل عمل اسپارک ٹاسک کوڈ شامل ہے۔
  • بنائی گئی تصویر میں صرف اسپارک اور ضروری انحصار شامل ہیں، قابل عمل کوڈ کو دور سے ہوسٹ کیا جاتا ہے (مثال کے طور پر HDFS میں)۔

سب سے پہلے، آئیے ایک Docker امیج بنائیں جس میں اسپارک ٹاسک کی آزمائشی مثال ہو۔ ڈوکر امیجز بنانے کے لیے، اسپارک کی ایک افادیت ہے جسے "docker-image-tool" کہتے ہیں۔ آئیے اس پر مدد کا مطالعہ کریں:

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

اس کی مدد سے، آپ Docker کی تصاویر بنا سکتے ہیں اور انہیں ریموٹ رجسٹریوں میں اپ لوڈ کر سکتے ہیں، لیکن بطور ڈیفالٹ اس کے بہت سے نقصانات ہیں:

  • بغیر کسی ناکامی کے ایک ساتھ 3 ڈوکر امیجز بناتا ہے - اسپارک، پی اسپارک اور آر کے لیے۔
  • آپ کو تصویر کا نام بتانے کی اجازت نہیں دیتا۔

لہذا، ہم ذیل میں دی گئی اس افادیت کا ایک ترمیم شدہ ورژن استعمال کریں گے:

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 کا حساب لگانے کے لیے ایک ٹیسٹ ٹاسک ہوتا ہے (یہاں {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}

آئیے ڈوکر رجسٹری میں اجازت کے لیے موجودہ صارف کا ٹوکن حاصل کریں:

oc whoami -t

OKD کلسٹر کی اندرونی Docker رجسٹری میں لاگ ان کریں (ہم پاس ورڈ کے طور پر پچھلی کمانڈ کا استعمال کرتے ہوئے حاصل کردہ ٹوکن استعمال کرتے ہیں):

docker login {docker-registry-url}

آئیے جمع شدہ ڈوکر امیج کو ڈوکر رجسٹری 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}۔

کاموں کو چلانے کے لیے، پوڈز کو روٹ کے طور پر چلانے کے لیے مراعات کے ساتھ ایک سروس اکاؤنٹ بنانا چاہیے (ہم اس نکتے پر بعد میں بات کریں گے):

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

آئیے اسپارک ٹاسک کو OKD کلسٹر میں شائع کرنے کے لیے spark-submit کمانڈ چلائیں، بنائے گئے سروس اکاؤنٹ اور 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 کے نام کی تشکیل میں حصہ لے گا۔

—کلاس — ایگزیکیوٹیبل فائل کی کلاس، جب کام شروع ہوتا ہے تو کہا جاتا ہے۔

—conf — چنگاری ترتیب کے پیرامیٹرز؛

spark.executor.instances — لانچ کرنے کے لیے اسپارک ایگزیکیوٹرز کی تعداد؛

spark.kubernetes.authenticate.driver.serviceAccountName - پوڈز لانچ کرتے وقت استعمال ہونے والے Kubernetes سروس اکاؤنٹ کا نام (Kubernetes API کے ساتھ تعامل کرتے وقت سیکیورٹی سیاق و سباق اور صلاحیتوں کی وضاحت کرنے کے لیے)؛

spark.kubernetes.namespace — Kubernetes نام کی جگہ جس میں ڈرائیور اور ایگزیکیوٹر پوڈز لانچ کیے جائیں گے۔

spark.submit.deployMode — اسپارک کو لانچ کرنے کا طریقہ (معیاری اسپارک-سبمٹ کے لیے "کلسٹر" استعمال کیا جاتا ہے، اسپارک آپریٹر اور اسپارک "کلائنٹ" کے بعد کے ورژن کے لیے)؛

spark.kubernetes.container.image - ڈوکر امیج جو پوڈز کو لانچ کرنے کے لیے استعمال ہوتی ہے۔

spark.master — Kubernetes API URL (بیرونی مخصوص ہے لہذا رسائی مقامی مشین سے ہوتی ہے)؛

local:// ڈوکر امیج کے اندر اسپارک قابل عمل کا راستہ ہے۔

ہم متعلقہ OKD پروجیکٹ پر جاتے ہیں اور بنائے گئے پوڈز کا مطالعہ کرتے ہیں - https://{OKD-WEBUI-URL}/console/project/{project}/browse/pods۔

ترقی کے عمل کو آسان بنانے کے لیے، ایک اور آپشن استعمال کیا جا سکتا ہے، جس میں اسپارک کی ایک مشترکہ بیس امیج بنائی جاتی ہے، جسے چلانے کے لیے تمام کاموں کے ذریعے استعمال کیا جاتا ہے، اور ایگزیکیوٹیبل فائلوں کے سنیپ شاٹس کو بیرونی اسٹوریج (مثال کے طور پر، ہڈوپ) میں شائع کیا جاتا ہے اور کال کرتے وقت مخصوص کیا جاتا ہے۔ چنگاری-ایک لنک کے طور پر جمع کرائیں. اس صورت میں، آپ 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

اسپارک ایگزیکیوٹیبل فائل کو HDFS میں لوڈ کریں (یہاں {path-to-local-file} موجودہ میزبان پر اسپارک ایگزیکیوٹیبل فائل کا راستہ ہے):

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

اس کے بعد، ہم HDFS پر اپ لوڈ کردہ Spark فائل کا استعمال کرتے ہوئے spark-submit کر سکتے ہیں (یہاں {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 اسکرپٹ کو تبدیل کرنے کی ضرورت پڑ سکتی ہے - ڈوکر فائل میں ایک ہدایت شامل کریں تاکہ انحصار لائبریریوں کو /opt/spark/jars ڈائرکٹری میں کاپی کیا جا سکے۔ انٹری پوائنٹ میں SPARK_CLASSPATH میں HDFS کنفیگریشن فائل شامل کریں۔

دوسرا استعمال کیس - اپاچی لیوی

مزید، جب کوئی کام تیار کیا جاتا ہے اور اس کے نتیجے کو جانچنے کی ضرورت ہوتی ہے، تو سوال یہ پیدا ہوتا ہے کہ اسے CI/CD عمل کے حصے کے طور پر شروع کیا جائے اور اس پر عمل درآمد کی حیثیت کا پتہ لگایا جائے۔ بلاشبہ، آپ اسے مقامی اسپارک-سبمٹ کال کا استعمال کرتے ہوئے چلا سکتے ہیں، لیکن یہ CI/CD انفراسٹرکچر کو پیچیدہ بناتا ہے کیونکہ اس کے لیے CI سرور ایجنٹس/رنرز پر اسپارک کو انسٹال اور کنفیگر کرنے اور Kubernetes API تک رسائی قائم کرنے کی ضرورت ہوتی ہے۔ اس معاملے کے لیے، ہدف کے نفاذ نے Apache Livy کو ایک REST API کے طور پر استعمال کرنے کا انتخاب کیا ہے تاکہ ایک Kubernetes کلسٹر کے اندر ہوسٹ کیے گئے Spark کاموں کو چلانے کے لیے۔ اس کی مدد سے، آپ باقاعدہ cURL درخواستوں کا استعمال کرتے ہوئے Kubernetes کلسٹر پر Spark ٹاسک چلا سکتے ہیں، جو آسانی سے کسی بھی CI حل کی بنیاد پر لاگو کیا جاتا ہے، اور Kubernetes کلسٹر کے اندر اس کی جگہ کا تعین Kubernetes API کے ساتھ بات چیت کرتے وقت تصدیق کے مسئلے کو حل کرتا ہے۔

Kubernetes پر Apache Spark چل رہا ہے۔

آئیے اسے دوسرے استعمال کے معاملے کے طور پر اجاگر کریں - ایک ٹیسٹ لوپ میں Kubernetes کلسٹر پر CI/CD عمل کے حصے کے طور پر Spark کے کاموں کو چلانا۔

Apache Livy کے بارے میں تھوڑا سا - یہ ایک HTTP سرور کے طور پر کام کرتا ہے جو ایک ویب انٹرفیس اور ایک RESTful API فراہم کرتا ہے جو آپ کو ضروری پیرامیٹرز کو پاس کرکے دور سے اسپارک سبمٹ لانچ کرنے کی اجازت دیتا ہے۔ روایتی طور پر اسے HDP تقسیم کے حصے کے طور پر بھیجا گیا ہے، لیکن مناسب مینی فیسٹ اور Docker امیجز کے ایک سیٹ کا استعمال کرتے ہوئے OKD یا کسی دوسرے Kubernetes انسٹالیشن پر بھی تعینات کیا جا سکتا ہے، جیسے کہ یہ - github.com/ttauveron/k8s-big-data-experiments/tree/master/livy-spark-2.3. ہمارے کیس کے لیے، اسی طرح کی ڈوکر امیج بنائی گئی تھی، بشمول 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"]

تیار کردہ تصویر کو آپ کے موجودہ ڈوکر ریپوزٹری، جیسے اندرونی OKD ریپوزٹری میں بنایا اور اپ لوڈ کیا جا سکتا ہے۔ اسے تعینات کرنے کے لیے، درج ذیل مینی فیسٹ کا استعمال کریں ({registry-url} - ڈوکر امیج رجسٹری کا URL، {image-name} - Docker امیج کا نام، {tag} - Docker image tag، {livy-url} - مطلوبہ URL جہاں سرور قابل رسائی Livy ہو گا؛ "روٹ" مینی فیسٹ استعمال کیا جاتا ہے اگر Red Hat OpenShift کو Kubernetes ڈسٹری بیوشن کے طور پر استعمال کیا جاتا ہے، بصورت دیگر NodePort قسم کا متعلقہ Ingress یا Service manifest استعمال کیا جاتا ہے:

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

اسے لاگو کرنے اور پوڈ کو کامیابی سے لانچ کرنے کے بعد، Livy گرافیکل انٹرفیس لنک پر دستیاب ہے: http://{livy-url}/ui۔ Livy کے ساتھ، ہم اپنے اسپارک ٹاسک کو REST کی درخواست کا استعمال کر کے شائع کر سکتے ہیں، مثال کے طور پر، پوسٹ مین۔ درخواستوں کے ساتھ مجموعہ کی ایک مثال ذیل میں پیش کی گئی ہے (شروع کیے گئے کام کے آپریشن کے لیے ضروری متغیرات کے ساتھ کنفیگریشن آرگیومنٹس کو "آرگس" صف میں پاس کیا جا سکتا ہے):

{
    "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 سرور کے ساتھ پوڈ کے اندر موجود Livy کنٹینر کے لاگز کا جائزہ لیں - https://{OKD-WEBUI-URL}/console/project/{project}/browse/pods/{livy-pod-name }?tab=logs۔ ان سے ہم دیکھ سکتے ہیں کہ جب "livy" نامی کنٹینر میں Livy REST API کو کال کرتے ہیں، تو ایک چنگاری جمع کرائی جاتی ہے، جیسا کہ ہم نے اوپر استعمال کیا ہے (یہاں {livy-pod-name} تخلیق شدہ پوڈ کا نام ہے۔ لیوی سرور کے ساتھ)۔ مجموعہ میں ایک دوسری استفسار بھی متعارف کرایا گیا ہے جو آپ کو ایسے کاموں کو چلانے کی اجازت دیتا ہے جو لیوی سرور کا استعمال کرتے ہوئے دور سے ایک اسپارک ایگزیکیوٹیبل کی میزبانی کرتے ہیں۔

تیسرا استعمال کیس - اسپارک آپریٹر

اب جب کہ اس کام کا تجربہ ہوچکا ہے، اس کو باقاعدگی سے چلانے کا سوال پیدا ہوتا ہے۔ Kubernetes کلسٹر میں کاموں کو باقاعدگی سے چلانے کا مقامی طریقہ CronJob entity ہے اور آپ اسے استعمال کر سکتے ہیں، لیکن اس وقت Kubernetes میں ایپلی کیشنز کو منظم کرنے کے لیے آپریٹرز کا استعمال بہت مشہور ہے اور Spark کے لیے کافی سمجھدار آپریٹر موجود ہے، جو کہ آپریٹر بھی ہے۔ انٹرپرائز سطح کے حل میں استعمال کیا جاتا ہے (مثال کے طور پر، لائٹ بینڈ فاسٹ ڈیٹا پلیٹ فارم)۔ ہم اسے استعمال کرنے کی تجویز کرتے ہیں - اسپارک کے موجودہ مستحکم ورژن (2.4.5) میں کبرنیٹس میں اسپارک ٹاسک چلانے کے لیے کنفیگریشن کے محدود اختیارات ہیں، جب کہ اگلا بڑا ورژن (3.0.0) کبرنیٹس کے لیے مکمل تعاون کا اعلان کرتا ہے، لیکن اس کی ریلیز کی تاریخ نامعلوم ہے۔ . اسپارک آپریٹر کنفیگریشن کے اہم آپشنز (مثال کے طور پر اسپارک پوڈز میں ہڈوپ رسائی کنفیگریشن کے ساتھ کنفیگ میپ لگانا) اور باقاعدگی سے طے شدہ کام کو چلانے کی صلاحیت شامل کرکے اس کمی کی تلافی کرتا ہے۔

Kubernetes پر Apache Spark چل رہا ہے۔
آئیے اسے استعمال کے تیسرے کیس کے طور پر اجاگر کرتے ہیں - ایک پروڈکشن لوپ میں Kubernetes کلسٹر پر Spark کے کاموں کو باقاعدگی سے چلاتے ہیں۔

اسپارک آپریٹر اوپن سورس ہے اور گوگل کلاؤڈ پلیٹ فارم کے اندر تیار کیا گیا ہے۔ github.com/GoogleCloudPlatform/spark-on-k8s-operator. اس کی تنصیب 3 طریقوں سے کی جا سکتی ہے:

  1. لائٹ بینڈ فاسٹ ڈیٹا پلیٹ فارم/کلاؤڈ فلو انسٹالیشن کے حصے کے طور پر؛
  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 والا آپریٹر شامل ہے۔ اگر اس قسم کی تنصیب کا استعمال کیا جاتا ہے تو، اسپارک ایپلیکیشن مینی فیسٹ کی تفصیل گٹ میں مناسب API ورژن کے ساتھ مثال کے ٹیگز پر مبنی ہونی چاہیے، مثال کے طور پر، "v1beta1-0.9.0-2.4.0"۔ آپریٹر کا ورژن "ورژن" لغت میں آپریٹر میں شامل CRD کی تفصیل میں پایا جا سکتا ہے:
    oc get crd sparkapplications.sparkoperator.k8s.io -o yaml
    	

اگر آپریٹر صحیح طریقے سے انسٹال ہوا ہے تو، متعلقہ پروجیکٹ میں اسپارک آپریٹر کے ساتھ ایک فعال پوڈ ظاہر ہوگا (مثال کے طور پر، کلاؤڈ فلو کی تنصیب کے لیے کلاؤڈ فلو اسپیس میں کلاؤڈ فلو-fdp-sparkoperator) اور اس سے متعلقہ Kubernetes ریسورس کی قسم "sparkapplications" ظاہر ہوگی۔ . آپ مندرجہ ذیل کمانڈ کے ساتھ دستیاب سپارک ایپلی کیشنز کو تلاش کر سکتے ہیں:

oc get sparkapplications -n {project}

اسپارک آپریٹر کا استعمال کرتے ہوئے کاموں کو چلانے کے لیے آپ کو 3 چیزیں کرنے کی ضرورت ہے:

  • ایک ڈوکر امیج بنائیں جس میں تمام ضروری لائبریریوں کے ساتھ ساتھ کنفیگریشن اور قابل عمل فائلیں شامل ہوں۔ ٹارگٹ پکچر میں، یہ ایک تصویر ہے جسے CI/CD اسٹیج پر بنایا گیا ہے اور ٹیسٹ کلسٹر پر آزمایا گیا ہے۔
  • کوبرنیٹس کلسٹر سے قابل رسائی رجسٹری میں ڈوکر امیج شائع کریں۔
  • "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" ڈکشنری میں قابل عمل جار فائل کا راستہ ہونا چاہیے؛
    6. "spec.sparkVersion" ڈکشنری میں Spark کے استعمال ہونے والے ورژن کی نشاندہی کرنی چاہیے۔
    7. "spec.driver.serviceAccount" ڈکشنری کو متعلقہ Kubernetes نام کی جگہ کے اندر سروس اکاؤنٹ کی وضاحت کرنی چاہیے جو ایپلیکیشن چلانے کے لیے استعمال کیا جائے گا۔
    8. "spec.executor" لغت میں درخواست کے لیے مختص وسائل کی تعداد کی نشاندہی کرنی چاہیے۔
    9. "spec.volumeMounts" ڈکشنری میں مقامی ڈائرکٹری کی وضاحت ہونی چاہیے جس میں مقامی Spark ٹاسک فائلیں بنائی جائیں گی۔

مینی فیسٹ بنانے کی ایک مثال (یہاں {spark-service-account} Spark کاموں کو چلانے کے لیے Kubernetes کلسٹر کے اندر ایک سروس اکاؤنٹ ہے):

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"

یہ مینی فیسٹ ایک سروس اکاؤنٹ کی وضاحت کرتا ہے جس کے لیے، مینی فیسٹ کو شائع کرنے سے پہلے، آپ کو ضروری رول بائنڈنگز بنانا ہوں گی جو اسپارک ایپلیکیشن کو Kubernetes API (اگر ضروری ہو) کے ساتھ تعامل کرنے کے لیے ضروری رسائی کے حقوق فراہم کرتی ہیں۔ ہمارے معاملے میں، درخواست کو پوڈز بنانے کے حقوق کی ضرورت ہے۔ آئیے ضروری رول بائنڈنگ بنائیں:

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

یہ بات بھی قابل توجہ ہے کہ اس مینی فیسٹ تفصیلات میں "hadoopConfigMap" پیرامیٹر شامل ہوسکتا ہے، جو آپ کو Docker امیج میں متعلقہ فائل کو پہلے رکھے بغیر Hadoop کنفیگریشن کے ساتھ ConfigMap کی وضاحت کرنے کی اجازت دیتا ہے۔ یہ کاموں کو باقاعدگی سے چلانے کے لیے بھی موزوں ہے - "شیڈول" پیرامیٹر کا استعمال کرتے ہوئے، دیئے گئے کام کو چلانے کے لیے ایک شیڈول متعین کیا جا سکتا ہے۔

اس کے بعد، ہم اپنے مینی فیسٹ کو 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}

اسپارک ٹاسکس کو خصوصی sparkctl یوٹیلیٹی کا استعمال کرتے ہوئے بھی منظم کیا جا سکتا ہے۔ اسے انسٹال کرنے کے لیے اس کے سورس کوڈ کے ساتھ ریپوزٹری کو کلون کریں، گو انسٹال کریں اور اس یوٹیلیٹی کو بنائیں:

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

آئیے اسپارک ٹاسک چلانے کی فہرست کا جائزہ لیتے ہیں:

sparkctl list -n {project}

آئیے اسپارک ٹاسک کے لیے ایک تفصیل بنائیں:

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}

آئیے اسپارک ٹاسک چلانے کی فہرست کا جائزہ لیتے ہیں:

sparkctl list -n {project}

آئیے شروع کیے گئے اسپارک ٹاسک کے واقعات کی فہرست کا جائزہ لیتے ہیں:

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

آئیے چلتے ہوئے اسپارک ٹاسک کی حیثیت کا جائزہ لیتے ہیں:

sparkctl status spark-pi -n {project}

آخر میں، میں Kubernetes میں Spark (2.4.5) کے موجودہ مستحکم ورژن کو استعمال کرنے کے دریافت شدہ نقصانات پر غور کرنا چاہوں گا:

  1. پہلا اور، شاید، بنیادی نقصان ڈیٹا لوکلٹی کی کمی ہے۔ YARN کی تمام تر خامیوں کے باوجود، اس کے استعمال کے فوائد بھی تھے، مثال کے طور پر، کوڈ کو ڈیٹا تک پہنچانے کا اصول (بجائے ڈیٹا سے کوڈ)۔ اس کی بدولت، اسپارک کے کاموں کو ان نوڈس پر انجام دیا گیا جہاں حسابات میں شامل ڈیٹا موجود تھا، اور نیٹ ورک پر ڈیٹا کی فراہمی میں لگنے والے وقت کو نمایاں طور پر کم کر دیا گیا۔ Kubernetes استعمال کرتے وقت، ہمیں پورے نیٹ ورک پر کام میں شامل ڈیٹا کو منتقل کرنے کی ضرورت کا سامنا کرنا پڑتا ہے۔ اگر وہ کافی بڑے ہیں تو، ٹاسک پر عمل درآمد کا وقت نمایاں طور پر بڑھ سکتا ہے، اور اس کے لیے اسپارک ٹاسک انسٹینسز کو ان کے عارضی اسٹوریج کے لیے مختص کی گئی کافی بڑی مقدار میں ڈسک کی جگہ کی ضرورت ہوتی ہے۔ اس نقصان کو خصوصی سافٹ ویئر کے استعمال سے کم کیا جا سکتا ہے جو Kubernetes میں ڈیٹا لوکلٹی کو یقینی بناتا ہے (مثال کے طور پر Alluxio)، لیکن اس کا اصل مطلب یہ ہے کہ ڈیٹا کی مکمل کاپی کوبرنیٹس کلسٹر کے نوڈس پر اسٹور کرنے کی ضرورت ہے۔
  2. دوسرا اہم نقصان سیکورٹی ہے. پہلے سے طے شدہ طور پر، اسپارک ٹاسکس کو چلانے کے حوالے سے سیکورٹی سے متعلقہ خصوصیات کو غیر فعال کر دیا جاتا ہے، کربروس کا استعمال سرکاری دستاویزات میں شامل نہیں ہوتا ہے (حالانکہ متعلقہ اختیارات ورژن 3.0.0 میں متعارف کرائے گئے تھے، جس کے لیے اضافی کام کی ضرورت ہوگی)، اور حفاظتی دستاویزات Spark (https://spark.apache.org/docs/2.4.5/security.html) کا استعمال کرتے ہوئے صرف YARN، Mesos اور اسٹینڈ الون کلسٹر کلیدی اسٹورز کے طور پر ظاہر ہوتے ہیں۔ ایک ہی وقت میں، وہ صارف جس کے تحت اسپارک ٹاسک شروع کیے گئے ہیں، براہ راست متعین نہیں کیا جا سکتا ہے - ہم صرف اس سروس اکاؤنٹ کی وضاحت کرتے ہیں جس کے تحت یہ کام کرے گا، اور صارف کا انتخاب کنفیگر شدہ سیکیورٹی پالیسیوں کی بنیاد پر کیا جاتا ہے۔ اس سلسلے میں، یا تو روٹ یوزر استعمال کیا جاتا ہے، جو پیداواری ماحول میں محفوظ نہیں ہے، یا پھر بے ترتیب UID والا صارف، جو ڈیٹا تک رسائی کے حقوق کی تقسیم کے وقت تکلیف دہ ہوتا ہے (اسے PodSecurityPolicies بنا کر اور ان کو لنک کرکے حل کیا جاسکتا ہے۔ متعلقہ سروس اکاؤنٹس)۔ فی الحال، حل یہ ہے کہ یا تو تمام ضروری فائلوں کو براہ راست Docker امیج میں رکھیں، یا اپنی تنظیم میں اپنائے گئے رازوں کو ذخیرہ کرنے اور بازیافت کرنے کے طریقہ کار کو استعمال کرنے کے لیے اسپارک لانچ اسکرپٹ میں ترمیم کریں۔
  3. کبرنیٹس کا استعمال کرتے ہوئے اسپارک جابز کو چلانا باضابطہ طور پر اب بھی تجرباتی موڈ میں ہے اور مستقبل میں استعمال شدہ نمونے (کنفیگریشن فائلز، ڈوکر بیس امیجز، اور لانچ اسکرپٹس) میں نمایاں تبدیلیاں ہو سکتی ہیں۔ اور درحقیقت، مواد تیار کرتے وقت، ورژن 2.3.0 اور 2.4.5 کا تجربہ کیا گیا، رویہ نمایاں طور پر مختلف تھا۔

آئیے اپ ڈیٹس کا انتظار کرتے ہیں - اسپارک (3.0.0) کا ایک نیا ورژن حال ہی میں جاری کیا گیا تھا، جس نے کبرنیٹس پر اسپارک کے کام میں اہم تبدیلیاں لائی ہیں، لیکن اس ریسورس مینیجر کے لیے تعاون کی تجرباتی حیثیت کو برقرار رکھا ہے۔ شاید اگلی اپڈیٹس آپ کے سسٹم کی حفاظت کے لیے بغیر کسی خوف کے اور فنکشنل پرزوں کو آزادانہ طور پر ترمیم کرنے کی ضرورت کے بغیر یارن کو ترک کرنے اور کوبرنیٹس پر اسپارک کے کاموں کو چلانے کی مکمل سفارش کرنا ممکن بنائے گی۔

فن

ماخذ: www.habr.com

نیا تبصرہ شامل کریں