はじめに
学部3年、現在就活中の大木です。
現在インターン先でレコメンドシステムをsparkをもちいて構築しているのですが、
EMRでsparkを動かしてゴニョゴニョする前にローカルで色々試してみたく、
またどうせならspark clusterを構築してワチャワチャやりたいと思いそのためにdockerfileを作ったので共有します。
こちら
2357gi/apache-spark-cluster: localでspark clusterを立ち上げて遊ぶ用 pyspark用のnotebookもあるヨ!
🐰使い方
cloneして
$ git clone https://github.com/2357gi/apache-spark-cluster
jupyter notebookを使いたい場合はDockerfile内の以下の環境変数を有効化して
make run &&make notebook
で立ち上がります。
PYSPARK_DRIVER_PYTHON=/usr/local/bin/jupyter \
PYSPARK_DRIVER_PYTHON_OPTS="notebook --no-browser --port 8888 --ip=0.0.0.0 --allow-root"
\
で環境変数を複数行に渡り書き連ねているので、その辺を気をつけてください。
pythonfileをsubmitしたい場合は上記の環境変数に関する記述を消してmake run &&make kick-py <pythonfile>
でどうぞ。
UI用のポートも開放しているので
Spark Master at spark://master:7077
や
Spark Jobs(spark taskが実行されている瞬間のみ)
も使えるようになっています。
解説
Dockerfile
FROM ubuntu:18.04
ベースとなるイメージはUbuntu18.04を使用しています。
採用理由は個人的に使い慣れているだけです。
python等のイメージを使用しても良かったのですが、理解しながら作業を進めたかったのであえてこちらを使用しました。
# Environment variables
ENV SPARK_VERSION=2.4.0 \
HADOOP_VERSION=2.7 \
SPARK_HOME=/spark \
PATH=$SPARK_HOME/bin:$PATH \
PYSPARK_PYTHON=/usr/bin/python3 \
PYSPARK_DRIVER_PYTHON=/usr/local/bin/jupyter \
PYSPARK_DRIVER_PYTHON_OPTS="notebook --no-browser --port 8888 --ip=0.0.0.0 --allow-root"
環境変数を設定します。
SPARK_VERSIONやHADOOP_VERSIONを変数として登録し、後のsparkをダウンロードする際のダウンロードUrlに変数を使用しています。
これによりバージョン変更に強くなります。
ミソとなるのがPYSPARK_PYTHON
, PYSPARK_DRIVER_PYTHON
, PYSPARK_DRIVER_PYTHON_OPTS
です。
PYSPARK_PYTHON
ここでpysparkのpythonのバージョン指定を行なっています。
PYSPARK_DRIVER_PYTHON
, PYSPARK_DRIVER_PYTHON_OPTS
こちらでpysparkがjupyter notebookで立ち上がるように設定しています。
githubに上がっているDockerfileにはこの2種の変数の記述はないので、
もしnotebookを使用したいのであれば適宜追加してください。
notebookの引数諸々はdocker内で起動したjupyter notebookをホスト側から接続するための諸々です。
この辺はすこしセキュアではないのですが、ローカルで遊ぶだけなので許容範囲としました。
# Install required apt package and ensure that the packages were installed
RUN apt-get update && apt-get install -y \
bc \
curl \
default-jdk \
git \
python3 \
python3-pip \
scala
(説明略)
# Install spark
RUN mkdir spark &&\
curl -sL \
http://ftp.tsukuba.wide.ad.jp/software/apache/spark/spark-${SPARK_VERSION}/spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}.tgz \
| tar zx -C spark --strip-components 1
sparkを引っ張ってきて展開し、/sparkに設置しています。
近さ的に筑波のミラーから引っ張ってきていますがココらへんはあんまりよくないかもしれません。
展開の方法ですがcurlで引っ張ってきたものをtarにパイプで渡すことによってcurl &&tar &&mv && rm
などといったナンセンスなコマンドの羅列にならないように工夫しましたがココらへんは悔しさが残ります。(詳細)
RUN pip3 install jupyter ipyparallel \
&& ipcluster nbextension enable
jupyterをpipでinstallします。
pipでjupyterを導入するとpython3のkernelを読み込んでくれない?ここがすこしうまく行かなかったので
別途ipyparallelをpipでインストールしてnbextensiionをenableします。
これでjupyter notebook上でpython3がつかえるようになります。
Docker-compose
みんな大好きdocker-compose
version: '3'
services:
master:
image: 2357gi/apache-spark
hostname: master
ports:
- 4040:4040
- 6066:6066
- 8080:8080
- 7077:7077
environment:
MASTER: spark://master:7077
SPARK_CONF_DIR: /conf
SPARK_PUBLIC_DNS: localhost
volumes:
- ./work:/work
- ./data:/data
command: /spark/bin/spark-class org.apache.spark.deploy.master.Master -h master
worker1:
image: 2357gi/apache-spark
hostname: worker1
depends_on:
- master
ports:
- 8081:8081
environment:
SPARK_CONF_DIR: /conf
SPARK_WORKER_CORES:
SPARK_WORKER_MEMORY: 2g
SPARK_WORKER_PORT: 8081
SPARK_WORKER_WEBUI_PORT: 8081
SPARK_PUBLIC_DNS: localhost
volumes:
- ./work:/work
- ./data:/data
command: /spark/bin/spark-class org.apache.spark.deploy.worker.Worker spark://master:7077
worker2:
image: 2357gi/apache-spark
hostname: worker1
depends_on:
- master
ports:
- 8082:8082
environment:
SPARK_CONF_DIR: /conf
SPARK_WORKER_CORES:
SPARK_WORKER_MEMORY: 2g
SPARK_WORKER_PORT: 8082
SPARK_WORKER_WEBUI_PORT: 8082
SPARK_PUBLIC_DNS: localhost
volumes:
- ./work:/work
- ./data:/data
command: /spark/bin/spark-class org.apache.spark.deploy.worker.Worker spark://master:7077
$ docker-compose up --scale worker=n
でスケールするようにしたかったのですが、
ポートの変更とSPARK_WORKER_PORT
の変数を連動させるのが難しかったのでこの形に落ち着きました。
誰か氏〜〜〜!w
Makefile
WORKER=1
build_docker: Dockerfile
@echo "\n📦 build 2357gi/apache-spark"
@docker build ./ -t 2357gi/apache-spark
build_compose:
@echo "\n🏗 Pile up containers"
@docker-compose up -d --scale worker=$(WORKER)
run: docker-compose.yml
@echo "\n✨ apache-spark cluster setup is start!"
@make build_docker
@make build_compose
@echo "\n🍾 set up is finished! \n you wanna access ⚡spaek shell, hit it! \n$$ make s-shell"
@echo "or you wanna start 📔 pyspark notebook, hit it! \n$$ make notebook"
@echo "... if u wanna open 🐚 shell? do this. \n$$ make shell"
s-shell:
@echo "\n⚡ start spark-shell...."
@docker-compose exec master /spark/bin/spark-shell --master spark://localhost:7077
notebook:
@echo "\n📔 start pyspark notebook...."
@docker-compose exec master /spark/bin/pyspark
@docker-compose exec
shell:
@echo "\n🐚 start master shell...."
@docker-compose exec master /bin/bash
WORKERを変数にすることによって$ make run WORKER=<任意のworker node数
を指定できるようにしました。
あとは普通な感じです。
これは蛇足ですが、
makefileに絵文字を入れると可愛くていいですね。