使用 docker 来构建 spark 集群

Description:
上一博客中介绍了如何在 ubuntu 上面部署 docker 系统,以及 docker 的基本命令; 在本篇博客中将会介绍如何利用 docker-hub 上的资源来快速搭建一个 spark 集群


如何使用 dockerfile 来生成 docker 镜像文件

在后续的步骤中有一个镜像文件是无法直接从 docker-hub 的镜像库中直接下载的,但是可以从 github 上面下载到该镜像文件的 dockerfile 文件。 所以在这里介绍一下如何使用 dockerfile 来创建 docker 镜像文件。 如果今后需要的话,将会详细介绍一下如何根据自己的需要来定制编写自己的 dockerfile .

docker build

用来将指定路径的中 dockerfile 生成 docker 镜像文件

 docker build -t="amplab/apache-hadoop-hdfs-precise:1.2.1" . 

 // 上述命令会搜索当前路径,看是否有 dockerfile 文件,如果有,那么执行该 dockerfile 文件,并根据该 dockerfile 文件生成
 // docker 镜像文件。同时又将该镜像文件打上名为 'amplab/apache-hadoop-hdfs-precise:1.2.1' 的标签
 // 由于后面会通过 github 上面提供的 deploy.sh 脚本来构建 spark 系统,所以尽最大可能的保持 hadoop 的镜像文件的名称一致性 
 

从 docker-hub 中下载镜像文件

首先确保正确登录 docker-hub 账号
其实我安装 spark 的主要目的是为了使用 spark 提供的 GraphX 和 mllib 这两个工具,而 mllib 中在 spark-0.9 之后才支持,
所以,在这里我安装的是 spark-1.0.0 版本
在执行 pull 命令之前,我开启了翻墙的软件,这样可以节省时间

sudo docker pull amplab/apache-hadoop-hdfs-precise:1.2.1   
// 这个镜像在 docker-hub 上面找不到,所以需要根据 github 可以获得的 Dockerfile 来构建其镜像文件

$docker pull amplab/dnsmasq-precise:1.0.0
$docker pull amplab/spark-worker:1.0.0
$docker pull amplab/spark-master:1.0.1
$docker pull amplab/spark-shell:1.0.1

$docker images                // 通过该命令查看系统中的镜像文件

REPOSITORY               TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu_14                wget                44552cea1d79        7 hours ago         187.9 MB
ubuntu                   14.04               8693db7e8a00        3 weeks ago         187.9 MB
amplab/spark-shell       1.0.0               c18acb8d81a0        20 months ago       964.3 MB
amplab/spark-worker      1.0.0               6f77966546ee        20 months ago       964.3 MB
amplab/spark-master      1.0.0               a43b969cfeff        20 months ago       964.3 MB
amplab/dnsmasq-precise   latest              d9cdba2ae123        23 months ago       205.8 MB

从 git-hub 上面下载运行 docker 镜像文件的脚本

$wget https://github.com/amplab/docker-scripts/archive/master.zip
$unzip master.zip

启动 spark 集群

将路径切换到包含 /deploy 文件夹的路径下面

./deploy/deploy.sh -i amplab/spark:1.0.0 -w 3

$docker ps                 // 通过该命令来查看系统中正在运行的容器信息

CONTAINER ID        IMAGE                           COMMAND                CREATED              STATUS              PORTS                NAMES
855415af179d        amplab/spark-shell:1.0.0        "/root/spark_shell_f   About a minute ago   Up About a minute   8888/tcp             cocky_meitner           
5bb8f871e474        amplab/spark-shell:1.0.0        "/root/spark_shell_f   2 minutes ago        Up 2 minutes        8888/tcp             modest_brown            
2c2d49565559        amplab/spark-worker:1.0.0       "/root/spark_worker_   5 minutes ago        Up 5 minutes        8888/tcp             silly_ptolemy           
24b16b64e6ad        amplab/spark-worker:1.0.0       "/root/spark_worker_   5 minutes ago        Up 5 minutes        8888/tcp             compassionate_lalande   
25efa7bbeb20        amplab/spark-worker:1.0.0       "/root/spark_worker_   5 minutes ago        Up 5 minutes        8888/tcp             happy_curie             
1ba8d72a6cd2        amplab/spark-master:1.0.0       "/root/spark_master_   6 minutes ago        Up 6 minutes        7077/tcp, 8080/tcp   kickass_jones           
3a8c3a8906df        amplab/dnsmasq-precise:latest   "/root/dnsmasq_files   6 minutes ago        Up 6 minutes 

具体的参数解释可以戳这里
-w 是用来指定 spark 运行之后对应的 worker 进程个数
从上面输入 docker ps 命令之后显示出来的信息可以推知,我们总共创建了: spark-shell , spark-worker , spark-master, dns
这些容器运行,但是没有 hadoop 运行, 于是在熟悉上述流程的我又查了其他的几个spark 集群镜像文件,找了一个合适的 接下来试试这个镜像文件好了…


不过先来将当前系统中的所有运行容器停止

// 同样现将路径切换到 ./deploy 文件夹的路径下面
$ ./deploy/kill_all.sh spark
$ ./deploy/kill_all.sh namespace

将该镜像文件下载到本地

$docker pull sequenceiq/spark:v1.6.0onHadoop2.6.0
成功下载显示信息:
...
95d969caad90: Download complete 
2d727ce74b86: Download complete 
28c9338da9a6: Download complete 
cb7d9861a895: Download complete 
73bb712333d9: Download complete 
a466bc76549f: Download complete 
441cf02fdf7d: Download complete 
056efae329d8: Download complete 
Status: Downloaded newer image for sequenceiq/spark:v1.6.0onHadoop2.6.0

从 docker 镜像文件生成并运行容器

先来查看一下当前系统中所有的镜像文件

$docker images     // 先来查看一下当前系统中所有的镜像文件
REPOSITORY               TAG                   IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu_14                wget                  44552cea1d79        24 hours ago        187.9 MB
ubuntu                   14.04                 8693db7e8a00        3 weeks ago         187.9 MB
sequenceiq/spark         v1.6.0onHadoop2.6.0   056efae329d8        5 weeks ago         2.877 GB
amplab/spark-shell       1.0.0                 c18acb8d81a0        20 months ago       964.3 MB
amplab/spark-worker      1.0.0                 6f77966546ee        20 months ago       964.3 MB
amplab/spark-master      1.0.0                 a43b969cfeff        20 months ago       964.3 MB
amplab/dnsmasq-precise   latest                d9cdba2ae123        23 months ago       205.8 MB

再运行镜像文件生成容器实例

$docker run -it sequenceiq/spark:v1.6.0onHadoop2.6.0  bash 

成功运行显示信息:
Starting sshd:                                             [  OK  ]
Starting namenodes on [1f25c1d3d790]
1f25c1d3d790: starting namenode, logging to /usr/local/hadoop/logs/hadoop-root-namenode-1f25c1d3d790.out
localhost: starting datanode, logging to /usr/local/hadoop/logs/hadoop-root-datanode-1f25c1d3d790.out
Starting secondary namenodes [0.0.0.0]
上述 docker 运行命令作用是是从刚刚下载到本地的 docker 镜像文件中生成 docker 容器(该容器中就包含部署好了的 hadoop 和 spark 软件);
生成容器之后,登录到该容器中,并运行 bash 命令

成功登录显示信息:
bash-4.1# ls     // 先显示一下容器中的基本信息       
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  pam-1.1.1-17.el6.src.rpm  proc  root  rpmbuild  sbin  selinux  srv  sys  tmp  usr  var
bash-4.1# jps     // 然后查看一下容器系统中运行的进程都有什么。 可以看出有 Hadoop 节点和 Spark 等相关进程在运行 
562 NodeManager
353 SecondaryNameNode
109 NameNode
183 DataNode
636 Jps
482 ResourceManager

运行 spark 中的 counter 测试程序

首先需要运行一下 spark-shell , 直接在当前 bash 命令行中输入如下命令 
$spark-shell \
 --master yarn-client \
 --driver-memory 1g \
 --executor-memory 1g \
 --executor-cores 1

如果成功,将会显示如下信息:

16/02/14 02:57:02 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
16/02/14 02:57:03 INFO spark.SecurityManager: Changing view acls to: root
16/02/14 02:57:03 INFO spark.SecurityManager: Changing modify acls to: root
16/02/14 02:57:03 INFO spark.SecurityManager: SecurityManager: authentication disabled; ui acls disabled; users with view permissions: Set(root); users with modify permissions: Set(root)
16/02/14 02:57:04 INFO spark.HttpServer: Starting HTTP Server
16/02/14 02:57:04 INFO server.Server: jetty-8.y.z-SNAPSHOT
16/02/14 02:57:04 INFO server.AbstractConnector: Started SocketConnector@0.0.0.0:58832
16/02/14 02:57:04 INFO util.Utils: Successfully started service 'HTTP class server' on port 58832.
Welcome to
      ____              __
     / __/__  ___ _____/ /__
    _\ \/ _ \/ _ `/ __/  '_/
   /___/ .__/\_,_/_/ /_/\_\   version 1.6.0
      /_/

Using Scala version 2.10.5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_51)
Type in expressions to have them evaluated.
... 后面反正还有挺多,最后会看到 scala> 命令行提示输入符

我们来测试一个最简单的计数程序调用好了

scala> sc.parallelize( 1 to 1000).count()
16/02/14 03:01:56 INFO spark.SparkContext: Starting job: count at :28
16/02/14 03:01:56 INFO scheduler.DAGScheduler: Got job 0 (count at :28) with 2 output partitions
16/02/14 03:01:56 INFO scheduler.DAGScheduler: Final stage: ResultStage 0 (count at :28)
16/02/14 03:01:56 INFO scheduler.DAGScheduler: Parents of final stage: List()
16/02/14 03:01:56 INFO scheduler.DAGScheduler: Missing parents: List()
16/02/14 03:01:56 INFO scheduler.DAGScheduler: Submitting ResultStage 0 (ParallelCollectionRDD[0] at parallelize at :28), which has no missing parents
16/02/14 03:01:57 INFO storage.MemoryStore: Block broadcast_0 stored as values in memory (estimated size 1096.0 B, free 1096.0 B)
16/02/14 03:01:57 INFO storage.MemoryStore: Block broadcast_0_piece0 stored as bytes in memory (estimated size 804.0 B, free 1900.0 B)
16/02/14 03:01:57 INFO storage.BlockManagerInfo: Added broadcast_0_piece0 in memory on 172.17.0.10:48410 (size: 804.0 B, free: 517.4 MB)
16/02/14 03:01:57 INFO spark.SparkContext: Created broadcast 0 from broadcast at DAGScheduler.scala:1006
16/02/14 03:01:57 INFO scheduler.DAGScheduler: Submitting 2 missing tasks from ResultStage 0 (ParallelCollectionRDD[0] at parallelize at :28)
16/02/14 03:01:57 INFO cluster.YarnScheduler: Adding task set 0.0 with 2 tasks
16/02/14 03:01:58 INFO scheduler.TaskSetManager: Starting task 0.0 in stage 0.0 (TID 0, 42ba3f37ce84, partition 0,PROCESS_LOCAL, 2078 bytes)
16/02/14 03:01:58 INFO scheduler.TaskSetManager: Starting task 1.0 in stage 0.0 (TID 1, 42ba3f37ce84, partition 1,PROCESS_LOCAL, 2135 bytes)
16/02/14 03:02:04 INFO storage.BlockManagerInfo: Added broadcast_0_piece0 in memory on 42ba3f37ce84:58577 (size: 804.0 B, free: 517.4 MB)
16/02/14 03:02:04 INFO storage.BlockManagerInfo: Added broadcast_0_piece0 in memory on 42ba3f37ce84:36276 (size: 804.0 B, free: 517.4 MB)
16/02/14 03:02:09 INFO scheduler.TaskSetManager: Finished task 0.0 in stage 0.0 (TID 0) in 11580 ms on 42ba3f37ce84 (1/2)
16/02/14 03:02:09 INFO scheduler.TaskSetManager: Finished task 1.0 in stage 0.0 (TID 1) in 11454 ms on 42ba3f37ce84 (2/2)
16/02/14 03:02:09 INFO cluster.YarnScheduler: Removed TaskSet 0.0, whose tasks have all completed, from pool 
16/02/14 03:02:09 INFO scheduler.DAGScheduler: ResultStage 0 (count at :28) finished in 11.657 s
16/02/14 03:02:09 INFO scheduler.DAGScheduler: Job 0 finished: count at :28, took 13.058068 s
res0: Long = 1000

这样一个 spark 集群就搭建好了,如果需要把当前对容器做出的修改同步到原有的镜像文件(推荐重新另存一个新的镜像文件),可以使用上一篇博客中介绍的 docker commit 这个命令

关于收尾工作

当前所处的状态是 scala> 的命令行,输入 exit 便可以退出当前 scala 命令行交互的状态;
再次输入 exit (一次或是多次) 便可以退出当前登录的 spark-hadoop 集群容器,当然容器在你退出之后便会’消亡’,也就是不运行了系统回收它的资源咯,输入 docker ps 便查看不到容器信息;
如果在实际工作中推荐的做法是,在退出容器之前,在另一个远程访问终端内,将该容器的状态信息进行保存(归档或是生成镜像文件,如果乐意也可以将生成的镜像文件提交到 docker-hub 的上面)

总之,博客中很多地方写的很啰嗦啦,因为我喜欢在自己经常犯的错误的地方啰嗦几句,不喜欢的话,来打我啊~
end