Purumir's Blog

Machine Learning, SW architect, Management, favorites

kubernetes로 spark-submit하기(spark-submit to kubernetes)

spark 공식 사이트( https://spark.apache.org/docs/latest/running-on-kubernetes.html ) 에 spark-submit을 kubernetes상에서 수행하는 방법에 대해서 나와 있습니다. 가이드에 따라서 container를 빌드하고 이를 이용해 spark-submit을 하는 상황입니다. 이 작업의 컨셉 다이어 그램은 아래와 같습니다.


제가 겪은 상황은 spark-submit을 kubernetes cluster상에 namespace를 생성하고, 해당 namespace에 istio-injection:enabled를 했을 경우 겪게 되었던 “Initial Job has not accepted any resources: check your cluster UI to ensure that workers are registered and have sufficient resources”에 대한 트러블 슈팅에 대한 내용입니다. 특히 kubeflow를 설치시 istio관련 많은 컴포넌트들이 설치되는데 이로 인해서 위와 같은 에러 상황을 마주하게 되었습니다.

해결책은 spark-submit시 istio-injection을 false처리하는 것입니다. 이를 통해서 spark-submit시 (특히 client mode시) spark driver와 spark executor의 communication이 되지 않아 발생하는 “Initial Job has not accepted any resources: check your cluster UI to ensure that workers are registered and have sufficient resources” 의 트러블 슈팅이 가능합니다.

kubernetes에서 spark-submit을 수행하기 위해서는 다음과 같은 절차를 따릅니다.

1) Namespace 생성 & Service Account 생성 & ClusterRoleBinding 수행

  • Namespace 생성 & istio-injection enable
1
2
kubectl create namespace data-platform
kubectl label namespace data-platform istio-injection=enabled
  • Service Account & ClusterRoleBinding 생성
1
2
3
Using kubectl)
kubectl create serviceaccount spark --namespace=data-platform
kubectl create clusterrolebinding spark-role --clusterrole=edit --serviceaccount=data-platform:spark --namespace=data-platform
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: v1
kind: ServiceAccount
metadata:
name: spark
namespace: data-platform
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: spark-role
namespace: data-platform
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: edit
subjects:
- kind: ServiceAccount
name: spark
namespace: data-platform

2) spark-submit시 “—conf spark.kubernetes.executor.annotation.sidecar.istio.io/inject=false” 옵션을 추가하는데, 이는 istio환경에서 POD를 구동시 istio가 side-car를 injection하면서 kubernetes cluster 외부에 있는 spark driver와 kubernetes cluster내부에 있는 spark client의 communication을 blocking하기 때문에 side-car injection을 하지 않게 하는 것입니다.

“—conf spark.kubernetes.authenticate.oauthTokenFile=“과 “—conf spark.kubernetes.authenticate.caCertFile=“은 위에서 생성한 service account의 secret에 있는 token값과 ca.crt내용입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
./bin/spark-submit \
--master k8s://https://<k8s master IP>:6443 \
--deploy-mode client \
--name spark-pi \
--class org.apache.spark.examples.SparkPi \
--conf spark.kubernetes.namespace=data-platform \
--conf spark.kubernetes.authenticate.driver.serviceAccountName=spark \
--conf spark.kubernetes.container.image=<spark official site 가이드 따라 빌드한 컨테이너 이미지> \
--conf spark.kubernetes.driver.volumes.persistentVolumeClaim.<Persistent Volume Claim Name>.options.claimName=<Persistent Volume Claim Name> \
--conf spark.kubernetes.driver.volumes.persistentVolumeClaim.<Persistent Volume Claim Name>.mount.path=<storage class path> \
--conf spark.kubernetes.driver.volumes.persistentVolumeClaim.<Persistent Volume Claim Name>.mount.readOnly=false \
--conf spark.kubernetes.authenticate.oauthTokenFile=<file location> # service account(spark) token file
--conf spark.kubernetes.authenticate.caCertFile=<file location> # service account(spark) ca.crt파일
--conf spark.kubernetes.executor.request.cores=500m \
--conf spark.kubernetes.driverEnv.memory=1g \
--conf spark.kubernetes.executor.annotation.sidecar.istio.io/inject=false \ #istio 환경에서 Initial Job Resource 부족 에러를 해결하기 위한 방법(driver-executor의 통신을 가능하게 함.)
--conf spark.executor.cores=1 \
--conf spark.executor.memory=700m \
--conf spark.worker.cores=1 \
--conf spark.driver.host=<이 spark-submit실행 host ip address> \
--conf spark.driver.port=7077 \
--jars elasticsearch-hadoop-7.6.1.jar \
--driver-memory 1g \
--packages org.apache.spark:spark-streaming-kafka-0-8-assembly_2.11:2.4.5 \
/Users/hikari/hanwharnd/ai_platform/spark-2.4.5-bin-hadoop2.7/examples/jars/spark-examples_2.11-2.4.5.jar

위와 같은 command를 수행시 아래 처럼 해당 namespace(data-platform)에서 spark용 Pod가 생성되는 것을 확인할 수 있습니다. 아래의 Pod는 spark-submit을 중지하면 expire됩니다.