搭建mesos集群,使用zookeeper管理mesos master,防止单点失效。在mesos集群上运行spark,并搭建jupyter,做为spark client。
搭建zookeeper\mesos集群 3个zookeeper,3个mesos master
zookeeper dockerfile 1 2 3 4 5 6 7 FROM openjdk8:on MAINTAINER lyalchan "lyallchan@163.com" ENV ZOOKEEPER="zookeeper-3.4.9" RUN busybox wget http://caddy/$ZOOKEEPER.tar.gz -O - | tar zx && ln -s /$ZOOKEEPER /zookeeper RUN mv /zookeeper/conf/zoo_sample.cfg /zookeeper/conf/zoo.cfg ENV PATH /zookeeper/bin:$PATH
很简单,就是下载解压,默认的配置文件,zookeeper/bin加入路径
mesos dockerfile 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 FROM openjdk8:on MAINTAINER lyalchan "lyallchan@163.com" ENV MESOS="mesos-bin-1.1.0" RUN busybox wget http://caddy/$MESOS.tar.gz -O - | tar xz && ln -s /$MESOS /mesos RUN apt-get update && apt-get install -y \ libsvn1 \ libcurl3-nss ENV PATH /mesos/bin:/mesos/sbin:$PATH ENV CONDA="Miniconda2-latest-Linux-x86_64.sh" RUN busybox wget http://caddy/$CONDA -P / RUN bash /$CONDA -b -p conda RUN rm /$CONDA ENV PATH /conda/bin:$PATH ENV PYTHONPATH=$PYTHONPATH:/mesos/lib/python2.7/site-packages/ RUN conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ \ && conda config --set show_channel_urls yes
mesos部分也比较简单,下载解压,mesos/bin和mesos/sbin加入路径。
安装了libsvn1和libcurl3-nss包,这是在启动mesos的时候提示缺少文件,再加上去的。
mesos WEB UI需要python运行,这里没有直接安装python,而是使用了conda。
conda是偏重于科学计算的python套件,其中的包管理工具conda比pip好用。
conda的安装包直接是个脚本文件,bash这个文件就可以安装,加上-b参数可以接受默认配置,自动安装
最后的conda config是换国内源
启动zookeeper集群 zookeeper start.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #!/bin/sh NETWORK="net" CONTAINER="zoo" NUM=3 # hosts in cluster # start zookeeper containers... echo echo starting zookeeper containers... for i in `seq $NUM`; do docker run \ -d \ --hostname ${CONTAINER}$i \ --name ${CONTAINER}$i \ --net $NETWORK \ zookeeper \ /bin/bash -c "/etc/init.d/ssh start && sleep 99999999" done # start zookeeper service echo echo starting zookeeper service ZOOKEEPER_DATADIR="/zookeeper/data" for i in `seq 1 $NUM`; do #/zoo.cfg specially for server:1=xxxxx for j in `seq $NUM`; do docker exec ${CONTAINER}$i /bin/bash -c "echo server.$j=${CONTAINER}$j:2888:3888 >> /zookeeper/conf/zoo.cfg" done docker exec ${CONTAINER}$i /bin/bash -c "echo dataDir=$ZOOKEEPER_DATADIR >> /zookeeper/conf/zoo.cfg" docker exec ${CONTAINER}$i /bin/bash -c "mkdir -p $ZOOKEEPER_DATADIR" docker exec ${CONTAINER}$i /bin/bash -c "echo $i > $ZOOKEEPER_DATADIR/myid" docker exec ${CONTAINER}$i /zookeeper/bin/zkServer.sh start done echo done!
由于启动zookeeper服务器的数量需要动态调整,不必重新生成image,因此采用先启动容器,再动态生成配置文件,启动服务的方案。
NUM是zookeeper服务器的数量,官方推荐奇数,最少3台服务器,这里就定义为3
第二段是启动容器,并同时启动了ssh服务
第三段是动态生成zoo.cfg和myid,并启动zookeeper服务。最后生成的zoo.cfg,除去默认的部分为
1 2 3 4 server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888 dataDir=/zookeeper/data
myid根据服务器顺序分别为1,2,3
zkServer.sh start启动服务。
启动mesos master集群 mesos start-master.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #!/bin/sh CONTAINER=mesos NET=net MASTER=zk://zoo1:2181,zoo3:2181,zoo3:2181/mesos for i in `seq 3`; do docker run \ -itd \ --hostname ${CONTAINER}$i \ --name ${CONTAINER}$i \ -p 505$i:505$i \ --network $NET \ -e MESOS_QUORUM=2 \ -e MESOS_ZK=$MASTER \ -e MESOS_WORK_DIR="/" \ -e MESOS_HOSTNAME=localhost \ -e MESOS_PORT=505$i \ mesos \ mesos-master done
mesos的配置可以有两种方式传递
命令行参数
环境变量
docker环境下,传递环境变量比较方便
MASTER指向zookeeper集群,并在容器启动时,传递给MESOS_ZK
按照顺序分别启动mesos-master容器
暴露5051,5052,5052端口
定义HOSTNAME,这个参数是mesos WEB UI定时刷新页面的时候访问的地址,由于是docker环境,端口暴露后的主机为localhost。
其它参数比较好理解
这样,启动了mesos master集群,并使用zookeeper做HA,防止单点失效。
在mesos上运行spark spark dockerfile 1 2 3 4 5 6 7 8 9 10 11 FROM mesos MAINTAINER lyalchan "lyallchan@163.com" ENV SPARK="spark-2.1.0-bin-hadoop2.6" RUN busybox wget -O - http://caddy/$SPARK.tgz | tar zx \ && ln -s /$SPARK /spark ENV PATH /spark/sbin:/spark/bin:$PATH ENV SPARK_HOME=/spark RUN echo "export MESOS_NATIVE_JAVA_LIBRARY=/mesos/lib/libmesos.so" >> /spark/conf/spark-env.sh ENV PYSPARK_PYTHON=/conda/bin/python RUN conda install numpy -y
spark在mesos上运行,必须要有mesos环境,因此在mesos镜像基础上建立spark镜像。
官网上说,除了将spark压缩包放在mesos可以访问的地方,也可以在所有mesos slave的相同目录安装spark,配置spark.mesos.excutor.home指向$SPARK_HOME
Alternatively, you can also install Spark in the same location in all the Mesos slaves, and configure spark.mesos.executor.home (defaults to SPARK_HOME) to point to that location.
安装过程很常规,下载解压。
在spark-env.sh中设置MESOS_NATIVE_JAVA_LIBRARY为libmesos.so
设置PYSPARK_PYTHON为conda的python,使得spark可以找到python
最后装上numpy包
启动spark spark start-mesos-slave.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #!/bin/sh DIR=`dirname $0` DATA=`cygpath -aw $DIR/data` NET="net" CONTAINER="spark" MASTER=zk://zoo1:2181,zoo2:2181,zoo3:2181/mesos S_NUM=3 # start spark slave containers with mesos for i in `seq 1 $S_NUM`;do docker run \ -itd \ --hostname ${CONTAINER}_s$i \ --name ${CONTAINER}_s$i \ --network $NET \ --privileged \ --volume "$DATA":/v \ -e MESOS_MASTER=$MASTER \ -e MESOS_WORK_DIR="/" \ -e MESOS_SYSTEMD_ENABLE_SUPPORT=false \ spark \ mesos-slave done
与其说启动spark,不如说是启动mesos slave。当客户端提交spark应用后,mesos slave再启动spark。
mesos slave使用容器技术(自带的或者docker)启动framework,framework是运行在mesos上的应用程序。因此启动mesos slave容器比较麻烦,需要特权启动,如果使用docker,还需要绑定宿主机的docker.sock和docker。
S_NUM是启动的spark节点数量,最小1个,这里取3个。
搭建jupyter 搭建jupyter做为spark集群客户端。
jupyter dockerfile jupyter做为spark集群客户端需要有mesos、spark以及python环境。
上面的spark镜像也有这三个环境,不过其中python是mini conda。
为了使用jupyter,有两个选择,可以在spark镜像基础上再安装jupyter,也可以从头安装mesos和spark,并安装anaconda,anaconda是更加强大的python科学计算包,其中包括了jupyter。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 # Creates anaconda with spark FROM openjdk8:on MAINTAINER lyalchan "lyallchan@163.com" ENV MESOS="mesos-bin-1.1.0" RUN busybox wget http://caddy/$MESOS.tar.gz -O - | tar xz && ln -s /$MESOS /mesos RUN apt-get update && apt-get install -y \ libsvn1 \ libcurl3-nss ENV PATH /mesos/bin:/mesos/sbin:$PATH ENV SPARK="spark-2.1.0-bin-hadoop2.6" RUN busybox wget -O - http://caddy/$SPARK.tgz | tar zx \ && ln -s /$SPARK /spark ENV PATH /spark/sbin:/spark/bin:$PATH ENV SPARK_HOME=/spark RUN echo "export MESOS_NATIVE_JAVA_LIBRARY=/mesos/lib/libmesos.so" >> /spark/conf/spark-env.sh ENV CONDA=Anaconda2-4.3.0-Linux-x86_64.sh RUN busybox wget http://caddy/$CONDA -P / RUN bash /$CONDA -b -p conda RUN rm /$CONDA ENV PATH /conda/bin:$PATH ENV PYSPARK_DRIVER_PYTHON jupyter ENV PYSPARK_DRIVER_PYTHON_OPTS "notebook --ip='*' --NotebookApp.password='' --NotebookApp.token='' --no-browser" ENV PYSPARK_PYTHON=/conda/bin/python RUN conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ \ && conda config --set show_channel_urls yes
mesos\spark常规安装,spark安装好以后,在spark-env.sh设置变量MESOS_NATIVE_JAVA_LIBRARY。
anaconda下载安装好以后,要设置2个环境变量,使得pyspark启动时,调用jupyter notebook,这在pyspark脚本中有详细说明:
In Spark 2.0, IPYTHON and IPYTHON_OPTS are removed and pyspark fails to launchis set in the user’s environment. Instead, users should set PYSPARK_DRIVER_PYTHON to use IPython and set PYSPARK_DRIVER_PYTHON_OPTS to pass options when starting (e.g. PYSPARK_DRIVER_PYTHON_OPTS=’notebook’). This supports full customization and executor Python executables.
ENV PYSPARK_DRIVER_PYTHON jupyter
ENV PYSPARK_DRIVER_PYTHON_OPTS “notebook –ip=’*’ –NotebookApp.password=’’ –NotebookApp.token=’’ –no-browser”
还要设置PYSPARK_PYTHON指向/conda/bin/python,使得spark可以找到python。
启动jupyter jupyter start.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #!/bin/bash V=`cygpath -aw $(dirname $0)/v` CONTAINER="conda" NETWORK="net" MASTER=zk://zoo1:2181,zoo2:2181,zoo3:2181/mesos docker run \ -itd \ --hostname ${CONTAINER} \ --name ${CONTAINER} \ --network $NETWORK \ -v "$V":/v:rw \ -w /v \ -p 127.0.0.1:8888:8888\ -p 4040:4040 \ anaconda \ /bin/sh -c "pyspark --master mesos://$MASTER"
测试 系统全部跑起来,需要启动zookeeper、mesos master、mesos slave with spark和jupyter
暴露的端口有
1 2 3 5051:5052:5053 3个mesos master服务 8888 jupyter notebook 4040 spark jobs
localhost:5051 访问localhost:5051可以看到
选举出来的server是5051,是第一个mesos容器mesos1
有3个agents,分别是spark的3个容器
有1个framwork,是conda容器的PySparkShell,也就是跑的juypter notebook
停止mesos1,2-3min后,可以看到选举的server变成5052
localhost:8888 访问localhost:8888,是jupyter notebook界面,可以在其中新建一个notebook,并运行一个spark案例
1 2 3 4 5 6 7 8 import numpy as np from pyspark.mllib.stat import Statistics m = sc.parallelize([np.array([1.0, 20.0, 300.0]), np.array([3.0, 10.0, 200.0]), np.array([2.0, 30.0, 100.0])],2) summary = Statistics.colStats(m) print(summary.mean()) # a dense vector containing the mean value for each column print(summary.variance()) # column-wise variance print(summary.numNonzeros()) # number of nonzeros in each column
如果有结果,说明安装成功。
localhost:4040 访问localhost:4040,可以看到刚才跑的案例的分布式计算的过程。