Vážení čtenáři, dobrý den. Dnes si povíme něco málo o Apache Spark a jeho perspektivách vývoje.
V moderním světě velkých dat je Apache Spark de facto standardem pro vývoj úloh dávkového zpracování dat. Kromě toho se také používá k vytváření streamovacích aplikací, které pracují v mikrodávkovém konceptu, zpracovávají a nahrávají data po malých částech (Spark Structured Streaming). A tradičně to bylo součástí celkového Hadoop stacku s použitím YARN (nebo v některých případech Apache Mesos) jako správce zdrojů. Do roku 2020 je jeho používání ve své tradiční podobě pro většinu společností velkou otázkou kvůli nedostatku slušných distribucí Hadoop - vývoj HDP a CDH se zastavil, CDH je málo rozvinuté a má vysoké náklady a zbytek Hadoop poskytovatelé buď přestali existovat, nebo mají nejasnou budoucnost. Proto se komunita a velké společnosti stále více zajímají o provozování Apache Spark pomocí Kubernetes – protože se stalo standardem v orchestraci kontejnerů a správě zdrojů v soukromých a veřejných cloudech, řeší problém nepohodlného plánování zdrojů pro úlohy Spark na YARN a poskytuje stabilní vývojová platforma s mnoha komerčními a open source distribucemi pro společnosti všech velikostí. Navíc na vlně popularity se většině z nich již podařilo získat pár vlastních instalací a vybudovat si odborné znalosti v jeho používání, což zjednodušuje přesun.
Počínaje verzí 2.3.0 získal Apache Spark oficiální podporu pro spouštění úloh v clusteru Kubernetes a dnes si povíme něco o aktuální vyspělosti tohoto přístupu, různých možnostech jeho použití a úskalích, na které při implementaci narazí.
Nejprve se podíváme na proces vývoje úloh a aplikací založených na Apache Spark a upozorníme na typické případy, kdy chcete spustit úlohu na clusteru Kubernetes. Při přípravě tohoto příspěvku se jako distribuce používá OpenShift a budou uvedeny příkazy relevantní pro jeho nástroj příkazového řádku (oc). Pro ostatní distribuce Kubernetes lze použít příslušné příkazy standardního nástroje příkazového řádku Kubernetes (kubectl) nebo jejich ekvivalenty (například pro zásady oc adm).
První případ použití je spark-submit
Během vývoje úloh a aplikací musí vývojář spouštět úlohy pro ladění transformace dat. Teoreticky lze pro tyto účely použít pahýly, ale vývoj zahrnující skutečné (i když testovací) instance koncových systémů se v této třídě úloh ukázal jako rychlejší a lepší. V případě, že ladíme na skutečných instancích koncových systémů, jsou možné dva pracovní scénáře:
vývojář spustí úlohu Spark lokálně v samostatném režimu;
vývojář spustí úlohu Spark na clusteru Kubernetes v testovací smyčce.
První možnost má právo existovat, ale má řadu nevýhod:
pro každého vývojáře je požadován přístup z pracoviště ke všem instancím koncových systémů, které potřebuje;
Pro spuštění vyvíjené úlohy jsou na produkčním stroji vyžadovány dostatečné zdroje.
Druhá možnost postrádá tyto nedostatky, protože použití clusteru Kubernetes vám umožňuje alokovat potřebný fond zdrojů pro spouštění úloh a poskytnout mu potřebný přístup k instancím koncových systémů, flexibilně k němu poskytovat přístup pomocí modelu role Kubernetes pro všichni členové vývojového týmu. Vyzdvihněme to jako první případ použití – spouštění úloh Spark z místního vývojářského stroje na clusteru Kubernetes v testovacím okruhu.
Podívejme se blíže na proces nastavení Sparku pro místní spuštění. Chcete-li začít používat Spark, musíte jej nainstalovat:
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
Shromažďujeme potřebné balíčky pro práci s Kubernetes:
cd spark-2.4.5/
./build/mvn -Pkubernetes -DskipTests clean package
Úplné sestavení zabere spoustu času a ve skutečnosti jsou k vytvoření obrazů Docker a jejich spuštění v clusteru Kubernetes potřeba pouze jary z adresáře „assembly/“, takže lze sestavit pouze tento dílčí projekt:
Spouštění úloh Spark na Kubernetes vyžaduje, abyste vytvořili image Dockeru, který se použije jako základní image. Zde jsou 2 možné přístupy:
Vygenerovaný obraz Dockeru obsahuje spustitelný kód úlohy Spark;
Vytvořený image obsahuje pouze Spark a potřebné závislosti, spustitelný kód je hostován vzdáleně (například v HDFS).
Nejprve vytvořte obraz Dockeru obsahující testovací případ úlohy Spark. Pro vytváření obrazů Docker má Spark odpovídající nástroj s názvem „docker-image-tool“. Pojďme si to pro pomoc prostudovat:
./bin/docker-image-tool.sh --help
Lze jej použít k vytváření obrázků Docker a jejich nahrávání do vzdálených registrů, ale ve výchozím nastavení má řadu nevýhod:
bez selhání vytvoří 3 Docker obrazy najednou - pro Spark, PySpark a R;
neumožňuje zadat název obrázku.
Proto použijeme upravenou verzi tohoto nástroje, která je uvedena níže:
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
S jeho pomocí vytvoříme základní obrázek Spark, který obsahuje testovací úlohu pro výpočet čísla Pi pomocí Spark (zde {docker-registry-url} je adresa URL vašeho registru obrázků Docker, {repo} je název úložiště uvnitř registr, který odpovídá projektu v OpenShift , {image-name} — název obrázku (pokud je použito tříúrovňové oddělení obrázků, například jako v integrovaném registru obrázků Red Hat OpenShift), {tag} — tag tohoto obrázku verze):
Zkontrolujeme, zda je vytvořený obraz dostupný v OKD. Chcete-li to provést, otevřete v prohlížeči adresu URL se seznamem obrázků odpovídajícího projektu (zde {project} je název projektu v clusteru OpenShift, {OKD-WEBUI-URL} je adresa URL webové konzole OpenShift ) — https://{OKD-WEBUI-URL}/console /project/{project}/browse/images/{image-name}.
Chcete-li spouštět úlohy, musí být vytvořen servisní účet s oprávněními ke spouštění modulů jako root (tento bod probereme později):
--name - název úkolu, který se bude podílet na tvorbě názvu podů Kubernetes;
--class — třída spustitelného souboru volaného při spuštění úlohy;
--conf - konfigurační parametry Spark;
spark.executor.instances - počet spouštěcích programů Spark, které se mají spustit
spark.kubernetes.authenticate.driver.serviceAccountName – Název účtu služby Kubernetes používaného při spouštění Pods (k definování kontextu zabezpečení a možností při interakci s Kubernetes API)
spark.kubernetes.namespace – jmenný prostor Kubernetes, ve kterém poběží moduly ovladače a spouštěče;
spark.submit.deployMode - jak spustit Spark (pro standardní spark-submit použijte "cluster", pro Spark Operator a novější verze Spark "client");
spark.kubernetes.container.image je obraz Dockeru používaný ke spuštění modulů Pods.
spark.master – URL rozhraní Kubernetes API (je určeno externí, takže volání probíhá z místního počítače);
local:// je cesta ke spustitelnému souboru Spark uvnitř obrazu Dockeru.
Přejdeme do odpovídajícího projektu OKD a prostudujeme vytvořené pody - https://{OKD-WEBUI-URL}/console/project/{project}/browse/pods.
Pro zjednodušení procesu vývoje lze použít další možnost, ve které se vytvoří společný základní obraz Spark, který používají všechny úlohy ke spuštění, a snímky spustitelných souborů jsou publikovány na externí úložiště (například Hadoop) a specifikovány při volání sparku. - odeslat jako odkaz. V tomto případě můžete spouštět různé verze úloh Spark, aniž byste museli znovu sestavovat obrazy Dockeru, například pomocí WebHDFS k publikování obrazů. Odešleme požadavek na vytvoření souboru (zde {host} je hostitel služby WebHDFS, {port} je port služby WebHDFS, {cesta-k-souboru-na-hdfs} je požadovaná cesta k souboru na HDFS):
curl -i -X PUT "http://{host}:{port}/webhdfs/v1/{path-to-file-on-hdfs}?op=CREATE
Tím se vrátí odpověď formuláře (zde {location} je adresa URL, která se má použít ke stažení souboru):
Zároveň je třeba poznamenat, že pro přístup k HDFS a zprovoznění úlohy může být nutné změnit Dockerfile a skript entrypoint.sh – přidat do Dockerfile direktivu pro kopírování závislých knihoven do /opt /spark/jars a zahrňte konfigurační soubor HDFS do SPARK_CLASSPATH ve vstupním bodu.
Druhým případem použití je Apache Livy
Dále, když je úloha vyvinuta a je nutné otestovat získaný výsledek, vyvstává otázka jejího spuštění jako součásti procesu CI/CD a sledování stavu jejího provádění. Samozřejmě jej můžete spustit pomocí místního volání pro spark-submit, ale to komplikuje infrastrukturu CI / CD, protože vyžaduje instalaci a konfiguraci Spark na agentech / běžcích serveru CI a konfiguraci přístupu k Kubernetes API. V tomto případě se cílová implementace rozhodla použít Apache Livy jako REST API pro spouštění úloh Spark hostovaných v clusteru Kubernetes. S ním můžete spouštět úlohy Spark na clusteru Kubernetes pomocí běžných požadavků cURL, což je snadno implementovatelné na základě libovolného řešení CI a jeho umístění uvnitř clusteru Kubernetes řeší problém autentizace při interakci s Kubernetes API.
Vyzdvihněme to jako druhý případ použití – spouštění úloh Spark jako součást procesu CI / CD na clusteru Kubernetes v testovacím okruhu.
Něco málo o Apache Livy – funguje jako HTTP server, který poskytuje webové rozhraní a RESTful API, které vám umožní vzdáleně spustit spark-submit předáním potřebných parametrů. Tradičně byl dodáván jako součást distribuce HDP, ale lze jej nasadit také do OKD nebo jakékoli jiné instalace Kubernetes pomocí příslušného manifestu a sady obrazů Docker, jako je tento − github.com/ttauveron/k8s-big-data-experiments/tree/master/livy-spark-2.3. Pro náš případ byl vytvořen podobný obraz Docker, včetně Spark verze 2.4.5 z následujícího Dockerfile:
Vygenerovaný obrázek lze sestavit a nahrát do úložiště Docker, které máte, jako je například interní úložiště OKD. Chcete-li jej nasadit, použijte následující manifest ({registry-url} – adresa URL registru obrázků Docker, {image-name} – název obrázku Docker, {tag} – značka obrázku Docker, {livy-url} – požadovaná adresa URL, kam bude server být k dispozici Livy; manifest "Route" se použije, pokud je Red Hat OpenShift použit jako distribuce Kubernetes, jinak se použije odpovídající manifest Ingress nebo Service typu NodePort):
Po jeho použití a úspěšném spuštění modulu je Livy GUI dostupné na: http://{livy-url}/ui. S Livy můžeme publikovat naši úlohu Spark pomocí požadavku REST od Postmana, například. Níže je uveden příklad kolekce s požadavky (argumenty konfigurace s proměnnými nezbytnými pro práci spouštěné úlohy lze předat v poli "args"):
Proveďme první požadavek z kolekce, přejděte do rozhraní OKD a zkontrolujte, zda byla úloha úspěšně spuštěna - https://{OKD-WEBUI-URL}/console/project/{project}/browse/pods. Zároveň se v rozhraní Livy (http://{livy-url}/ui) objeví relace, v rámci které můžete pomocí Livy API nebo grafického rozhraní sledovat průběh úkolu a studovat protokoly relací.
Nyní si ukážeme, jak Livy funguje. Chcete-li to provést, prozkoumejte protokoly kontejneru Livy uvnitř pod se serverem Livy - https://{OKD-WEBUI-URL}/console/project/{project}/browse/pods/{livy-pod-name }?tab=logs. Z nich můžete vidět, že při volání Livy REST API v kontejneru s názvem „livy“ se provede spark-submit, podobný tomu, který jsme použili výše (zde {livy-pod-name} je název vytvořeného podu se serverem Livy). Kolekce také poskytuje druhý dotaz, který vám umožňuje spouštět úlohy se vzdáleným hostováním spustitelného souboru Spark pomocí serveru Livy.
Třetí případ použití - Spark Operator
Nyní, když je úloha otestována, vyvstává otázka jejího pravidelného spouštění. Nativním způsobem, jak pravidelně spouštět úlohy v clusteru Kubernetes, je entita CronJob a můžete ji používat, ale v současné době je použití operátorů pro správu aplikací v Kubernetes velmi populární a pro Spark existuje poměrně vyzrálý operátor, který mezi jiné věci, se používá v řešeních na podnikové úrovni (například Lightbend FastData Platform). Doporučujeme ji používat - aktuální stabilní verze Spark (2.4.5) má poněkud omezené možnosti konfigurace spouštění úloh Spark v Kubernetes, zatímco další hlavní verze (3.0.0) si nárokuje plnou podporu pro Kubernetes, ale její datum vydání zůstává neznámý. Spark Operator to vynahrazuje přidáním důležitých konfiguračních možností (jako je připojení ConfigMap s konfigurací přístupu Hadoop do Spark Pods) a možností pravidelného spouštění naplánované úlohy.
Vyjmenujme to jako třetí případ použití – pravidelné spouštění úloh Spark na clusteru Kubernetes v produkční smyčce.
Pomocí manifestů z oficiálního úložiště (https://github.com/GoogleCloudPlatform/spark-on-k8s-operator/tree/master/manifest). Zároveň stojí za zmínku následující – Cloudflow zahrnuje operátora s verzí API v1beta1. Pokud se použije tento typ instalace, pak by popisy manifestu aplikace Spark měly být založeny na příkladech ze značek v Gitu s příslušnou verzí API, například "v1beta1-0.9.0-2.4.0". Verzi operátora si můžete prohlédnout v popisu CRD, který je součástí operátoru ve slovníku "verze":
oc get crd sparkapplications.sparkoperator.k8s.io -o yaml
Pokud je operátor správně nainstalován, pak bude mít odpovídající projekt aktivní Pod s operátorem Spark (například cloudflow-fdp-sparkoperator v prostoru Cloudflow pro instalaci Cloudflow) a objeví se odpovídající typ prostředku Kubernetes s názvem „sparkapplications“. Dostupné aplikace Spark můžete prozkoumat pomocí následujícího příkazu:
oc get sparkapplications -n {project}
Chcete-li spouštět úlohy pomocí operátora Spark, musíte udělat 3 věci:
vytvořte obraz Dockeru, který obsahuje všechny potřebné knihovny a také konfigurační a spustitelné soubory. V cílovém obrázku se jedná o obrázek vytvořený ve fázi CI / CD a testovaný na testovacím clusteru;
publikovat obraz Dockeru do registru přístupného z clusteru Kubernetes;
Tento manifest specifikuje účet služby, pro který musíte před publikováním manifestu vytvořit nezbytné vazby rolí a poskytnout potřebná přístupová práva pro aplikaci Spark pro interakci s Kubernetes API (v případě potřeby). V našem případě aplikace potřebuje práva k vytvoření Podů. Vytvořme potřebnou vazbu role:
Za zmínku také stojí, že parametr „hadoopConfigMap“ může být specifikován ve specifikaci tohoto manifestu, což vám umožňuje zadat ConfigMap s konfigurací Hadoop, aniž byste museli nejprve vkládat odpovídající soubor do obrazu Docker. Je vhodný i pro pravidelné spouštění úloh – pomocí parametru „plán“ lze určit plán spouštění této úlohy.
Poté uložíme náš manifest do souboru spark-pi.yaml a aplikujeme jej na náš cluster Kubernetes:
oc apply -f spark-pi.yaml
Tím se vytvoří objekt typu "sparkapplications":
oc get sparkapplications -n {project}
> NAME AGE
> spark-pi 22h
Tím se vytvoří pod s aplikací, jejíž stav se bude zobrazovat ve vytvořených „sparkapplications“. Lze jej zobrazit pomocí následujícího příkazu:
oc get sparkapplications spark-pi -o yaml -n {project}
Po dokončení úkolu přejde POD do stavu „Completed“, který bude také aktualizován v „sparkapplications“. Protokoly aplikací lze zobrazit v prohlížeči nebo pomocí následujícího příkazu (zde {sparkapplications-pod-name} je název spuštěné úlohy pod):
oc logs {sparkapplications-pod-name} -n {project}
Úlohy Spark lze také spravovat pomocí specializovaného nástroje sparkctl. Chcete-li jej nainstalovat, naklonujeme úložiště s jeho zdrojovým kódem, nainstalujeme Go a vytvoříme tento nástroj:
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
Podívejme se na seznam událostí spuštěné úlohy Spark:
sparkctl event spark-pi -n {project} -f
Podívejme se na stav spuštěné úlohy Spark:
sparkctl status spark-pi -n {project}
Na závěr bych rád zvážil objevené nevýhody provozování aktuální stabilní verze Spark (2.4.5) v Kubernetes:
První a možná hlavní nevýhodou je nedostatek datové lokality. Přes všechny nedostatky YARN byly v jeho použití plusy, například princip doručování kódu do dat (spíše než data do kódu). Díky němu byly úkoly Sparku prováděny na uzlech, kde se nacházela data zúčastněná na výpočtech, a čas na doručení dat po síti se znatelně zkrátil. Při používání Kubernetes se potýkáme s potřebou přesouvat po síti data, která se podílejí na práci na úkolu. Jsou-li dostatečně velké, může se doba provádění úlohy výrazně prodloužit a je třeba alokovat dostatečně velké množství místa na disku instancím úloh Spark pro jejich dočasné úložiště. Tuto nevýhodu lze snížit použitím specializovaných softwarových nástrojů, které poskytují datovou lokalitu v Kubernetes (například Alluxio), ale ve skutečnosti to znamená nutnost ukládat kompletní kopii dat na uzly clusteru Kubernetes.
Druhou velkou nevýhodou je bezpečnost. Ve výchozím nastavení jsou funkce související se zabezpečením týkající se spouštění úloh Spark zakázány, použití Kerberos není zahrnuto v oficiální dokumentaci (ačkoli odpovídající možnosti se objevily ve verzi 3.0.0, která bude vyžadovat další práci) a v dokumentaci zabezpečení při použití Spark (https://spark.apache.org/docs/2.4.5/security.html) se jako úložiště klíčů objeví pouze YARN, Mesos a Standalone Cluster. Zároveň nelze přímo specifikovat uživatele, pod kterým jsou úlohy Sparku spouštěny – nastavujeme pouze servisní účet, pod kterým bude pracovat, a uživatel je vybírán na základě nakonfigurovaných bezpečnostních politik. V tomto ohledu je použit buď uživatel root, který není v produktivním prostředí bezpečný, nebo uživatel s náhodným UID, což je nepohodlné při distribuci přístupových práv k datům (rozhoduje se vytvořením PodSecurityPolicies a jejich propojením s odpovídajícími servisními účty) . V tuto chvíli je řešením buď vložení všech potřebných souborů přímo do obrazu Dockeru, nebo úprava spouštěcího skriptu Spark tak, aby používal mechanismus pro ukládání a získávání tajných informací akceptovaných ve vaší organizaci.
Spouštění úloh Spark s Kubernetes je stále oficiálně v experimentálním režimu a v budoucnu může dojít k významným změnám v použitých artefaktech (konfigurační soubory, základní obrázky Dockeru a spouštěcí skripty). A skutečně – při přípravě materiálu se testovaly verze 2.3.0 a 2.4.5, chování bylo výrazně odlišné.
Počkejme si na aktualizace – nedávno byla vydána čerstvá verze Spark (3.0.0), která přinesla hmatatelné změny do práce Sparku na Kubernetes, ale zachovala si experimentální status podpory tohoto správce zdrojů. Snad příští aktualizace skutečně umožní plně doporučit opustit YARN a spouštět úlohy Spark na Kubernetes bez obav o bezpečnost vašeho systému a bez nutnosti sami dolaďovat funkční komponenty.