SparkのMaster1つとWorker1つをdocker-composeで上げてpysparkを動かすまで

# 概要

このエントリでは、Apache Sparkをdocker-composeを使ってmaster1台 + worker1台で立ち上げ、その中でpyspark(pythonのshell)を動かすところまでをとりあえます。

# 前提

## 環境情報

ApacheSparkは、下記バージョンを使用します。

- Apache Spark 2.4.3

動作環境は、Ubuntu 19.04です。

この環境でdocker ceを動かすときの中については、別エントリ[Ubuntu19.04でdocker-ceのインストールでつまづくときのメモ(2019年の5月時点)](https://qiita.com/hrkt/items/d38748625cd1d71412c2)を書きました。

筆者は、Windows 10 Professionalで、Oracle VM Virtialobx 6を動かし、その中でUbuntu 19.04を使っています。

## 他のエントリ

本エントリでは、下記エントリを参考にしました。

- [Docker でお試し Spark クラスタを構築する](https://qiita.com/hoto17296/items/12366c9f9965ce28a780)


# Sparkのコンテナ

下記のようなDockerfileを使用し、Sparkのバイナリが入ったコンテナを作ります。

Java Runtimeには、[Amazon Corretto8](https://hub.docker.com/_/amazoncorretto?tab=description)を使用しました。tar, gzipが入っていなかっtので、yumで入れています。

```dockerfile

FROM amazoncorretto:8u212

ENV SPARK_VERSION=2.4.3
ENV HADOOP_VERSION=2.7

RUN yum install -y tar gzip \
    && curl -O http://apache.mirror.iphh.net/spark/spark-${SPARK_VERSION}/spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}.tgz \
    && 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
```

これをビルドしておきます。

```shell
$ sudo docker build -t spark .
```


# docker-compose

```yaml
networks:
  back:

services:

  master:
    image: spark
    networks:
      - back
    ports:
      - 4040:4040
      - 8080:8080
    command: /spark/bin/spark-class org.apache.spark.deploy.master.Master --host 0.0.0.0

  worker:
    image: spark
    networks:
      - back
    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で起動します。

```
$ sudo docker-compose up -d
```

# 接続

筆者は、下記のようなシェルスクリプトを用意して接続しました。

```bash
$ cat exec_pyspark.sh 
#!/bin/sh
sudo docker-compose exec master /spark/bin/pyspark --master spark://localhost:7077
```

# 実行

[Sparkの公式サイトより、円周率の計算を行うサンプル](https://spark.apache.org/examples.html)を実行してみます。(そのままだとエラーになるので、下記に少し改変したものを載せます。)
これを上記で起動したpysparkのシェルにぺたっと貼ります。

```python
import random
MAX=1000000
def inside(p):
    x, y = random.random(), random.random()
    return x*x + y*y < 1

count = sc.parallelize(xrange(0, MAX)) \
             .filter(inside).count()
print "Pi is roughly %f" % (4.0 * count / MAX)
```

という流れを実際にやると、下記のようになります。
(後述するGitHubのリポジトリの中に、「exec_pyspark.sh」として格納してあるシェルすくクリプトです。コピペするファイルは、"test.py"というファイル名で格納しています。)

```shell

$ ./exec_pyspark.sh 
Python 2.7.14 (default, Jul 26 2018, 19:59:38) 
[GCC 7.3.1 20180303 (Red Hat 7.3.1-5)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
19/05/28 12:24:09 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Using Spark's default log4j profile: org/apache/spark/log4j-defaults.properties
Setting default log level to "WARN".
To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).
Welcome to
      ____              __
     / __/__  ___ _____/ /__
    _\ \/ _ \/ _ `/ __/  '_/
   /__ / .__/\_,_/_/ /_/\_\   version 2.4.3
      /_/

Using Python version 2.7.14 (default, Jul 26 2018 19:59:38)
SparkSession available as 'spark'.
>>> import random
>>> MAX=1000000
>>> def inside(p):
...     x, y = random.random(), random.random()
...     return x*x + y*y < 1
... 
>>> count = sc.parallelize(xrange(0, MAX)) \
...              .filter(inside).count()
>>> print "Pi is roughly %f" % (4.0 * count / MAX)                              
Pi is roughly 3.140824

```

# まとめ

このエントリでは、docker-composeを使い、1台のPCの中でSparkのmaster+workerを起動し、pysparkを起動するところまでを紹介しました。

このエントリで使用したファイルは、[GitHubにタグをつけて格納](https://github.com/hrkt/spark-env-sample/releases/tag/1.0)しています。