Kubernetes 에서 Spark 돌려보기

쿠버네티스에서 스파크를 돌려볼까 한다.
kubernetes 는 좀 할줄 아는 사람, spark 완전 초보를 대상으로 글을 썼다.
내가 오늘 처음 Spark 를 돌려봤기에..
모든 bash command 는 spark 설치 루트 디렉토리 기준이다.

환경

로컬 : Mac, mojave 10.14
Kubernetes : 1.9, RBAC enabled
Spark : 2.4.0

일단 로컬 mac 에서 standalone 으로 돌려보기

mac 에 설치하기

brew install apache-spark

로 깔아도 되지만.. 이렇게 설치하면 테스트해볼 example 이 없다..
그래서 그냥 다운로드 페이지에서 tar 받아서 압축 푼다.

mac 에서 spark 예제 돌려보기

제일 간단하게 python pi 예제 돌려보는 커맨드
(결과가 log 사이에 섞여서 나온다.)

bin/spark-submit examples/src/main/python/pi.py

워드카운트 예제도 돌려본다.
(arguments를 받을 수 있다는걸 배웠다.)

bin/spark-submit examples/src/main/python/wordcount.py README.md

이제 kubernetes에서 클러스터로 돌려보기

그전에 이미지 빌드

kubernetes에서 spark 를 돌리려면, pods 를 생성할 base docker image 가 필요하다.
요렇게 해서 한번 만들어 보자

bin/docker-image-tool.sh build

docker images로 확인해보면 이미지가 세개 만들어져 있다.

REPOSITORY     TAG                  IMAGE ID            CREATED             SIZE
spark-r latest 76831d4bc63c 5 days ago 764MB
spark-py latest ec2d882c5f8a 5 days ago 438MB
spark latest 90cf7bdaee92 5 days ago 348MB

아 이미지가 개발 언어마다 다른가보다..
참고로 이 이미지를 만드는 dockerfile 은 여기 있다.

kubernetes/dockerfiles/spark

(spark-r 과 spark-py 용 dockerfile 은 그 아래 bindings 를 뒤져보면 각각 dockerfile 이 나온다.)

docker image 안에 필요한 파일을 다 넣고 이미지를 만들어야 한다.
application 도 이미지 안에 넣어두어야 하는데, 로컬에 있는 application 을 kubernetes 로 바로 전송하면서 실행하는 모드는 아직 없다고 한다.
(네트워크에서 접근 가능한 링크로 제공하는건 괜찮다고 한다.)

이렇게 만든 이미지는 kubernetes 가 pods 를 만들때 끌어다 쓸 수 있는 docker registry 에 올려 두자
나는 docker 커맨드를 사용했지만, docker-image-tool.sh 의 옵션으로도 제공한다.

bin/docker-image-tool.sh -r docker.io/myrepo -t v2.3.0 build
bin/docker-image-tool.sh -r docker.io/myrepo -t v2.3.0 push

-r 옵션으로 registry 를 지정하고
-t 옵션으로 tag 를 지정하자

RBAC 설정

알고보니 내가 쓰는 클러스터는 RBAC 가 enable 되어있었다.
일단 spark-submit 을 kubernetes 에다가 때리면, driver 라는 pod 가 생기고, 이놈이 다른 executor pods 를 만든다.

그런데 pod 주제에 다른 pods 를 만들려면 권한이 있어야 하는거다.
그래서 권한 셋팅을 한다.
(나는 어쩌다보니 namespace 까지 설정 해버렸다.. namespace 는 default 로 해도 되겠더라)

namespace.yml

kind: Namespace
apiVersion: v1
metadata:
name: spark
labels:
name: spark

serviceaccount.yml

kind: ServiceAccount
apiVersion: v1
metadata:
namespace: spark
name: spark

role.yml

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: spark
name: spark-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list", "create", "update", "patch", "delete"]

rolebinding.yml

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: spark-rolebinding
namespace: spark
subjects:
- kind: ServiceAccount
name: spark
roleRef:
kind: Role
name: spark-role
apiGroup: rbac.authorization.k8s.io

파일이 많아서 혼미한데, 이게 뭔소리냐면,

spark 네임스페이스 아래에서 이 모든 일이 일어날 것인데,
spark-rolebinding 에 적혀있기를,
spark 서비스 어카운트 님은
spark-role 롤을 가질 것이다.

진짜로 예제 돌리기

이렇게 셋팅을 하고 아래와 같이 예제를 돌린다

bin/spark-submit \
-—master k8s://https://KUBERNETES_MASTER_NODE:PORT \
--deploy-mode cluster \
--name spark-pi \
--class org.apache.spark.examples.SparkPi \
--conf spark.executor.instances=2 \
—-conf spark.kubernetes.namespace=spark \
—-conf spark.kubernetes.authenticate.driver.serviceAccountName=spark \
--conf spark.kubernetes.container.image=humbledude/spark \
local:///opt/spark/examples/jars/spark-examples_2.11-2.4.0.jar

local:// 부터는 docker image 안에서 application 의 위치를 지정해준다.
내 pc에 있는걸 바로 돌리는건 아직 안된다고 한다.

옵션은 이렇게 동작한다.

  • --master : 쿠버네티스 마스터 노드, k8s://로 시작하면 된다. (kubectl cluster-info 로 알수 있다)
  • --deploy-mode : cluster / client 모드가 있다.
    • cluster 모드는 쿠버네티스 상에 application 을 돌리기 위해 driver 와 executor 를 다 알아서 생성하고 정리하는 모드이다.
    • client 모드는 spark-shell 이나 notebook 처럼 interactive 모드로 작업하기 위한 모드라 한다. (별도 옵션으로 server / port 를 지정해 줘야 한다)
  • --name : 이름이다. pod 이름이 이거 기반으로 생성된다.
  • —-class : jar 파일 내 실행 클래스
  • —-conf spark.executor.instances : executor 갯수이다. 쿠버네티스 클러스터에서 감당 못하는 숫자를 넣으면 어떻게 되는지 아직 안해봤다.
  • —-conf spark.kubernetes.authenticate.driver.serviceAccountName : 위에서 만든 serveice account 를 넣는다. 이 account 가 적절한 권한이 있어야 한다.
  • —-conf spark.kubernetes.namespace : 위에서 만든 namespace 를 넣는다. namespace 를 따로 안만들고 default 로 했으면, 이 옵션이 필요가 없다.
  • —-conf spark.kubernetes.container.image : 위에서 만든 docker image 위치를 넣는다. 쿠버네티스에서 접근 가능한 위치에 image 가 있어야겠지?

python 도 돌려보자

spark-submit \
-—master k8s://https://KUBERNETES_MASTER_NODE:PORT \
--deploy-mode cluster \
--name spark-py-pi \
--conf spark.executor.instances=2
--conf spark.kubernetes.namespace=spark
--conf spark.kubernetes.authenticate.driver.serviceAccountName=spark \
--conf spark.kubernetes.container.image=humbledude/spark-py \
local:///opt/spark/examples/src/main/python/pi.py

별거 없고, image 만 교체하고, —-class 만 뺐다.
잘돈다.

결과는 kubectl logs PODS 으로 본다.
(example 이니까 결과가 로그에 나오는걸로..)

기타 삽질들..

삽질 1

얼마전엔 brew 로 spark 인스톨 했더니 2.3.2 가 깔리고,
image build 는 홈페이지에 받은 2.4.0 tar 파일 압축푼 디렉토리에서 했더니 application 을 돌릴수가 없었다.
2.3.2/ 2.4.0 두 버전간 호환이 안되니, 잘 맞춰서 하자

삽질 2

2.3.2 에서 python 돌릴라고 했더니 쿠버네티스에서는 python 안된다고 떴었다.
2.4.0 에서는 잘 돌았다.

참고

공식 문서

https://spark.apache.org/docs/latest/running-on-kubernetes.html

2.4.0 what’s new 블로그

https://databricks.com/blog/2018/09/26/whats-new-for-apache-spark-on-kubernetes-in-the-upcoming-apache-spark-2-4-release.html