القراء الأعزاء ، مساء الخير. سنتحدث اليوم قليلاً عن Apache Spark وآفاق تطويرها.
في العالم الحديث للبيانات الضخمة ، يعد Apache Spark المعيار الفعلي لتطوير مهام معالجة البيانات المجمعة. بالإضافة إلى ذلك ، يتم استخدامه أيضًا لإنشاء تطبيقات دفق تعمل في مفهوم الدُفعات الصغيرة ومعالجة وتحميل البيانات في أجزاء صغيرة (Spark Structured Streaming). وقد كان تقليديًا جزءًا من مكدس Hadoop الإجمالي ، باستخدام YARN (أو ، في بعض الحالات ، Apache Mesos) كمدير للموارد. بحلول عام 2020 ، يكون استخدامه في شكله التقليدي لمعظم الشركات محل سؤال كبير بسبب عدم وجود توزيعات Hadoop لائقة - توقف تطوير HDP و CDH ، CDH متخلف وله تكلفة عالية ، وبقية Hadoop لم يعد مقدمو الخدمة موجودون أو لديهم مستقبل غامض. لذلك ، يهتم المجتمع والشركات الكبيرة بشكل متزايد بتشغيل Apache Spark باستخدام Kubernetes - بعد أن أصبح المعيار في تنسيق الحاويات وإدارة الموارد في السحب الخاصة والعامة ، فإنه يحل مشكلة تخطيط الموارد غير المريح لمهام Spark على YARN ويوفر بشكل ثابت منصة تطوير مع العديد من التوزيعات التجارية ومفتوحة المصدر للشركات من جميع الأحجام. بالإضافة إلى ذلك ، في موجة الشعبية ، تمكن معظمهم بالفعل من الحصول على اثنين من التركيبات الخاصة بهم وبناء الخبرة في استخدامها ، مما يبسط هذه الخطوة.
بدءًا من الإصدار 2.3.0 ، تلقى Apache Spark دعمًا رسميًا لتشغيل المهام في مجموعة Kubernetes ، وسنتحدث اليوم عن النضج الحالي لهذا النهج ، والخيارات المختلفة لاستخدامه ، والمزالق التي ستواجهها أثناء التنفيذ.
أولاً وقبل كل شيء ، دعنا نلقي نظرة على عملية تطوير المهام والتطبيقات بناءً على Apache Spark وإبراز الحالات النموذجية التي تريد فيها تشغيل مهمة على مجموعة Kubernetes. في إعداد هذا المنشور ، يتم استخدام OpenShift كتوزيع وسيتم إعطاء الأوامر ذات الصلة بأداة سطر الأوامر (oc). بالنسبة لتوزيعات Kubernetes الأخرى ، يمكن استخدام الأوامر المناسبة لأداة سطر أوامر Kubernetes القياسية (kubectl) أو ما يعادلها (على سبيل المثال ، لسياسة oc adm).
حالة الاستخدام الأولى هي إرسال شرارة
أثناء تطوير المهام والتطبيقات ، يحتاج المطور إلى تشغيل المهام لتصحيح أخطاء تحويل البيانات. من الناحية النظرية ، يمكن استخدام بذرة لهذه الأغراض ، ولكن التطوير الذي يتضمن أمثلة حقيقية (وإن كانت اختبارية) للأنظمة النهائية أثبت أنه أسرع وأفضل في هذه الفئة من المهام. في الحالة التي نقوم فيها بتصحيح الأخطاء في حالات حقيقية للأنظمة النهائية ، هناك سيناريوهان للعمل:
يقوم المطور بتشغيل مهمة Spark محليًا في الوضع المستقل ؛
يقوم أحد المطورين بتشغيل مهمة 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 ، لذلك يمكن إنشاء هذا المشروع الفرعي فقط:
يتطلب تشغيل مهام Spark على Kubernetes إنشاء صورة Docker لاستخدامها كصورة أساسية. هناك طريقتان محتملتان هنا:
تشتمل صورة 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} هو عنوان URL لسجل صور Docker الخاص بك ، {repo} هو اسم المستودع بالداخل السجل ، الذي يطابق المشروع في OpenShift ، {image-name} - اسم الصورة (إذا تم استخدام فصل ثلاثي المستويات للصور ، على سبيل المثال ، كما هو الحال في سجل الصور المتكامل Red Hat OpenShift) ، {tag} - علامة هذا نسخة الصورة):
دعنا نتحقق من أن الصورة المبنية متاحة في OKD. للقيام بذلك ، افتح عنوان URL مع قائمة صور المشروع المقابل في المتصفح (هنا {project} هو اسم المشروع داخل مجموعة OpenShift ، {OKD-WEBUI-URL} هو عنوان URL لوحدة تحكم الويب OpenShift ) - https: // {OKD-WEBUI-URL} / console / project / {project} / browse / images / {image-name}.
لتشغيل المهام ، يجب إنشاء حساب خدمة بامتيازات تشغيل البودات كجذر (سنناقش هذه النقطة لاحقًا):
--name - اسم المهمة التي ستشارك في تشكيل اسم Kubernetes pods ؛
--class - فئة الملف القابل للتنفيذ تسمى عند بدء المهمة ؛
--conf - معلمات تكوين شرارة ؛
spark.executor.instances - عدد منفذي Spark المطلوب تشغيلهم
spark.kubernetes.authenticate.driver.serviceAccountName - اسم حساب خدمة Kubernetes المستخدم عند تشغيل Pods (لتحديد سياق الأمان والإمكانيات عند التفاعل مع Kubernetes API)
spark.kubernetes.namespace - مساحة اسم Kubernetes حيث سيتم تشغيل أقراص برنامج التشغيل والمنفذ ؛
spark.submit.deployMode - كيفية بدء تشغيل Spark (بالنسبة إلى استخدام شرارة الإرسال القياسي "الكتلة" ، لمشغل Spark والإصدارات الأحدث من Spark "العميل") ؛
spark.kubernetes.container.image - صورة عامل ميناء تُستخدم لتشغيل القرون
spark.master - عنوان URL الخاص بواجهة برمجة تطبيقات Kubernetes (يتم تحديد خارجي بحيث يتم إجراء الاستدعاء من الجهاز المحلي) ؛
local: // هو المسار إلى ملف Spark القابل للتنفيذ داخل صورة Docker.
نذهب إلى مشروع OKD المقابل وندرس البودات التي تم إنشاؤها - https: // {OKD-WEBUI-URL} / console / project / {project} / browse / pods.
لتبسيط عملية التطوير ، يمكن استخدام خيار آخر ، حيث يتم إنشاء صورة شرارة أساسية مشتركة ، وتستخدمها جميع المهام للتشغيل ، ويتم نشر لقطات من الملفات القابلة للتنفيذ في وحدة التخزين الخارجية (على سبيل المثال ، Hadoop) وتحديدها عند استدعاء شرارة -تقديمه كرابط. في هذه الحالة ، يمكنك تشغيل إصدارات مختلفة من مهام Spark دون إعادة إنشاء صور Docker باستخدام ، على سبيل المثال ، WebHDFS لنشر الصور. نرسل طلبًا لإنشاء ملف (هنا {host} هو مضيف خدمة WebHDFS ، {المنفذ} هو منفذ خدمة 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 الذي سيتم استخدامه لتنزيل الملف):
في الوقت نفسه ، تجدر الإشارة إلى أنه من أجل الوصول إلى HDFS وجعل المهمة تعمل ، قد يكون من الضروري تغيير Dockerfile و entrypoint.sh النصي - إضافة توجيه إلى Dockerfile لنسخ المكتبات التابعة إلى / opt / spark / jars وقم بتضمين ملف تكوين HDFS في SPARK_CLASSPATH في نقطة الدخول.
حالة الاستخدام الثانية هي Apache Livy
علاوة على ذلك ، عندما يتم تطوير المهمة ويكون مطلوبًا لاختبار النتيجة التي تم الحصول عليها ، فإن السؤال الذي يطرح نفسه هو إطلاقها كجزء من عملية CI / CD وتتبع حالة تنفيذها. بالطبع ، يمكنك تشغيله باستدعاء محلي لإرسال شرارة ، ولكن هذا يعقد البنية التحتية CI / CD لأنه يتطلب تثبيت وتكوين Spark على وكلاء / مشغلي خادم CI وتكوين الوصول إلى Kubernetes API. لهذه الحالة ، اختار التنفيذ المستهدف استخدام Apache Livy باعتباره REST API لتشغيل مهام Spark المستضافة داخل مجموعة Kubernetes. باستخدامه ، يمكنك تشغيل مهام Spark على مجموعة Kubernetes باستخدام طلبات cURL العادية ، والتي يتم تنفيذها بسهولة بناءً على أي حل CI ، ووضعها داخل مجموعة Kubernetes يحل مشكلة المصادقة عند التفاعل مع Kubernetes API.
لنفردها كحالة الاستخدام الثانية - تشغيل مهام Spark كجزء من عملية CI / CD على مجموعة Kubernetes في دائرة اختبار.
قليلا عن Apache Livy - إنه يعمل كخادم HTTP يوفر واجهة ويب وواجهة برمجة تطبيقات RESTful تتيح لك تشغيل إرسال شرارة عن بعد عن طريق تمرير المعلمات الضرورية. تم شحنه تقليديًا كجزء من توزيع HDP ، ولكن يمكن أيضًا نشره في OKD أو أي تثبيت Kubernetes آخر باستخدام البيان المناسب ومجموعة من صور Docker ، مثل هذا - github.com/ttauveron/k8s-big-data-experiments/tree/master/livy-spark-2.3. بالنسبة لحالتنا ، تم إنشاء صورة Docker مماثلة ، بما في ذلك إصدار Spark 2.4.5 من Dockerfile التالي:
يمكن إنشاء الصورة التي تم إنشاؤها وتحميلها إلى مستودع Docker لديك ، مثل مستودع OKD الداخلي. لنشره ، استخدم البيان التالي ({Registry-url} - عنوان URL لسجل Docker image ، {image-name} - Docker image name ، {tag} - علامة صورة Docker ، {livy-url} - عنوان URL المطلوب حيث سيقوم الخادم كن متاحًا Livy ؛ يتم استخدام بيان "المسار" إذا تم استخدام Red Hat OpenShift كتوزيع Kubernetes ، وإلا فسيتم استخدام بيان الدخول أو الخدمة المقابل لنوع NodePort):
بعد تطبيقه وتشغيل الكبسولة بنجاح ، تتوفر واجهة المستخدم الرسومية Livy على: http: // {livy-url} / ui. مع Livy ، يمكننا نشر مهمة Spark الخاصة بنا باستخدام طلب REST من Postman ، على سبيل المثال. يتم تقديم مثال لمجموعة مع طلبات أدناه (يمكن تمرير وسيطات التكوين مع المتغيرات اللازمة لعمل المهمة التي تم إطلاقها في مصفوفة "args"):
دعنا ننفذ الطلب الأول من المجموعة ، وانتقل إلى واجهة OKD وتحقق من بدء المهمة بنجاح - https: // {OKD-WEBUI-URL} / console / project / {project} / browse / pods. في الوقت نفسه ، ستظهر جلسة في واجهة Livy (http: // {livy-url} / ui) ، والتي من خلالها ، باستخدام واجهة برمجة تطبيقات Livy أو واجهة رسومية ، يمكنك مراقبة تقدم المهمة ودراسة سجلات الجلسة.
الآن دعنا نظهر كيف تعمل ليفي. للقيام بذلك ، دعنا نفحص سجلات حاوية Livy داخل الكبسولة باستخدام خادم Livy - https: // {OKD-WEBUI-URL} / console / project / {project} / browse / pods / {livy-pod-name }؟ علامة التبويب = السجلات. يمكنك أن ترى منهم أنه عند استدعاء Livy REST API في حاوية تسمى "livy" ، يتم إجراء إرسال شرارة ، على غرار ما استخدمناه أعلاه (هنا {livy-pod-name} هو اسم الكبسولة التي تم إنشاؤها مع خادم Livy). توفر المجموعة أيضًا استعلامًا ثانيًا يسمح لك بتشغيل المهام مع الاستضافة عن بُعد لبرنامج Spark القابل للتنفيذ باستخدام خادم Livy.
حالة الاستخدام الثالثة - عامل الشرارة
الآن وقد تم اختبار المهمة ، يطرح السؤال حول إطلاقها المنتظم. الطريقة الأصلية لتشغيل المهام بانتظام في مجموعة Kubernetes هي كيان CronJob ويمكنك استخدامه ، ولكن في الوقت الحالي ، يحظى استخدام المشغلين لإدارة التطبيقات في Kubernetes بشعبية كبيرة وهناك عامل ناضج إلى حد ما لـ Spark ، والذي من بين أشياء أخرى ، يتم استخدامها في حلول على مستوى المؤسسة (على سبيل المثال ، Lightbend FastData Platform). نوصي باستخدامه - يحتوي الإصدار الثابت الحالي من Spark (2.4.5) على خيارات محدودة نوعًا ما لتكوين إطلاق مهام Spark في Kubernetes ، بينما يطالب الإصدار الرئيسي التالي (3.0.0) بالدعم الكامل لـ Kubernetes ، ولكن تاريخ إصداره ما زال مجهولا. يعوض Spark Operator عن ذلك عن طريق إضافة خيارات تكوين مهمة (مثل تركيب ConfigMap مع تكوين وصول Hadoop إلى Spark Pods) والقدرة على تشغيل مهمة مجدولة على أساس منتظم.
دعنا نفرزها كحالة استخدام ثالثة - تشغيل مهام Spark بانتظام على مجموعة Kubernetes في حلقة إنتاج.
استخدام البيانات من المستودع الرسمي (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 (على سبيل المثال ، cloudflow-fdp-sparkoperator في مساحة Cloudflow لتثبيت Cloudflow) وسيظهر نوع مورد Kubernetes المقابل المسمى "sparkapplications". يمكنك استكشاف تطبيقات Spark المتاحة باستخدام الأمر التالي:
oc get sparkapplications -n {project}
لتشغيل المهام باستخدام Spark Operator ، عليك القيام بثلاثة أشياء:
قم بإنشاء صورة Docker تتضمن جميع المكتبات الضرورية ، بالإضافة إلى ملفات التكوين والملفات القابلة للتنفيذ. في الصورة المستهدفة ، هذه صورة تم إنشاؤها في مرحلة CI / CD واختبارها على مجموعة اختبار ؛
نشر صورة Docker في سجل يمكن الوصول إليه من مجموعة Kubernetes ؛
يحدد هذا البيان حساب الخدمة الذي تحتاج إلى إنشاء روابط الأدوار اللازمة له قبل نشر البيان ، مما يوفر حقوق الوصول الضرورية لتطبيق Spark للتفاعل مع Kubernetes API (إذا لزم الأمر). في حالتنا ، يحتاج التطبيق إلى حقوق إنشاء Pods. لنقم بإنشاء دور ملزم:
تجدر الإشارة أيضًا إلى أنه يمكن تحديد معلمة "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
سيؤدي هذا إلى إنشاء جراب مع تطبيق سيتم عرض حالته في "تطبيق شرارات" الذي تم إنشاؤه. يمكن مشاهدته بالأمر التالي:
oc get sparkapplications spark-pi -o yaml -n {project}
عند الانتهاء من المهمة ، سينتقل POD إلى الحالة "مكتمل" ، والتي سيتم تحديثها أيضًا في "تطبيقات الشرارة". يمكن عرض سجلات التطبيق في المتصفح أو باستخدام الأمر التالي (هنا {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 (2.4.5) في Kubernetes:
العيب الأول ، وربما العيب الرئيسي ، هو الافتقار إلى منطقة البيانات. على الرغم من جميع أوجه القصور في YARN ، كانت هناك إيجابيات في استخدامه ، على سبيل المثال ، مبدأ تسليم الكود إلى البيانات (بدلاً من البيانات للتشفير). بفضله ، تم تنفيذ مهام Spark على العقد حيث تم تحديد البيانات المتضمنة في الحسابات ، وتم تقليل الوقت اللازم لتسليم البيانات عبر الشبكة بشكل ملحوظ. عند استخدام Kubernetes ، نواجه الحاجة إلى نقل البيانات المتضمنة في عمل المهمة عبر الشبكة. إذا كانت كبيرة بما يكفي ، فيمكن زيادة وقت تنفيذ المهمة بشكل كبير ، ويلزم تخصيص مساحة كبيرة بما فيه الكفاية لمثيلات مهمة Spark لتخزينها المؤقت. يمكن تقليل هذا العيب باستخدام أدوات برمجية متخصصة توفر موقع البيانات في Kubernetes (على سبيل المثال ، Alluxio) ، ولكن هذا يعني في الواقع الحاجة إلى تخزين نسخة كاملة من البيانات على عقد مجموعة Kubernetes.
الجانب السلبي الرئيسي الثاني هو الأمن. بشكل افتراضي ، يتم تعطيل الميزات المتعلقة بالأمان فيما يتعلق بتشغيل مهام 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 لبدء التشغيل لاستخدام آلية تخزين واسترداد الأسرار المقبولة في مؤسستك.
لا يزال تشغيل مهام Spark باستخدام Kubernetes رسميًا في الوضع التجريبي وقد تكون هناك تغييرات كبيرة في العناصر الأثرية المستخدمة (ملفات التكوين وصور قاعدة Docker ونصوص بدء التشغيل) في المستقبل. وبالفعل - عند تحضير المواد ، تم اختبار الإصدارين 2.3.0 و 2.4.5 ، كان السلوك مختلفًا بشكل كبير.
دعنا ننتظر التحديثات - تم إصدار إصدار جديد من Spark (3.0.0) مؤخرًا ، والذي أدخل تغييرات ملموسة على عمل Spark على Kubernetes ، لكنه احتفظ بالحالة التجريبية لدعم مدير الموارد هذا. ربما ستتيح التحديثات التالية حقًا التوصية بشكل كامل بالتخلي عن YARN وتشغيل مهام Spark على Kubernetes دون خوف على أمان نظامك ودون الحاجة إلى تحسين المكونات الوظيفية بنفسك.