Apache Mesos で Apache Spark を動かす

ほとんど作業ログかつ自分用 (あとでもう少しまともな記事になるように編集するかも) です.
あと, Qiita 初投稿です:innocent:

# 環境

今回は ConoHa を 2 台使って Mesos クラスタを構築し, その上で Spark を動作させる.
スペックや OS などは以下の通り.

* Master: ConoHa RAM 1GB プラン, CentOS 7.2
* Slave: ConoHa RAM 2GB プラン, CentOS 7.2

使用した Mesos と Spark のバージョンは以下の通り.
どちらも執筆時点 (2016/12/7) の最新バージョンのはず.

* Apache Mesos: v1.1.0
* Apache Spark: v2.0.2

# Mesos のインストール

[公式ドキュメント](http://mesos.apache.org/gettingstarted/)を参考に作業を進める.
Master と Slave 両方で作業をしてください.

```
$ sudo yum install -y tar wget git
$ sudo wget http://repos.fedorapeople.org/repos/dchen/apache-maven/epel-apache-maven.repo -O /etc/yum.repos.d/epel-apache-maven.repo
$ sudo yum install -y epel-release
$ sudo bash -c 'cat > /etc/yum.repos.d/wandisco-svn.repo <<EOF
[WANdiscoSVN]
name=WANdisco SVN Repo 1.9
enabled=1
baseurl=http://opensource.wandisco.com/centos/7/svn-1.9/RPMS/$basearch/
gpgcheck=1
gpgkey=http://opensource.wandisco.com/RPM-GPG-KEY-WANdisco
EOF'
$ sudo yum update systemd
$ sudo yum groupinstall -y "Development Tools"
$ sudo yum install -y apache-maven python-devel java-1.8.0-openjdk-devel zlib-devel libcurl-devel openssl-devel cyrus-sasl-devel cyrus-sasl-md5 apr-devel subversion-devel apr-util-devel
```

ドキュメントには載っていないがコンパイル時にエラーになるので, pip と pytz をインストールしておく.

```
$ sudo yum install python-pip
$ sudo pip install --upgrade pytz
```


Mesos をダウンロードする.

```
$ wget http://archive.apache.org/dist/mesos/1.1.0/mesos-1.1.0.tar.gz
$ tar zxvf mesos-1.1.0.tar.gz
$ cd mesos-1.1.0
```

Mesos のコンパイルとビルドを行う.

```
$ mkdir build
$ cd build
$ ../configure
$ make
$ sudo make install
```

# Spark のインストール

こちらも Master と Slave の両方で作業をしてください.

Spark をダウンロードして `/usr/local` に配置する.
後々バージョンが変わったときにも対応できるように `/usr/local/spark` にシンボリックリンクを張っておく.

```
$ wget http://d3kbcqa49mib13.cloudfront.net/spark-2.0.2-bin-hadoop2.7.tgz
$ tar zxvf spark-2.0.2-bin-hadoop2.7.tgz
$ sudo mv spark-2.0.2-bin-hadoop2.7 /usr/local
$ sudo ln -s /usr/local/spark-2.0.2-bin-hadoop2.7 /usr/local/spark
```

Mesos と連携するための設定をしておく.

```
$ cp conf/spark-env.sh.template conf/spark-env.sh
$ vi conf/spark-env.sh
```

末尾に以下を追加する.

```
MESOS_NATIVE_JAVA_LIBRARY=/usr/local/lib/libmesos.so
SPARK_DRIVER_MEMORY=512M
SPARK_DAEMON_MEMORY=256M
```

下 2 つの設定は今回のような RAM が不十分なときだけで良い.

# Master ノード構築

Master ノードで mesos-master プロセスを起動する.
再起動や自動起動が後で楽になるように今回は systemd にプロセス立ち上げを任せた.
(ココらへんはあまり詳しくないのでざっくりと...)

```
$ sudo vi /etc/lib/systemd/system/mesos-master.service
```

```mesos-master.service
[Unit]
Description=Apache Mesos master
After=network.target

[Service]
ExecStart=/usr/local/sbin/mesos-master --work_dir=/var/lib/mesos-master
KillMode=process
Restart=always

[Install]
WantedBy=multi-user.target
```

```
sudo systemctl start mesos-master
sudo systemctl enable mesos-master // Optional
```

mesos-master プロセスが起動したのを確認後, 適当なマシンで以下の URL にアクセスして Web UI が表示されれば mesos-master の起動完了.

```
http://[Master ノードの IP アドレス]:5050
```

今回は Spark を Client モードではなく Cluster モードで立ち上げるので Mesos クラスタで `MesosClusterDispatcher` を起動する.

```
$ cd /usr/local/spark
$ sudo sbin/start-mesos-dispatcher.sh --master localhost:5050
```

先ほどの Web UI の Frameworks タブに Spark Cluster が追加されれば起動完了.

# Slave ノード構築

Slave ノードで mesos-agent プロセスを起動する.
こちらもサービスの管理は systemd にやらせる.

```
$ sudo vi /etc/lib/systemd/system/mesos-agent.service
```

```mesos-agent.service
[Unit]
Description=Apache Mesos agent
After=network.target

[Service]
ExecStart=/usr/local/sbin/mesos-agent --master=[Master ノードの IP アドレス]:5050 --work_dir=/var/lib/mesos-slave --resources=mem:1536
KillMode=process
Restart=always

[Install]
WantedBy=multi-user.target
```

RAM が十分にある環境の場合は ExecStart の最後の引数の `--resources=mem:5136` を外してください.

```
$ sudo systemctl start mesos-agent
$ sudo systemctl enable mesos-agent // Optional
```

mesos-agent プロセスが起動したのを確認後, 先ほどの Web UI の Agents タブに Slave ノードのホストが書かれた項目が表示されていれば完了.

# Spark のサンプルを動かしてみる

ここまでくれば Spark Cluster on Mesos な環境が構築できてるはずなので, サンプルにある適当なジョブを動かしてみる.
ただし, 動かすプログラムが含まれた jar は HTTP　から見れる位置に上げる必要がある.
適当な Web サーバにアップロードするか Google Drive などのクラウドストレージを使うのもありだろう.

```
cd /usr/local/spark
bin/spark-submit --class org.apache.spark.examples.SparkPi \
--master mesos://[Master ノードの IP アドレス]:7077 \
--executor-memory 512M
--deploy-mode cluster \
--supervise \
http://path/to/package.jar \
1000
```

しばらくして Mesos Web UI の Completed Tasks に FINISHED と項目が追加されればジョブが完了.
一番右にある Sandbox リンクを開いて stdout に以下のようなものが表示されていれば無事 Spark Cluster で処理が行えたことになる.

```
Pi is roughly 3.1415941514159416
```

# 最後に

今回は比較的サーバーリソースが貧しい環境での構築だったので, 使用メモリの制限などかなり面倒なことになった.
あまりに空きメモリが少ない場合 Mesos のコンパイルで失敗する可能性もある (経験談) ので要注意.
Spark Cluster を組むときには潤沢な RAM を積んだサーバを用意しましょうｗ