Docker部署Spark并提交WordCount任务

Spark概述

Apache Spark是一个开源集群运算框架,最初是由加州大学柏克莱分校AMPLab所开发。相对于HadoopMapReduce会在运行完工作后将中介数据存放到磁盘中,Spark使用了存储器内运算技术,能在数据尚未写入硬盘时即在存储器内分析运算。Spark在存储器内运行程序的运算速度能做到比Hadoop MapReduce的运算速度快上100倍,即便是运行程序于硬盘时,Spark也能快上10倍速度。[1]Spark允许用户将数据加载至集群存储器,并多次对其进行查询,非常适合用于机器学习算法。摘自维基百科。总结一下就是,hadoop的mapreduce是将中间结果存在磁盘上,而spark是将中间结果存在主存中,所以速度比Hadoop的mapreduce快。

准备工作

环境选择
  • 宿主机系统:win10
  • hadoop版本:3.1.1(构建基于HDFS的spark)
  • Spark版本:2.4.5
  • 容器系统:ubuntu16
  • jdk:1.8
准备
  • 下载jdk1.8下载地址放入E:/docker/spark目录下
  • 下载Hadoop下载地址放入E:/docker/spark目录下,这一步不是必须的,只是因为我部署hdfs的时候选择了版本3.1.1不想重新部署,所以下载Spark时选择了Pre-build with user-provided Apache Haddop,啥意思呢?就是自定义版本的Hadoop,如果选择的Spark版本是Pre-build for Apache Haddop 2.6/2.7,那就不需要单独下载Hadoop,因为下载的Spark已经预编译了。
  • 下载spark下载地址放入E:/docker/spark目录下,选择好自己的版本,如果已经安装了Hadoop2.6/2.7建议直接下载预编译了Hadoop的版本,不需要后续配置环境参数。
  • 关于Hadoop集群的部署可以参考Hadoop学习笔记(1)-环境搭建
编写Dockerfile文件
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
39
40
FROM ubuntu:16.04
MAINTAINER houwanfei

# 安装openssh-server
RUN apt-get update && apt-get install -y openssh-server

# 配置ssh免密登陆
RUN ssh-keygen -t rsa -f ~/.ssh/id_rsa -P '' && \
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
# 复制jdk和配置jdk环境
RUN mkdir /usr/lib/jvm/
ADD openjdk-8u40-b25-linux-x64-10_feb_2015.tar.gz /usr/lib/jvm/
ENV JAVA_HOME /usr/lib/jvm/java-se-8u40-ri/
ENV PATH $PATH:$JAVA_HOME/bin

# 复制hadoop和配置hadoop配置
RUN mkdir /usr/local/hadoop/
ADD hadoop-3.1.1.tar.gz /usr/local/hadoop/
ENV HADOOP_HOME /usr/local/hadoop/hadoop-3.1.1
ENV PATH $PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin

# 复制spark和配置spark环境
RUN mkdir /usr/local/spark
ADD spark-2.4.5-bin-without-hadoop.tgz /usr/local/spark
ENV SPARK_HOME=/usr/local/spark/spark-2.4.5-bin-without-hadoop
ENV PATH=$PATH:$SPARK_HOME/bin
ENV SPARK_MASTER_PORT 7077
ENV SPARK_MASTER_WEBUI_PORT 8080
ENV SPARK_MASTER_LOG /tmp/logs
ENV SPARK_WORKER_LOG /tmp/logs
ENV SPARK_VERSION 2.4.5

# 复制配置文件
COPY config/* /tmp/
RUN mv /tmp/spark-config.sh $SPARK_HOME/sbin && \
mv /tmp/spark-env.sh $SPARK_HOME/conf
# 暴露端口
EXPOSE 8080 7077 6066

CMD [ "sh", "-c", "service ssh start; bash"]
配置配置文件
1
2
3
4
5
6
7
# 将两个文件放入E:/docker/spark/config目录下
# spark-env.sh
export SPARK_DIST_CLASSPATH=$(${HADOOP_HOME}/bin/hadoop classpath)


# spark-config.sh 这里复制出来一个文件然后在最后加上这一句
export JAVA_HOME=/usr/lib/jvm/java-se-8u40-ri/
构建镜像
1
2
# cd切换目录到E:/docker/spark目录
docker build -t hou/spark .

启动

运行镜像

镜像已经构建完成下面开始启动镜像并启动spark

1
2
3
4
5
6
7
8
# 因为要利用hdfs,所以我将它和hadoop放入同一个网段
docker run -dit --name spark-master --net hadoop --hostname spark-master hou/spark

# 进入容器
docker exec -it spark-master /bin/bash

# 进入spark解压目录/usr/local/spark 进入sbin目录运行start-all.sh启动
./start-all.sh
验证
1
2
# 浏览器输入,将ip换成自己对应的ip,spark的web ui端口默认是8080
http://172.19.0.5:8080/

执行第一计算任务

创建一个java的maven空项目

Alt

填写groupid等信息

Alt

配置spark开发jar依赖

需要下载的jar相关依赖很多,可能要等很久看个人网速

1
2
3
4
5
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.12</artifactId>
<version>2.4.5</version>
</dependency>
编写计算任务代码

这里我是写的一个词频统计的

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
package com.hou.test;

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import scala.Tuple2;


import java.util.Arrays;

/**
* @Description
* @auther houwf
* @create 2020-04-29 10:50
*/
public class WordCountJob {
public static void main(String[] args) {
SparkConf conf = new SparkConf().setMaster("local").setAppName("WordCountApp");
JavaSparkContext sc = new JavaSparkContext(conf);
JavaRDD<String> input = sc.textFile("hdfs://172.19.0.2:9000/user/root/learn/madame_bovary");
System.out.println("inputs line:" + input.count());
JavaRDD<String> words = input.flatMap(s -> Arrays.asList(s.split(" ")).iterator());
JavaPairRDD<String, Integer> wordAndOne = words.mapToPair(word -> new Tuple2<>(word, 1));
JavaPairRDD<String, Integer> result = wordAndOne.reduceByKey((a, b) -> a+b);
JavaPairRDD<Integer, String> swap = result.mapToPair(Tuple2::swap);
JavaPairRDD<Integer, String> sorted = swap.sortByKey(false);
JavaPairRDD<String, Integer> sortResult = sorted.mapToPair(Tuple2::swap);
System.out.println("words:" + sortResult.count());
sortResult.saveAsTextFile("hdfs://172.19.0.2:9000/user/root/learn/madame_bovary_word_count");
sc.stop();
}
}
编译打包
1
mvn clean package
复制到spark容器
1
docker cp study.word.count-1.0-SNAPSHOT.jar spark-master:/tmp
提交任务到spark执行

如果没有明显报错信息,就说明执行成功。

1
2
# spark/bin目录下
./spark-submit --class com.hou.test.WordCountJob --master local /tmp/study.word.count-1.0-SNAPSHOT.jar
查看运行结果

在hdfs上查看运行结果,如果看到madame_bovary_word_count目录,点进去如果有结果说明词频统计以完成并将结果写入了HDFS。

Alt