Dockerでapache Sparkのローカル学習環境を用意する

個人開発したアプリの宣伝
目的地が設定できる手帳のような使い心地のTODOアプリを公開しています。
Todo with Location

Todo with Location

  • Yoshiko Ichikawa
  • Productivity
  • Free

スポンサードリンク

最近、Hadoop周りの学習を始めて、Sparkをもと思いこちらの書籍を購入。学習環境を構築しました。

こちらの書籍のSparkは1系で、バージョンが古いので都度互換を吸収する必要があります。


コンテナの作成

以下はDockerのプロファイル。殆どQiitaから拾ってきたんだけど、spark-submitでscalaプログラムを動かすにはscalaのビルド環境が必要になるので、sbtも併せて含めておく。

Dockerfile

FROM openjdk:8

ARG SPARK_VERSION=2.4.6
ARG HADOOP_VERSION=2.7

RUN echo "deb https://dl.bintray.com/sbt/debian /" | tee -a /etc/apt/sources.list.d/sbt.list
RUN curl -sL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823" | sudo apt-key add
RUN apt-get update \
    && apt-get install sbt

RUN wget -q http://ftp.meisei-u.ac.jp/mirror/apache/dist/spark/spark-${SPARK_VERSION}/spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}.tgz
RUN tar xzf spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}.tgz \
    && mv spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION} /spark \
    && rm spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}.tgz

EXPOSE 8080


docker-compose

version: '3'

services:
  master:
    build: .
    ports:
      - 4040:4040
      - 8080:8080
    volumes: 
      - .:/spark/work
    command: /spark/bin/spark-class org.apache.spark.deploy.master.Master --host 0.0.0.0

  worker:
    build: .
    depends_on:
      - master
    ports:
      - 8081-8089:8081
    command: /spark/bin/spark-class org.apache.spark.deploy.worker.Worker spark://master:7077 --host 0.0.0.0


コンテナの起動

$ docker-compose up -d

上記で、docker exec -it containerID bashなんかして、/spark/bin/spark-shellなんかするとインタラクティブシェルでSparkを扱うことができる。


スタンドアロンアプリケーションの構築

インタラクティブシェルでなく、ScalaやJava、Python等のプログラムからSparkを利用ことをスタンドアロンアプリケーションと呼ぶらしい。利用するアプリケーションのコードは GitHub - databricks/learning-spark: Example code from Learning Spark book 書籍のコードが公開されているので、こちらをforkしてDockerにマウントしてあるパスに配置しておいた。

以下はDockerコンテナにログインしておいて作業します。


配置したgithubのコード、mini-complete-example/というアプリケーションに移動して、書籍通り以下を実行する。

$ sbt clean package
$ /spark/bin/spark-submit \
 --class com.oreilly.learningsparkexamples.mini.scala.WordCount \
 ./target/scala-2.10/learning-spark-mini-example_2.10-0.0.1.jar \
 ./README.md ./wordcounts

ビルドは成功するんだけど、以下のようなエラーが出て、ランタイムエラーが出る。

Exception in thread "main" java.lang.NoSuchMethodError: org.apache.spark.SparkContext$.rddToPairRDDFunctions(Lorg/apache/spark/rdd/RDD;Lscala/reflect/ClassTag;Lscala/reflect/ClassTag;Lscala/math/Ordering;)Lorg/apache/spark/rdd/PairRDDFunctions;

これは、ビルドしたScalaのバージョンとランタイム(この場合Sparkが実行するScalaのバージョン)が違う時に現れるエラーのようで、ビルド時のバージョンをSparkのランタイムのバージョンに合わすようにする。

mini-complete-example/build.sbt

scalaVersion := "2.11.12"

とする。


再度ビルドすると、今度は

[error] (update) sbt.librarymanagement.ResolveException: Error downloading org.apache.spark:spark-core_2.11:1.1.0

と依存パッケージのバージョンが解決できないので、こちら scala - sbt got error when run Spark hello world code? - Stack Overflow を参考し解決を計った。

mini-complete-example/build.sbtを変更する

"org.apache.spark" % "spark-core_2.11" % "2.1.0"

これでビルドが通る。と思いきや、

[error] /spark/work/github/mini-complete-example/src/main/java/com/oreilly/learningsparkexamples/mini/java/WordCount.java:34:1: <anonymous com.oreilly.learningsparkexamples.mini.java.WordCount$1> is not abstract and does not override abstract method call(java.lang.String) in org.apache.spark.api.java.function.FlatMapFunction

同梱されているJavaのファイルでエラーがでる(笑)


https://stackoverrun.com/ja/q/10668208 を参考に、該当箇所のコードを、

JavaRDD<String> words = input.flatMap(l -> Arrays.asList(l.split(" ")).iterator());

に変更する。

これでビルドが通る。


spark-submitの実行

再度、

$ sbt clean package
$ /spark/bin/spark-submit \
 --class com.oreilly.learningsparkexamples.mini.scala.WordCount \
 ./target/scala-2.10/learning-spark-mini-example_2.10-0.0.1.jar \
 ./README.md ./wordcounts

とすると

WARN DependencyUtils: Local jar /spark/work/github/mini-complete-example/./target/scala-2.10/learning-spark-mini-example_2.10-0.0.1.jar does not exist, skipping.

となる。そうだった、Scalaのバージョンを変更したので、

/spark/bin/spark-submit \
 --class com.oreilly.learningsparkexamples.mini.scala.WordCount \
 ./target/scala-2.11/learning-spark-mini-example_2.11-0.0.1.jar \
 ./README.md ./wordcounts

とビルドしたjarのターゲット先を変更。

これでspark-submitに指定したwordcountsディレクトリにアプリケーションの実行結果が保存されます。