쿠버네티스 실행 (Running on Kubernetes)

쿠버네티스 실행 (Running on Kubernetes)

  • Security
    • User Identity
    • Volume Mounts
  • Prerequisites
  • How it works
  • Submitting Applications to Kubernetes
    • Docker Images
    • Cluster Mode
    • Client Mode
      • Client Mode Networking
      • Client Mode Executor Pod Garbage Collection
      • Authentication Parameters
    • IPv4 and IPv6
    • Dependency Management
    • Secret Management
    • Pod Template
    • Using Kubernetes Volumes
      • PVC-oriented executor pod allocation
    • Local Storage
      • Using RAM for local storage
    • Introspection and Debugging
      • Accessing Logs
      • Accessing Driver UI
      • Debugging
    • Kubernetes Features
      • Configuration File
      • Contexts
      • Namespaces
      • RBAC
    • Spark Application Management
    • Future Work
  • Configuration
    • Spark Properties
    • Pod template properties

Spark는 Kubernetes가 관리하는 클러스터에서도 동작할 수 있어요. 이 기능은 Spark에 새로 추가된 네이티브 Kubernetes 스케줄러를 사용합니다.

Security

인증 같은 보안 기능은 기본적으로 켜져 있지 않아요. 인터넷이나 신뢰할 수 없는 네트워크에 열려 있는 클러스터를 배포할 때는, 승인되지 않은 애플리케이션이 클러스터에서 실행되는 걸 막기 위해 클러스터 접근을 보호하는 게 중요합니다. Spark를 실행하기 전에 Spark Security와 이 문서의 보안 관련 섹션을 꼭 읽어 주세요.

User Identity

프로젝트가 제공하는 Dockerfile로 빌드한 이미지에는 기본 UID가 185인 기본 USER 지시자가 들어 있어요. 즉 결과 이미지는 컨테이너 안에서 Spark 프로세스를 이 UID로 실행합니다. 보안을 중시하는 배포라면, 원하는 비특권 UID와 GID를 지정한 USER 지시자가 들어 있는 커스텀 이미지를 고려해 보세요. 결과 UID의 보조 그룹(supplementary groups)에 root 그룹이 포함되어야 Spark 실행 파일을 실행할 수 있습니다. 제공되는 docker-image-tool.sh 스크립트로 직접 이미지를 빌드하는 경우 -u <uid> 옵션으로 원하는 UID를 지정할 수 있어요.

또는 Pod Template 기능을 활용해 Spark가 제출하는 pod에 runAsUser가 들어 있는 Security Context를 추가할 수도 있습니다. 이렇게 하면 이미지에 있는 USER 지시자를 덮어쓸 수 있어요. 다만 이 방식은 사용자의 협조가 필요해서 공유 환경에는 적합하지 않을 수 있다는 점을 염두에 두세요. pod가 어떤 사용자로 실행될 수 있는지 제한하고 싶다면 클러스터 관리자는 Pod Security Admission Controller를 사용해야 합니다.

Volume Mounts

이 문서의 Using Kubernetes Volumes 섹션에서 설명하듯이, Spark on K8S는 특정 볼륨 타입을 driver와 executor pod에 마운트할 수 있게 해 주는 설정 옵션을 제공해요. 특히 hostPath 볼륨을 허용하는데, Kubernetes 문서에서 설명하듯 이 볼륨에는 알려진 보안 취약점이 있습니다.

클러스터 관리자는 Pod Security Admission Controller를 사용해 환경에 맞게 hostPath 볼륨을 마운트하는 능력을 제한해야 합니다.

Prerequisites

  • kubectl로 접근이 설정된, 버전 >= 1.34의 실행 중인 Kubernetes 클러스터. 아직 동작하는 Kubernetes 클러스터가 없다면 minikube로 로컬 머신에 테스트 클러스터를 구성할 수 있어요.
    • DNS 애드온을 켠 최신 minikube 릴리스를 권장합니다.
    • 기본 minikube 설정으로는 Spark 애플리케이션을 실행하기에 부족하다는 점을 알아 두세요. 단일 executor로 간단한 Spark 애플리케이션을 시작하려면 CPU 3개와 메모리 4g를 권장해요.
    • Spark 환경의 kubernetes-client 라이브러리 버전과, Kubernetes 클러스터 버전과의 호환성을 확인하세요.
  • 클러스터에서 pod를 나열·생성·편집·삭제할 수 있는 적절한 권한이 있어야 합니다. kubectl auth can-i <list|create|edit|delete> pods를 실행해 이런 리소스를 나열할 수 있는지 확인할 수 있어요.
    • driver pod가 사용하는 service account 자격 증명은 pod, service, configmap을 생성할 수 있어야 합니다.
  • 클러스터에 Kubernetes DNS가 설정되어 있어야 합니다.

How it works

spark-submit을 사용해 Spark 애플리케이션을 Kubernetes 클러스터에 직접 제출할 수 있어요. 제출 메커니즘은 다음과 같이 동작합니다.

  • Spark는 Kubernetes pod 안에서 실행되는 Spark driver를 생성해요.
  • driver는 역시 Kubernetes pod 안에서 실행되는 executor들을 생성하고, 여기에 연결해서 애플리케이션 코드를 실행합니다.
  • 애플리케이션이 완료되면 executor pod는 종료되고 정리되지만, driver pod는 로그를 유지하며 Kubernetes API에서 "completed" 상태로 남아 있다가 결국 가비지 컬렉션되거나 수동으로 정리됩니다.

completed 상태에서 driver pod는 어떤 컴퓨팅이나 메모리 리소스도 사용하지 않는다는 점을 알아 두세요.

driver와 executor pod의 스케줄링은 Kubernetes가 처리해요. Kubernetes API와의 통신은 fabric8을 통해 이루어집니다. 해당 설정 속성을 사용하면 node selector로 드라이버와 executor pod를 사용 가능한 노드의 일부에만 스케줄링할 수 있어요. node/pod affinity 같은 더 고급 스케줄링 힌트는 향후 릴리스에서 사용할 수 있을 예정입니다.

Submitting Applications to Kubernetes

Docker Images

Kubernetes는 사용자가 pod 안의 컨테이너에 배포할 이미지를 제공해야 해요. 이미지는 Kubernetes가 지원하는 컨테이너 런타임 환경에서 실행되도록 빌드됩니다. Docker는 Kubernetes와 자주 함께 쓰이는 컨테이너 런타임 환경이에요. Spark는(버전 2.3부터) 이 용도로 사용하거나 개별 애플리케이션의 요구에 맞게 커스터마이즈할 수 있는 Dockerfile을 함께 제공하며, kubernetes/dockerfiles/ 디렉터리에서 찾을 수 있습니다.

Spark는 또한 Kubernetes 백엔드에서 사용할 Docker 이미지를 빌드하고 게시하는 데 쓰는 bin/docker-image-tool.sh 스크립트도 함께 제공해요.

사용 예시는 아래와 같습니다.

$ ./bin/docker-image-tool.sh -r <repo> -t my-tag build
$ ./bin/docker-image-tool.sh -r <repo> -t my-tag push

이 명령은 프로젝트가 제공하는 기본 Dockerfiles로 빌드해요. 커스텀 Dockerfiles 제공을 포함해 이 도구의 동작을 커스터마이즈할 수 있는 더 많은 옵션을 보려면 -h 플래그로 실행하세요.

기본적으로 bin/docker-image-tool.sh는 JVM 잡을 실행하기 위한 docker 이미지를 빌드합니다. 추가 언어 바인딩 docker 이미지를 빌드하려면 옵트인해야 해요.

사용 예시는 아래와 같아요.

# 추가 PySpark docker 이미지 빌드
$ ./bin/docker-image-tool.sh -r <repo> -t my-tag -p ./kubernetes/dockerfiles/spark/bindings/python/Dockerfile build

# 추가 SparkR docker 이미지 빌드
$ ./bin/docker-image-tool.sh -r <repo> -t my-tag -R ./kubernetes/dockerfiles/spark/bindings/R/Dockerfile build

Apache Spark Docker 이미지(예: apache/spark:<version>)를 직접 사용할 수도 있습니다.

Cluster Mode

클러스터 모드로 Spark Pi를 실행하려면,

$ ./bin/spark-submit \
    --master k8s://https://<k8s-apiserver-host>:<k8s-apiserver-port> \
    --deploy-mode cluster \
    --name spark-pi \
    --class org.apache.spark.examples.SparkPi \
    --conf spark.executor.instances=5 \
    --conf spark.kubernetes.container.image=<spark-image> \
    local:///path/to/examples.jar

Spark master는 spark-submit--master 커맨드라인 인자로 넘기거나 애플리케이션 설정에서 spark.master로 지정하는데, 반드시 k8s://<api_server_host>:<k8s-apiserver-port> 형식의 URL이어야 해요. HTTPS 포트 443이어도 포트는 항상 지정해야 합니다. master 문자열 앞에 k8s://를 붙이면 Spark 애플리케이션이 Kubernetes 클러스터에서 실행되며, API 서버는 api_server_url로 접속합니다. URL에 HTTP 프로토콜을 지정하지 않으면 기본값은 https예요. 예를 들어 master를 k8s://example.com:443으로 설정하는 것은 k8s://https://example.com:443으로 설정하는 것과 같지만, TLS 없이 다른 포트로 연결하려면 master를 k8s://http://example.com:8080으로 설정해야 합니다.

Kubernetes 모드에서 spark.app.name이나 spark-submit--name 인자로 지정한 Spark 애플리케이션 이름은 기본적으로 driver와 executor처럼 생성되는 Kubernetes 리소스 이름에 사용됩니다. 따라서 애플리케이션 이름은 소문자 영숫자, -, .로만 구성되어야 하고 영숫자로 시작하고 끝나야 해요.

Kubernetes 클러스터가 설정되어 있다면 kubectl cluster-info를 실행해 apiserver URL을 알아낼 수 있습니다.

$ kubectl cluster-info
Kubernetes master is running at http://127.0.0.1:6443

위 예시에서 특정 Kubernetes 클러스터는 spark-submit 인자로 --master k8s://http://127.0.0.1:6443을 지정해 사용할 수 있어요. 또한 인증 프록시인 kubectl proxy를 사용해 Kubernetes API와 통신할 수도 있습니다.

로컬 프록시는 다음으로 시작할 수 있어요.

$ kubectl proxy

로컬 프록시가 localhost:8001에서 실행 중이라면 spark-submit 인자로 --master k8s://http://127.0.0.1:8001을 사용할 수 있어요. 마지막으로 위 예시에서 스킴이 local://인 특정 URI의 jar를 지정했는데, 이 URI는 이미 Docker 이미지 안에 있는 예시 jar의 위치입니다.

Client Mode

Spark 2.4.0부터 Kubernetes에서 클라이언트 모드로 Spark 애플리케이션을 실행할 수 있어요. 애플리케이션이 클라이언트 모드로 실행되면 driver는 pod 안이나 물리적 호스트에서 실행될 수 있습니다. 클라이언트 모드로 애플리케이션을 실행할 때는 다음 요소들을 고려하는 것이 좋아요.

Client Mode Networking

Spark executor는 Spark executor들에서 라우팅 가능한 호스트 이름과 포트로 Spark driver에 연결할 수 있어야 해요. 클라이언트 모드에서 Spark가 동작하려면 필요한 특정 네트워크 구성이 설정마다 달라집니다. driver를 Kubernetes pod 안에서 실행한다면 headless service를 사용해 driver pod가 안정적인 호스트 이름으로 executor들에서 라우팅되게 할 수 있어요. headless service를 배포할 때 service의 label selector가 driver pod만 정확히 일치시키고 다른 pod는 일치시키지 않도록 해야 합니다. driver pod에 충분히 고유한 label을 할당하고 headless service의 label selector에 그 label을 사용하는 걸 권장해요. driver의 호스트 이름은 spark.driver.host, Spark driver 포트는 spark.driver.port로 지정합니다.

Client Mode Executor Pod Garbage Collection

Spark driver를 pod 안에서 실행한다면 spark.kubernetes.driver.pod.name을 그 pod의 이름으로 설정하는 것이 좋습니다. 이 속성을 설정하면 Spark 스케줄러가 OwnerReference로 executor pod를 배포하는데, 이로 인해 driver pod가 클러스터에서 삭제되면 애플리케이션의 모든 executor pod도 함께 삭제됩니다. driver는 spark.kubernetes.namespace로 지정된 네임스페이스에서 주어진 이름의 pod를 찾고, 해당 pod를 가리키는 OwnerReference가 각 executor pod의 OwnerReferences 목록에 추가돼요. 실제 driver pod가 아닌 pod를 OwnerReference로 설정하지 않도록 주의하세요. 잘못된 pod가 삭제되면 executor가 조기에 종료될 수 있습니다.

애플리케이션이 pod 안에서 실행되지 않거나, pod 안에서 실행 중인데 spark.kubernetes.driver.pod.name이 설정되지 않은 경우에는 애플리케이션 종료 시 executor pod가 클러스터에서 제대로 삭제되지 않을 수 있다는 점을 기억하세요. Spark 스케줄러가 이 pod들을 삭제하려고 시도하지만, 어떤 이유로든 API 서버로의 네트워크 요청이 실패하면 이 pod들은 클러스터에 남아 있습니다. executor 프로세스는 driver에 연결할 수 없으면 종료되어야 하므로, 애플리케이션 종료 후 executor pod가 클러스터의 컴퓨팅 리소스(CPU와 메모리)를 소비하지는 않아야 합니다.

spark.kubernetes.executor.podNamePrefix를 사용하면 executor pod 이름을 완전히 제어할 수 있어요. 이 속성이 설정되면 같은 네임스페이스의 모든 잡에서 고유하도록 만드는 것이 좋습니다.

Authentication Parameters

클라이언트 모드에서는 Kubernetes 인증 파라미터에 정확히 spark.kubernetes.authenticate 접두사를 사용하세요.

IPv4 and IPv6

3.4.0부터 Spark는 IPv4/IPv6 dual-stack network 기능을 통해 IPv6 전용 환경도 추가로 지원해요. 이 기능은 Pod와 Service에 IPv4와 IPv6 주소를 모두 할당할 수 있게 해 줍니다. K8s 클러스터 능력에 따라 spark.kubernetes.driver.service.ipFamilyPolicySingleStack, PreferDualStack, RequireDualStack 중 하나가 될 수 있고, spark.kubernetes.driver.service.ipFamiliesIPv4, IPv6, IPv4,IPv6, IPv6,IPv4 중 하나가 될 수 있어요. 기본적으로 Spark는 spark.kubernetes.driver.service.ipFamilyPolicy=SingleStack, spark.kubernetes.driver.service.ipFamilies=IPv4를 사용합니다.

IPv6만 사용하려면 다음처럼 잡을 제출할 수 있어요.

...
    --conf spark.kubernetes.driver.service.ipFamilies=IPv6 \

DualStack 환경에서 IPv6를 사용하려면 JVM에는 java.net.preferIPv6Addresses=true, Python에는 SPARK_PREFER_IPV6=true가 추가로 필요할 수 있습니다.

Dependency Management

애플리케이션의 의존성이 모두 HDFS나 HTTP 서버 같은 원격 위치에 있다면 적절한 원격 URI로 참조할 수 있어요. 또한 애플리케이션 의존성을 커스텀 빌드한 Docker 이미지에 미리 마운트할 수도 있습니다. 이런 의존성은 local:// URI로 참조하거나 Dockerfile에서 SPARK_EXTRA_CLASSPATH 환경 변수를 설정해 클래스패스에 추가할 수 있어요. local:// 스킴은 커스텀 빌드한 Docker 이미지의 의존성을 spark-submit에서 참조할 때도 필요합니다. 제출 클라이언트의 로컬 파일시스템에서 온 의존성은 file:// 스킴이나 스킴 없이(전체 경로로) 지원하는데, 목적지는 Hadoop 호환 파일시스템이어야 합니다. S3를 사용하는 전형적인 예시는 다음 옵션을 넘기는 것입니다.

...
--packages org.apache.hadoop:hadoop-aws:3.4.1
--conf spark.kubernetes.file.upload.path=s3a://<s3-bucket>/path
--conf spark.hadoop.fs.s3a.access.key=...
--conf spark.hadoop.fs.s3a.impl=org.apache.hadoop.fs.s3a.S3AFileSystem
--conf spark.hadoop.fs.s3a.fast.upload=true
--conf spark.hadoop.fs.s3a.secret.key=....
--conf spark.driver.extraJavaOptions=-Divy.cache.dir=/tmp -Divy.home=/tmp
file:///full/path/to/app.jar

앱 jar 파일은 S3에 업로드된 후 driver가 실행될 때 driver pod로 다운로드되어 클래스패스에 추가됩니다. Spark는 병렬로 실행되는 Spark 앱과의 충돌을 피하기 위해 업로드 경로 아래에 임의의 이름을 가진 하위 디렉터리를 생성해요. 사용자는 자신의 필요에 따라 생성된 하위 디렉터리를 관리할 수 있습니다.

클라이언트 스킴은 애플리케이션 jar와 spark.jars, spark.files, spark.archives 속성으로 지정된 의존성에 대해 지원됩니다.

중요: 모든 클라이언트 측 의존성은 평면 디렉터리 구조로 주어진 경로에 업로드되므로 파일 이름이 고유해야 하며, 그렇지 않으면 파일이 덮어써집니다. 또한 파생된 k8s 이미지의 기본 ivy 디렉터리에 필요한 접근 권한이 있는지 확인하거나 위처럼 설정을 수정하세요. 클러스터 모드에서 --packages를 사용할 때도 후자가 중요해요.

Secret Management

Kubernetes Secrets을 사용해 Spark 애플리케이션이 보호된 서비스에 접근하기 위한 자격 증명을 제공할 수 있어요. 사용자가 지정한 secret을 driver 컨테이너에 마운트하려면 spark.kubernetes.driver.secrets.[SecretName]=<mount path> 형태의 설정 속성을 사용할 수 있습니다. 마찬가지로 spark.kubernetes.executor.secrets.[SecretName]=<mount path> 형태의 설정 속성으로 사용자 지정 secret을 executor 컨테이너에 마운트할 수 있어요. 마운트할 secret은 driver와 executor pod와 같은 네임스페이스에 있다고 가정합니다. 예를 들어 spark-secret이라는 secret을 driver와 executor 컨테이너 양쪽의 /etc/secrets 경로에 마운트하려면 spark-submit 명령에 다음 옵션을 추가하세요.

--conf spark.kubernetes.driver.secrets.spark-secret=/etc/secrets
--conf spark.kubernetes.executor.secrets.spark-secret=/etc/secrets

환경 변수를 통해 secret을 사용하려면 spark-submit 명령에 다음 옵션을 사용합니다.

--conf spark.kubernetes.driver.secretKeyRef.ENV_NAME=name:key
--conf spark.kubernetes.executor.secretKeyRef.ENV_NAME=name:key

Pod Template

Kubernetes는 template 파일로 pod를 정의할 수 있게 해 줍니다. Spark 사용자도 마찬가지로 template 파일을 사용해 Spark 설정이 지원하지 않는 driver나 executor pod 구성을 정의할 수 있어요. 그러려면 spark.kubernetes.driver.podTemplateFilespark.kubernetes.executor.podTemplateFile이라는 Spark 속성을 spark-submit 프로세스가 접근 가능한 파일을 가리키도록 지정하세요.

--conf spark.kubernetes.driver.podTemplateFile=s3a://bucket/driver.yml
--conf spark.kubernetes.executor.podTemplateFile=s3a://bucket/executor.yml

driver pod가 executor pod template 파일에 접근할 수 있도록, 파일은 driver pod가 생성될 때 볼륨에 자동으로 마운트됩니다. Spark는 이 template 파일을 역직렬화한 뒤 어떤 검증도 하지 않고 Kubernetes API 서버의 검증에 의존해요.

Spark는 특정 pod 구성에 대해 자기 의견(opinionated)이 있어서 pod template에 있는 값 중 Spark가 항상 덮어쓰는 값들이 있다는 점을 알아 두는 게 중요합니다. 따라서 이 기능을 쓸 때 pod template 파일을 지정한다는 것은, pod를 만드는 과정에서 Spark가 빈 pod 대신 template pod로 시작하게 한다는 뜻입니다. 자세한 내용은 Spark가 덮어쓸 pod template 값의 전체 목록을 확인하세요.

Pod template 파일은 여러 컨테이너를 정의할 수도 있어요. 그런 경우 spark.kubernetes.driver.podTemplateContainerNamespark.kubernetes.executor.podTemplateContainerName이라는 Spark 속성으로 driver나 executor의 기반으로 사용할 컨테이너를 지정할 수 있습니다. 지정하지 않거나 컨테이너 이름이 유효하지 않으면 Spark는 목록의 첫 번째 컨테이너를 driver나 executor 컨테이너로 간주해요.

Using Kubernetes Volumes

다음 유형의 Kubernetes volumes을 driver와 executor pod에 마운트할 수 있어요.

  • hostPath: 호스트 노드 파일시스템의 파일이나 디렉터리를 pod에 마운트합니다.
  • emptyDir: pod가 노드에 할당될 때 생성되는 처음에는 비어 있는 볼륨이에요.
  • nfs: 기존 NFS(Network File System)를 pod에 마운트합니다.
  • persistentVolumeClaim: PersistentVolume을 pod에 마운트해요. NB: 볼륨 마운트 관련 보안 문제는 이 문서의 Security 섹션을 확인하세요.

위 유형 중 어떤 볼륨이라도 driver pod에 마운트하려면 다음 설정 속성을 사용합니다.

--conf spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].mount.path=<mount path>
--conf spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].mount.readOnly=<true|false>
--conf spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].mount.subPath=<mount subPath>

구체적으로 VolumeTypehostPath, emptyDir, nfs, persistentVolumeClaim 중 하나가 될 수 있어요. VolumeName은 pod 스펙의 volumes 필드 아래에서 볼륨에 사용할 이름입니다.

지원되는 각 볼륨 유형은 특정 구성 옵션이 있을 수 있으며, 다음 형태의 설정 속성으로 지정할 수 있어요.

spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].options.[OptionName]=<value>

예를 들어 볼륨 이름 imagesnfs의 서버와 경로는 다음 속성으로 지정할 수 있습니다.

spark.kubernetes.driver.volumes.nfs.images.options.server=example.com
spark.kubernetes.driver.volumes.nfs.images.options.path=/data

그리고 볼륨 이름 checkpointpvcpersistentVolumeClaim의 claim 이름은 다음 속성으로 지정할 수 있어요.

spark.kubernetes.driver.volumes.persistentVolumeClaim.checkpointpvc.options.claimName=check-point-pvc-claim

executor pod에 볼륨을 마운트하는 설정 속성은 spark.kubernetes.driver. 대신 spark.kubernetes.executor. 접두사를 사용합니다.

예를 들어 claim 이름으로 OnDemand를, storageClasssizeLimit 옵션을 사용해 executor별로 동적으로 생성되는 persistent volume claim을 마운트할 수 있어요. 이는 Dynamic Allocation의 경우에 유용합니다.

spark.kubernetes.executor.volumes.persistentVolumeClaim.data.options.claimName=OnDemand
spark.kubernetes.executor.volumes.persistentVolumeClaim.data.options.storageClass=gp
spark.kubernetes.executor.volumes.persistentVolumeClaim.data.options.sizeLimit=500Gi
spark.kubernetes.executor.volumes.persistentVolumeClaim.data.mount.path=/data
spark.kubernetes.executor.volumes.persistentVolumeClaim.data.mount.readOnly=false

지원되는 각 볼륨 유형에 대해 사용 가능한 옵션의 전체 목록은 아래 Spark Properties 섹션을 참조하세요.

PVC-oriented executor pod allocation

디스크는 중요한 리소스 유형 중 하나라서 Spark driver는 일련의 설정으로 세밀한 제어를 제공해요. 예를 들어 기본적으로 온디맨드 PVC는 executor가 소유하며 PVC의 라이프사이클은 소유 executor와 밀접하게 연결됩니다. 하지만 온디맨드 PVC를 driver가 소유하고 Spark 잡 수명 동안 다른 executor들이 재사용하게 할 수도 있는데, 다음 옵션으로 설정합니다. 이렇게 하면 PVC 생성·삭제 오버헤드가 줄어듭니다.

spark.kubernetes.driver.ownPersistentVolumeClaim=true
spark.kubernetes.driver.reusePersistentVolumeClaim=true

추가로 Spark 3.4부터 Spark driver는 PVC 지향 executor 할당을 할 수 있어요. 즉 Spark가 잡이 가질 수 있는 생성된 총 PVC 수를 세고, driver가 최대 PVC 수를 소유하면 새 executor 생성을 보류합니다. 이는 기존 PVC를 한 executor에서 다른 executor로 전환하는 데 도움이 됩니다.

spark.kubernetes.driver.waitToReusePersistentVolumeClaim=true

Local Storage

Spark는 셔플이나 다른 연산 중 데이터를 디스크로 스필하는 데 볼륨을 사용하는 걸 지원해요. 볼륨을 로컬 스토리지로 사용하려면 볼륨 이름이 spark-local-dir-로 시작해야 합니다. 예를 들어,

--conf spark.kubernetes.driver.volumes.[VolumeType].spark-local-dir-[VolumeName].mount.path=<mount path>
--conf spark.kubernetes.driver.volumes.[VolumeType].spark-local-dir-[VolumeName].mount.readOnly=false

구체적으로 executor에서 큰 셔플과 정렬 연산이 필요한 잡이라면 persistent volume claim을 사용할 수 있어요.

spark.kubernetes.executor.volumes.persistentVolumeClaim.spark-local-dir-1.options.claimName=OnDemand
spark.kubernetes.executor.volumes.persistentVolumeClaim.spark-local-dir-1.options.storageClass=gp
spark.kubernetes.executor.volumes.persistentVolumeClaim.spark-local-dir-1.options.sizeLimit=500Gi
spark.kubernetes.executor.volumes.persistentVolumeClaim.spark-local-dir-1.mount.path=/data
spark.kubernetes.executor.volumes.persistentVolumeClaim.spark-local-dir-1.mount.readOnly=false

내장 KubernetesLocalDiskShuffleDataIO 플러그인으로 셔플 데이터 복구 기능을 켜려면 다음이 필요해요. spark.kubernetes.driver.waitToReusePersistentVolumeClaim을 추가로 켜고 싶을 수도 있습니다.

spark.kubernetes.executor.volumes.persistentVolumeClaim.spark-local-dir-1.mount.path=/data/spark-x/executor-x
spark.shuffle.sort.io.plugin.class=org.apache.spark.shuffle.KubernetesLocalDiskShuffleDataIO

local storage로 설정한 볼륨이 없으면 Spark는 셔플이나 다른 연산 중 데이터를 디스크로 스필할 때 임시 스크래치 공간을 사용해요. Kubernetes를 리소스 매니저로 사용할 때 pod는 spark.local.dir이나 환경 변수 SPARK_LOCAL_DIRS에 나열된 각 디렉터리에 마운트된 emptyDir 볼륨과 함께 생성됩니다. 디렉터리를 명시적으로 지정하지 않으면 기본 디렉터리가 생성되어 적절하게 설정돼요.

emptyDir 볼륨은 Kubernetes의 임시 스토리지 기능을 사용하며 pod 수명을 넘어 지속되지 않습니다.

Using RAM for local storage

emptyDir 볼륨은 기본적으로 임시 스토리지에 노드의 백킹 스토리지를 사용해요. 이 동작은 일부 컴퓨트 환경에는 적절하지 않을 수 있습니다. 예를 들어 네트워크에 원격 스토리지가 마운트된 디스크 없는 노드가 있다면, 많은 executor가 이 원격 스토리지에 IO를 하는 게 오히려 성능을 떨어뜨릴 수 있어요.

이런 경우 설정에서 spark.kubernetes.local.dirs.tmpfs=true로 지정하는 게 바람직할 수 있는데, 이러면 emptyDir 볼륨이 tmpfs, 즉 RAM 백킹 볼륨으로 설정됩니다. 이렇게 설정하면 Spark의 로컬 스토리지 사용량이 pod의 메모리 사용량에 포함되므로, spark.{driver,executor}.memoryOverheadFactor 값을 적절히 늘려 메모리 요청을 키우고 싶을 수 있어요.

Introspection and Debugging

실행 중이거나 완료된 Spark 애플리케이션을 조사하고 진행 상황을 모니터링하며 조치를 취할 수 있는 여러 방법이 있습니다.

Accessing Logs

로그는 Kubernetes API와 kubectl CLI를 사용해 접근할 수 있어요. Spark 애플리케이션 실행 중에는 다음으로 애플리케이션의 로그를 스트리밍할 수 있습니다.

$ kubectl -n=<namespace> logs -f <driver-pod-name>

동일한 로그는 클러스터에 설치되어 있다면 Kubernetes dashboard로도 접근할 수 있어요.

로그 수집 시스템이 있다면 Spark Driver의 Executors 탭 UI에 노출할 수 있습니다. 예를 들어,

spark.ui.custom.executor.log.url='https://log-server/log?appId=&execId='

이 URL 템플릿에 기존 executor 환경 변수 값으로 채워지는 추가 커스텀 변수를 넣을 수도 있어요. 예를 들어,

spark.executorEnv.SPARK_EXECUTOR_ATTRIBUTE_YOUR_VAR='$(EXISTING_EXECUTOR_ENV_VAR)'
spark.ui.custom.executor.log.url='https://log-server/log?appId=&execId=&your_var='

Accessing Driver UI

모든 애플리케이션과 연결된 UI는 kubectl port-forward를 사용해 로컬에서 접근할 수 있어요.

$ kubectl port-forward <driver-pod-name> 4040:4040

그러면 Spark driver UI를 http://localhost:4040에서 접근할 수 있습니다.

Apache Spark 4.0.0부터 Driver UI는 새 설정으로 driver 로그를 볼 수 있는 방법을 제공해요.

spark.driver.log.localDir=/tmp

그러면 Spark driver UI를 http://localhost:4040/logs/에서 접근할 수 있어요. 선택적으로 로그 레이아웃은 다음으로 설정합니다.

spark.driver.log.layout="%m%n%ex"

Debugging

여러 종류의 실패가 있을 수 있어요. Kubernetes API 서버가 spark-submit이 보낸 요청을 거부하거나 다른 이유로 연결이 거부되면 제출 로직이 만난 오류를 알려줄 것입니다. 하지만 애플리케이션 실행 중 오류가 발생한다면, 가장 좋은 조사 방법은 종종 Kubernetes CLI를 통하는 것이에요.

driver pod를 둘러싼 스케줄링 결정에 대한 기본 정보를 얻으려면 다음을 실행할 수 있습니다.

$ kubectl describe pod <spark-driver-pod>

pod에 런타임 오류가 발생했다면 다음으로 상태를 더 조사할 수 있어요.

$ kubectl logs <spark-driver-pod>

실패한 executor pod의 상태와 로그도 비슷한 방식으로 확인할 수 있습니다. 마지막으로 driver pod를 삭제하면 모든 executor, 관련 service 등을 포함한 전체 spark 애플리케이션이 정리됩니다. driver pod는 Spark 애플리케이션의 Kubernetes 표현으로 생각할 수 있어요.

Kubernetes Features

Configuration File

Kubernetes 구성 파일은 보통 홈 디렉터리의 .kube/configKUBECONFIG 환경 변수로 지정된 위치에 있어요. Spark on Kubernetes는 이 파일을 사용해 Kubernetes 클러스터와 상호작용하는 데 쓰는 Kubernetes 클라이언트의 초기 자동 구성을 시도합니다. 대체 인증 방법 사용 등 클라이언트 구성을 더 커스터마이즈할 수 있는 다양한 Spark 설정 속성이 제공됩니다.

Contexts

Kubernetes 구성 파일은 서로 다른 클러스터와/또는 사용자 신원 간 전환을 허용하는 여러 context를 포함할 수 있어요. 기본적으로 Spark on Kubernetes는 Kubernetes 클라이언트의 초기 자동 구성 시 현재 context( kubectl config current-context로 확인 가능)를 사용합니다.

대체 context를 사용하려면 Spark 설정 속성 spark.kubernetes.context로 원하는 context를 지정할 수 있어요. 예: spark.kubernetes.context=minikube.

Namespaces

Kubernetes에는 namespaces 개념이 있어요. Namespace는 (리소스 쿼터를 통해) 여러 사용자 간에 클러스터 리소스를 나누는 방법입니다. Spark on Kubernetes는 namespace를 사용해 Spark 애플리케이션을 실행할 수 있어요. 이는 spark.kubernetes.namespace 설정을 통해 사용할 수 있습니다.

Kubernetes는 ResourceQuota로 개별 namespace의 리소스, 객체 수 등에 제한을 걸 수 있게 해 줍니다. 관리자는 namespace와 ResourceQuota를 조합해 Spark 애플리케이션을 실행하는 Kubernetes 클러스터에서 공유와 리소스 할당을 제어할 수 있어요.

RBAC

RBAC가 활성화된 Kubernetes 클러스터에서 사용자는 Kubernetes API 서버에 접근하기 위해 다양한 Spark on Kubernetes 구성 요소가 사용하는 Kubernetes RBAC 역할과 service account를 구성할 수 있습니다.

Spark driver pod는 Kubernetes API 서버에 접근해 executor pod를 생성하고 감시하기 위해 Kubernetes service account를 사용해요. driver pod가 사용하는 service account는 driver가 작업을 수행할 수 있는 적절한 권한이 있어야 합니다. 구체적으로 최소한 service account에는 driver pod가 pod와 service를 생성할 수 있게 하는 Role 또는 ClusterRole이 부여되어야 해요. 기본적으로 pod 생성 시 service account를 지정하지 않으면 driver pod에는 spark.kubernetes.namespace로 지정된 네임스페이스의 default service account가 자동으로 할당됩니다.

배포된 Kubernetes의 버전과 설정에 따라 이 default service account는 기본 Kubernetes RBAC 정책 아래에서 driver pod가 pod와 service를 생성할 수 있게 하는 역할을 가질 수도 있고 없을 수도 있어요. 때로는 올바른 역할이 부여된 커스텀 service account를 지정해야 할 수도 있습니다. Spark on Kubernetes는 spark.kubernetes.authenticate.driver.serviceAccountName=<service account name> 설정 속성으로 driver pod가 사용할 커스텀 service account를 지정할 수 있게 해 줍니다. 예를 들어 driver pod가 spark service account를 사용하게 하려면 spark-submit 명령에 다음 옵션을 추가하기만 하면 됩니다.

--conf spark.kubernetes.authenticate.driver.serviceAccountName=spark

커스텀 service account를 만들려면 kubectl create serviceaccount 명령을 사용할 수 있어요. 예를 들어 다음 명령은 spark라는 service account를 만듭니다.

$ kubectl create serviceaccount spark

service account에 Role이나 ClusterRole을 부여하려면 RoleBinding이나 ClusterRoleBinding이 필요합니다. RoleBinding이나 ClusterRoleBinding을 만들려면 kubectl create rolebinding(ClusterRoleBinding에는 clusterrolebinding) 명령을 사용할 수 있어요. 예를 들어 다음 명령은 default 네임스페이스에서 edit ClusterRole을 만들고 위에서 만든 spark service account에 부여합니다.

$ kubectl create clusterrolebinding spark-role --clusterrole=edit --serviceaccount=default:spark --namespace=default

Role은 단일 네임스페이스 안의 리소스(예: pod)에만 접근 권한을 부여할 수 있는 반면, ClusterRole은 모든 네임스페이스의 클러스터 범위 리소스(예: 노드)와 namespace 범위 리소스(예: pod) 모두에 접근 권한을 부여할 수 있다는 점을 알아 두세요. Spark on Kubernetes에서는 driver가 항상 같은 네임스페이스에 executor pod를 만들기 때문에 Role이면 충분하지만, 사용자는 ClusterRole을 대신 사용할 수도 있어요. RBAC 권한 부여와 pod용 Kubernetes service account 구성에 대한 자세한 내용은 Using RBAC AuthorizationConfigure Service Accounts for Pods를 참조하세요.

Spark Application Management

Kubernetes는 클러스터 모드에서 spark-submit CLI 도구를 통한 간단한 애플리케이션 관리 기능을 제공해요. 사용자는 잡을 제출할 때 출력되는 제출 ID를 제공해 잡을 종료할 수 있습니다. 제출 ID는 namespace:driver-pod-name 형식을 따릅니다. 사용자가 namespace를 생략하면 현재 k8s context에 설정된 namespace가 사용돼요. 예를 들어 kubectl config set-context minikube --namespace=spark처럼 특정 namespace를 설정했다면 기본적으로 spark namespace가 사용됩니다. 반면 특정 context에 namespace가 없으면 기본적으로 모든 namespace가 고려돼요. 즉 namespace와 관계없이 주어진 제출 ID와 일치하는 모든 Spark 애플리케이션에 연산이 영향을 미칩니다. 또한 애플리케이션 관리를 위한 spark-submit은 driver를 제출할 때 쓰는 것과 같은 백엔드 코드를 사용하므로 spark.kubernetes.context 등과 같은 속성을 재사용할 수 있어요.

예를 들어,

$ spark-submit --kill spark:spark-pi-1547948636094-driver --master k8s://https://192.168.2.8:8443

사용자는 --status 플래그로 애플리케이션 상태를 나열할 수도 있습니다.

$ spark-submit --status spark:spark-pi-1547948636094-driver --master  k8s://https://192.168.2.8:8443

두 연산 모두 glob 패턴을 지원해요. 예를 들어 사용자는 다음을 실행할 수 있습니다.

$ spark-submit --kill spark:spark-pi* --master  k8s://https://192.168.2.8:8443

위 명령은 특정 접두사가 붙은 모든 애플리케이션을 종료합니다.

사용자는 spark.kubernetes.appKillPodDeletionGracePeriod 속성으로 pod 종료의 유예 기간(grace period)을 지정할 수 있어요. 이 값을 --conf로 제공합니다(모든 K8s pod의 기본값은 30초).

Future Work

현재 작업 중이거나 작업할 예정인 몇 가지 Spark on Kubernetes 기능이 있어요. 이런 기능들은 향후 버전의 spark-kubernetes 통합에 결국 포함될 것으로 예상됩니다.

그중 일부는 다음과 같아요.

  • External Shuffle Service(외부 셔플 서비스)
  • Job Queues and Resource Management(잡 큐와 리소스 관리)

Configuration

Spark 설정에 대한 정보는 configuration 페이지를 참조하세요. 아래 설정은 Spark on Kubernetes에 특화된 것들입니다.

Spark Properties

Property Name Default Meaning Since Version
spark.kubernetes.context (none) 사용자 Kubernetes 구성 파일의 context로, Kubernetes 클라이언트 라이브러리의 초기 자동 구성에 사용된다. 지정하지 않으면 사용자의 현재 context가 사용된다. NB: 자동 구성된 설정 중 상당수는 spark.kubernetes.namespace 같은 다른 Spark 설정 속성으로 덮어쓸 수 있다. 3.0.0
spark.kubernetes.driver.master https://kubernetes.default.svc driver가 executor를 요청할 때 사용하는 내부 Kubernetes master(API 서버) 주소. 또는 driver-pod-only 모드의 local[*]. 3.0.0
spark.kubernetes.namespace default driver와 executor pod를 실행하는 데 사용할 namespace. 2.3.0
spark.kubernetes.container.image (none) Spark 애플리케이션에 사용할 컨테이너 이미지. 보통 example.com/repo/spark:v1.0.0 형태. 각 컨테이너 유형별로 명시적 이미지가 제공되지 않는 한 필수이며 사용자가 제공해야 한다. 참고: ``은 현재 Spark 버전으로 대체되는 내장 변수다. 2.3.0
spark.kubernetes.driver.container.image (value of spark.kubernetes.container.image) driver에 사용할 커스텀 컨테이너 이미지. 참고: ``은 현재 Spark 버전으로 대체되는 내장 변수다. 2.3.0
spark.kubernetes.executor.container.image (value of spark.kubernetes.container.image) executor에 사용할 커스텀 컨테이너 이미지. 참고: ``은 현재 Spark 버전으로 대체되는 내장 변수다. 2.3.0
spark.kubernetes.container.image.pullPolicy IfNotPresent Kubernetes 내에서 이미지를 가져올 때 사용하는 컨테이너 이미지 pull 정책. 유효한 값은 Always, Never, IfNotPresent. 2.3.0
spark.kubernetes.container.image.pullSecrets `` 비공개 이미지 레지스트리에서 이미지를 가져오는 데 사용하는 쿠버네티스 secret의 쉼표로 구분된 목록. 2.4.0
spark.kubernetes.allocation.batch.size 20 각 라운드의 executor pod 할당에서 한 번에 실행할 pod 수. 2.3.0
spark.kubernetes.allocation.batch.delay 1s 각 라운드의 executor pod 할당 사이 대기 시간. 1초 미만 값은 spark driver의 과도한 CPU 사용을 유발할 수 있다. 2.3.0
spark.kubernetes.allocation.maximum Int.MaxValue 전체 잡 라이프사이클 동안 생성하려고 시도할 최대 executor pod 수. 4.1.0
spark.kubernetes.allocation.recoveryMode.enabled (none) Spark driver가 OOM으로 인한 executor 종료를 감지하면, recovery-mode executor를 할당하기 시작한다. 이 executor는 executor JVM당 단일 태스크만 받는다. 즉 recovery-mode executor는 OOM으로 종료된 executor를 대체해 리소스를 많이 먹는 태스크로부터 나머지 태스크·스테이지를 살려낸다. false로 설정하면 Spark는 recovery-mode executor를 사용하지 않는다. 4.2.0
spark.kubernetes.jars.avoidDownloadSchemes (none) executor에 분배되기 전에 driver 로컬 디스크로 다운로드되지 않을 jar 스킴의 쉼표 구분 목록(kubernetes 배포 전용). jar가 크고 executor 수가 많을 때 사용한다. 동시 다운로드가 네트워크 포화와 타임아웃을 유발할 수 있기 때문. 와일드카드 *는 어떤 스킴에 대해서도 jar를 다운로드하지 않음을 나타낸다. 4.0.0
spark.kubernetes.authenticate.submission.caCertFile (none) driver를 시작할 때 TLS로 Kubernetes API 서버에 연결하는 데 사용하는 CA cert 파일 경로. 이 파일은 제출 머신의 디스크에 있어야 한다. URI가 아닌 경로로 지정(즉 스킴을 제공하지 말 것). 클라이언트 모드에서는 spark.kubernetes.authenticate.caCertFile을 사용한다. 2.3.0
spark.kubernetes.authenticate.submission.clientKeyFile (none) driver를 시작할 때 Kubernetes API 서버에 인증하는 데 사용하는 client key 파일 경로. 이 파일은 제출 머신의 디스크에 있어야 한다. URI가 아닌 경로로 지정. 클라이언트 모드에서는 spark.kubernetes.authenticate.clientKeyFile을 사용한다. 2.3.0
spark.kubernetes.authenticate.submission.clientCertFile (none) driver를 시작할 때 Kubernetes API 서버에 인증하는 데 사용하는 client cert 파일 경로. 이 파일은 제출 머신의 디스크에 있어야 한다. URI가 아닌 경로로 지정. 클라이언트 모드에서는 spark.kubernetes.authenticate.clientCertFile을 사용한다. 2.3.0
spark.kubernetes.authenticate.submission.oauthToken (none) driver를 시작할 때 Kubernetes API 서버에 인증하는 데 사용할 OAuth 토큰. 다른 인증 옵션과 달리 인증에 사용할 토큰의 정확한 문자열 값이어야 한다. 클라이언트 모드에서는 spark.kubernetes.authenticate.oauthToken을 사용한다. 2.3.0
spark.kubernetes.authenticate.submission.oauthTokenFile (none) driver를 시작할 때 Kubernetes API 서버에 인증하는 데 사용할 토큰이 들어 있는 OAuth 토큰 파일 경로. 이 파일은 제출 머신의 디스크에 있어야 한다. URI가 아닌 경로로 지정. 클라이언트 모드에서는 spark.kubernetes.authenticate.oauthTokenFile을 사용한다. 2.3.0
spark.kubernetes.authenticate.driver.caCertFile (none) executor를 요청할 때 driver pod에서 TLS로 Kubernetes API 서버에 연결하는 데 사용하는 CA cert 파일 경로. 이 파일은 제출 머신의 디스크에 있어야 하며 driver pod에 업로드된다. URI가 아닌 경로로 지정. 클라이언트 모드에서는 spark.kubernetes.authenticate.caCertFile을 사용한다. 2.3.0
spark.kubernetes.authenticate.driver.clientKeyFile (none) executor를 요청할 때 driver pod에서 Kubernetes API 서버에 인증하는 데 사용하는 client key 파일 경로. 이 파일은 제출 머신의 디스크에 있어야 하며 Kubernetes secret으로 driver pod에 업로드된다. URI가 아닌 경로로 지정. 클라이언트 모드에서는 spark.kubernetes.authenticate.clientKeyFile을 사용한다. 2.3.0
spark.kubernetes.authenticate.driver.clientCertFile (none) executor를 요청할 때 driver pod에서 Kubernetes API 서버에 인증하는 데 사용하는 client cert 파일 경로. 이 파일은 제출 머신의 디스크에 있어야 하며 Kubernetes secret으로 driver pod에 업로드된다. URI가 아닌 경로로 지정. 클라이언트 모드에서는 spark.kubernetes.authenticate.clientCertFile을 사용한다. 2.3.0
spark.kubernetes.authenticate.driver.oauthToken (none) executor를 요청할 때 driver pod에서 Kubernetes API 서버에 인증하는 데 사용할 OAuth 토큰. 다른 인증 옵션과 달리 인증에 사용할 토큰의 정확한 문자열 값이어야 한다. 이 토큰 값은 Kubernetes secret으로 driver pod에 업로드된다. 클라이언트 모드에서는 spark.kubernetes.authenticate.oauthToken을 사용한다. 2.3.0
spark.kubernetes.authenticate.driver.oauthTokenFile (none) executor를 요청할 때 driver pod에서 Kubernetes API 서버에 인증하는 데 사용할 인증 토큰이 들어 있는 OAuth 토큰 파일 경로. 다른 인증 옵션과 달리 이 파일은 인증에 사용할 토큰의 정확한 문자열 값을 포함해야 한다. 이 토큰 값은 secret으로 driver pod에 업로드된다. 클라이언트 모드에서는 spark.kubernetes.authenticate.oauthTokenFile을 사용한다. 2.3.0
spark.kubernetes.authenticate.driver.mounted.caCertFile (none) executor를 요청할 때 driver pod에서 TLS로 Kubernetes API 서버에 연결하는 데 사용하는 CA cert 파일 경로. 이 경로는 driver pod에서 접근 가능해야 한다. URI가 아닌 경로로 지정. 클라이언트 모드에서는 spark.kubernetes.authenticate.caCertFile을 사용한다. 2.3.0
spark.kubernetes.authenticate.driver.mounted.clientKeyFile (none) executor를 요청할 때 driver pod에서 Kubernetes API 서버에 인증하는 데 사용하는 client key 파일 경로. 이 경로는 driver pod에서 접근 가능해야 한다. URI가 아닌 경로로 지정. 클라이언트 모드에서는 spark.kubernetes.authenticate.clientKeyFile을 사용한다. 2.3.0
spark.kubernetes.authenticate.driver.mounted.clientCertFile (none) executor를 요청할 때 driver pod에서 Kubernetes API 서버에 인증하는 데 사용하는 client cert 파일 경로. 이 경로는 driver pod에서 접근 가능해야 한다. URI가 아닌 경로로 지정. 클라이언트 모드에서는 spark.kubernetes.authenticate.clientCertFile을 사용한다. 2.3.0
spark.kubernetes.authenticate.driver.mounted.oauthTokenFile (none) executor를 요청할 때 driver pod에서 Kubernetes API 서버에 인증하는 데 사용할 OAuth 토큰이 들어 있는 파일 경로. 이 경로는 driver pod에서 접근 가능해야 한다. 다른 인증 옵션과 달리 이 파일은 인증에 사용할 토큰의 정확한 문자열 값을 포함해야 한다. 클라이언트 모드에서는 spark.kubernetes.authenticate.oauthTokenFile을 사용한다. 2.3.0
spark.kubernetes.authenticate.driver.serviceAccountName default driver pod를 실행할 때 사용하는 service account. driver pod는 API 서버에 executor pod를 요청할 때 이 service account를 사용한다. CA cert 파일, client key 파일, client cert 파일, 및/또는 OAuth 토큰과 함께 지정할 수 없다. 클라이언트 모드에서는 spark.kubernetes.authenticate.serviceAccountName을 사용한다. 2.3.0
spark.kubernetes.authenticate.executor.serviceAccountName (value of spark.kubernetes.authenticate.driver.serviceAccountName) executor pod를 실행할 때 사용하는 service account. 이 파라미터가 설정되지 않으면 폴백 논리가 driver의 service account를 사용한다. 3.1.0
spark.kubernetes.authenticate.caCertFile (none) 클라이언트 모드에서 executor를 요청할 때 TLS로 Kubernetes API 서버에 연결하는 데 사용하는 CA cert 파일 경로. URI가 아닌 경로로 지정(즉 스킴을 제공하지 말 것). 2.4.0
spark.kubernetes.authenticate.clientKeyFile (none) 클라이언트 모드에서 executor를 요청할 때 Kubernetes API 서버에 인증하는 데 사용하는 client key 파일 경로. URI가 아닌 경로로 지정. 2.4.0
spark.kubernetes.authenticate.clientCertFile (none) 클라이언트 모드에서 executor를 요청할 때 Kubernetes API 서버에 인증하는 데 사용하는 client cert 파일 경로. URI가 아닌 경로로 지정. 2.4.0
spark.kubernetes.authenticate.oauthToken (none) 클라이언트 모드에서 executor를 요청할 때 Kubernetes API 서버에 인증하는 데 사용할 OAuth 토큰. 다른 인증 옵션과 달리 인증에 사용할 토큰의 정확한 문자열 값이어야 한다. 2.4.0
spark.kubernetes.authenticate.oauthTokenFile (none) 클라이언트 모드에서 executor를 요청할 때 Kubernetes API 서버에 인증하는 데 사용할 OAuth 토큰이 들어 있는 파일 경로. 2.4.0
spark.kubernetes.driver.label.[LabelName] (none) LabelName이 지정하는 label을 driver pod에 추가한다. 예: spark.kubernetes.driver.label.something=true. Spark는 정리(bookkeeping) 목적으로 driver pod에 자체 label도 추가한다는 점에 주의. 2.3.0
spark.kubernetes.driver.annotation.[AnnotationName] (none) AnnotationName이 지정하는 Kubernetes annotation을 driver pod에 추가한다. 예: spark.kubernetes.driver.annotation.something=true. 2.3.0
spark.kubernetes.driver.service.label.[LabelName] (none) LabelName이 지정하는 Kubernetes label을 driver service에 추가한다. 예: spark.kubernetes.driver.service.label.something=true. Spark는 정리 목적으로 driver service에 자체 label도 추가한다는 점에 주의. 3.4.0
spark.kubernetes.driver.service.annotation.[AnnotationName] (none) AnnotationName이 지정하는 Kubernetes annotation을 driver service에 추가한다. 3.4.0

Pod template properties

아래 표는 Spark가 덮어쓸 pod 스펙 값의 전체 목록입니다.

Pod Metadata

| Pod metadata key | Modified value | Description | | labels | spark.kubernetes.{driver,executor}.label.*의 label 추가 | Spark는 spark 설정으로 지정한 추가 label을 추가한다. | | annotations | spark.kubernetes.{driver,executor}.annotation.*의 annotation 추가 | Spark는 spark 설정으로 지정한 추가 annotation을 추가한다. |

Pod Spec

| Pod spec key | Modified value | Description | | serviceAccount | spark.kubernetes.authenticate.driver.serviceAccountName 값 | Spark는 driver에 대해서만 serviceAccount를 spark 설정 값으로 덮어쓴다. |

| Pod spec key | Modified value | Description | | serviceAccountName | spark.kubernetes.authenticate.driver.serviceAccountName 값 | Spark는 driver에 대해서만 serviceAccountName을 spark 설정 값으로 덮어쓴다. |

Container spec

| image | spark.kubernetes.{driver,executor}.container.image 값 | 이미지는 spark 설정으로 정의된다. | | imagePullPolicy | spark.kubernetes.container.image.pullPolicy 값 | Spark는 driver와 executor 양쪽의 pull 정책을 덮어쓴다. | | 기타 리소스 한도 | spark.{driver,executor}.resources.{resourceName}.* 설정 | — |

Resource Allocation and Configuration Overview

configuration 페이지의 Custom Resource Scheduling and Configuration Overview 섹션을 꼭 읽어 두세요. 이 섹션은 리소스 스케줄링의 Kubernetes 특화 측면만 다룹니다.

참고와 예시로, GPU 스케줄링에 관한 Kubernetes 문서를 볼 수 있어요. Spark는 리소스 한도 설정만 지원합니다.

Resource Level Scheduling Overview

Using Volcano as Customized Scheduler for Spark on Kubernetes

Build

Downloads 페이지에서 배포하는 것처럼 Volcano 지원이 포함된 Spark 배포판을 만들려면, "Building Spark"도 더 참조하세요.

Usage
# driver/executor VolcanoFeatureStep 지정
--conf spark.kubernetes.driver.pod.featureSteps=org.apache.spark.deploy.k8s.features.VolcanoFeatureStep
--conf spark.kubernetes.executor.pod.featureSteps=org.apache.spark.deploy.k8s.features.VolcanoFeatureStep
Volcano Feature Step

Volcano feature step은 사용자가 Volcano PodGroup을 만들고 driver/executor pod annotation을 설정해 이 PodGroup과 연결하게 도와줍니다. 현재 Volcano Feature Step에서는 driver/job 수준 PodGroup만 지원된다는 점을 알아 두세요.

Using Apache YuniKorn as Customized Scheduler for Spark on Kubernetes

Get started
--conf spark.kubernetes.scheduler.name=yunikorn
--conf spark.kubernetes.driver.label.queue=root.default
--conf spark.kubernetes.executor.label.queue=root.default
--conf spark.kubernetes.driver.annotation.yunikorn.apache.org/app-id={{APP_ID}}
--conf spark.kubernetes.executor.annotation.yunikorn.apache.org/app-id={{APP_ID}}

{{APP_ID}}는 Spark 잡 ID로 자동 대체되는 내장 변수입니다. 위 구성으로 잡은 기본 Kubernetes 스케줄러 대신 YuniKorn 스케줄러가 스케줄링합니다.

Stage Level Scheduling Overview

Kubernetes에서 dynamic allocation은 셔플 추적 기능을 요구하므로, 이전 스테이지에서 다른 ResourceProfile을 사용한 executor는 그 위에 셔플 데이터가 있어 idle timeout이 발생하지 않을 수 있다는 점에 유의하세요.