Spark on Kubernetes の採用判断 — YARN / EMR との棲み分けと運用設計
Spark を Kubernetes で実行するときの構成要素 (Spark Operator / spark-submit)、既存の YARN / EMR との違い、リソース管理・ログ・メトリクスの運用設計、避けるべき罠。
Spark を Kubernetes で動かす意義
Apache Spark は大規模データ処理の定番フレームワーク。従来は Hadoop YARN や Mesos の上で動かすのが主流でしたが、Spark 2.3+ (2018 年) で Kubernetes が公式対応し、2.4+ で本番利用に耐える品質に達しました。
Kubernetes 上で動かすメリット:
- クラスタマネージャが Kubernetes に一元化 (別途 YARN 運用不要)
- コンテナイメージで依存関係を固定化、環境差分 0
- 既存の K8s エコシステム (Prometheus / Istio / ArgoCD) と統合
- クラウドネイティブ運用 (GKE / EKS / AKS のオートスケール活用)
デメリット:
- Kubernetes の学習コスト・運用負荷
- YARN と比較してエコシステムの歴史が浅い (Jupyter 統合等は YARN 側が先行していた)
他の実行環境との比較 (2024+)
| Spark on Kubernetes | Spark on YARN | AWS EMR | Databricks | |
|---|---|---|---|---|
| クラスタ管理 | K8s | Hadoop YARN | マネージド | フルマネージド |
| インフラ柔軟性 | 高 (任意クラウド) | オンプレ / クラウド | AWS のみ | AWS/Azure/GCP |
| 運用コスト | 中〜高 (自前) | 高 (YARN 専門知識) | 低 (マネージド) | 低 (フル) |
| コスト | 使用分だけ | 常時クラスタ | On-demand | プレミアム |
| MLOps 統合 | 自前 (MLflow 等) | 自前 | SageMaker 連携 | 標準搭載 |
選び方:
- 既に K8s 基盤がある企業 → Spark on K8s で統合
- データエンジニアだけで素早く始めたい → EMR か Databricks
- 大規模データサイエンス組織 → Databricks
- オンプレ要件 → Spark on K8s (自前) か YARN
デプロイ方式
A. spark-submit 直接
spark-submit \
--master k8s://https://<kubernetes-api>:443 \
--deploy-mode cluster \
--name my-job \
--class com.example.MyJob \
--conf spark.kubernetes.namespace=spark \
--conf spark.kubernetes.container.image=myrepo/spark:3.5.0 \
--conf spark.executor.instances=5 \
local:///opt/spark/examples/jars/my-app.jar
Spark 公式がサポートする素の方式。Driver / Executor が Pod として起動。
B. Spark Operator (推奨)
GoogleCloudPlatform/spark-on-k8s-operator で、Spark ジョブを K8s CRD として宣言。
apiVersion: sparkoperator.k8s.io/v1beta2
kind: SparkApplication
metadata:
name: my-job
namespace: spark
spec:
type: Scala
mode: cluster
image: "myrepo/spark:3.5.0"
mainClass: com.example.MyJob
mainApplicationFile: "local:///opt/spark/examples/jars/my-app.jar"
sparkVersion: "3.5.0"
driver:
cores: 1
memory: "2g"
serviceAccount: spark
executor:
cores: 2
instances: 5
memory: "4g"
Argo CD や Flux で GitOps 化しやすく、本番運用の定番構成。
運用設計のポイント
1. Executor の Dynamic Allocation
Spark 3.0+ は Dynamic Allocation on K8s をサポート。負荷に応じて Executor Pod 数を自動調整。
spark.dynamicAllocation.enabled=true
spark.dynamicAllocation.minExecutors=2
spark.dynamicAllocation.maxExecutors=50
spark.dynamicAllocation.executorIdleTimeout=60s
バッチジョブはコスト削減に直結。
2. ノード Taint / Tolerations でワークロード分離
Spark Executor を汎用ノードから隔離し、Spark 専用ノードプールに集約:
executor:
tolerations:
- key: dedicated
operator: Equal
value: spark
effect: NoSchedule
nodeSelector:
workload: spark
Spark ジョブで他サービスを巻き込まない。
3. ログ集約
Driver / Executor Pod の stdout は K8s ノードに書かれる。Fluentd / Fluent Bit で ELK / Loki に集約。Spark UI (spark.history.server) は別途 Spark History Server を立てる。
4. メトリクス
Spark の Prometheus Sink を有効化:
spark.metrics.conf.*.sink.prometheusServlet.class=org.apache.spark.metrics.sink.PrometheusServlet
spark.metrics.conf.*.sink.prometheusServlet.path=/metrics/prometheus
Pod の /metrics/prometheus エンドポイントを Prometheus でスクレイプ。
5. ストレージ
- HDFS は K8s と相性が悪い → S3 / GCS / Azure Blob を直接利用
- シャッフルファイル は Executor の emptyDir か、大規模なら専用 Shuffle Service
落とし穴
1. ノードリソースが足りず Pod Pending
Spark は要求リソース (CPU / メモリ) を Pod 定義に反映。ノードが足りないと Pending 状態で止まる。Cluster Autoscaler / Karpenter でノード自動追加設定を。
2. OOM Killed
Executor の memoryOverhead を見落とすとコンテナ OOM で kill される。JVM ヒープ + オフヒープ + K8s オーバーヘッドを考慮:
executor.memory = 4g
executor.memoryOverhead = 1g (JVM ヒープ以外の領域)
→ Pod requests.memory = 5g
3. Spark History Server のストレージ爆発
ジョブログ (event log) が S3 に貯まり続ける。ライフサイクルポリシーで古いものを自動削除。
4. Image Pull 問題
毎 Executor 起動時にコンテナイメージを pull すると遅い。ノード上にキャッシュ済みイメージを配布、または軽量イメージを用意。
5. Service Account / IAM
Executor Pod は KUBE API に触る必要がある。IRSA (EKS) や Workload Identity (GKE) で Pod にクラウド IAM を割り当て、S3 等への権限を安全に付与。
まとめ
- Spark on K8s は 既存 K8s 基盤がある企業に強い
- Spark Operator + Dynamic Allocation + ノード分離 が運用の標準
- マネージド (EMR / Databricks) と比較して 運用コスト vs コントロール のトレードオフ
- ログ・メトリクス・ストレージの設計を初期に決めないと後で苦労する
関連記事
- クラウド·
Concourse on Kubernetes 検証メモ — Helm 導入と本番運用で考えること
Concourse を Kubernetes 上にデプロイする構成メモ。Helm チャートでの立ち上げ手順、Worker ノードを DaemonSet で配置する設計、本番運用での留意点と 2024 年の現実解。
- クラウド·
Concourse CI アーキテクチャ解剖 — ATC / TSA / Worker はどう連携するか
Concourse の内部コンポーネント (ATC / TSA / Worker / Garden / Baggageclaim / PostgreSQL) の役割と通信フロー。YAML 駆動 + Docker Job の設計思想、2024 時点の立ち位置も含めて整理。
- クラウド·
Looker (Google Cloud) の設計思想 — LookML で BI を「コード化」する
Looker のモデル定義言語 LookML を中心に、他 BI ツールとの思想差、組織運用での使い所と落とし穴、Looker Studio との棲み分けまで。