全民数据科学, 亲切地称为"深色"或"斯波克"
> Fully distributed Spark cluster running inside of Docker containers
介绍
在过去的几年中,已经流行的两种技术是Apache Spark和Docker。
Apache Spark为用户提供了一种以分布式方式执行CPU密集型任务的方法。 与Hadoop等其他分布式技术相比,由于采用这种技术的速度,最近几年该技术的采用一直在稳定增长。 2014年,Spark赢得了"灰色排序基准"测试,该测试中,他们使用比Hadoop集群少10倍的机器,对100TB数据的整理速度提高了3倍。
另一方面,Docker已在各种情况下得到广泛采用。 Docker为用户提供了定义最小规格环境的能力,这意味着您可以轻松地开发,交付和扩展应用程序。 此外,由于使用Linux容器,用户能够开发Docker容器,这些容器可以在单个服务器上同时运行,而又彼此隔离。 最后,Docker提供了一个称为Docker Engine的抽象层,该层保证了可以运行Docker的计算机之间的兼容性,从而解决了"它在我的计算机上工作,但我不知道为什么它在您的计算机上不起作用"这一古老的难题。
随着大数据的兴起,这两种技术是天作之合。 Apache Spark提供分析引擎以减少数量,而Docker提供快速,可扩展的部署以及一致的环境。
先决条件
我假设了解Docker命令和术语以及Apache Spark概念。 因此,如果您不熟悉这两种技术,那么我不建议您使用本文。 考虑到简洁性,本文将有意省略掉正在发生的事情的许多细节。 有关该体系结构的完整描述以及该过程的更连续的逐步介绍,我将读者定向到我的github存储库。
我还假定您至少具有云提供商的基本经验,因此能够在您喜欢的平台上设置计算实例。
本文的其余部分将直截了当地介绍各种级别的体系结构复杂性:
· Docker容器网络-本地计算机
· Docker容器网络-多台机器
· Apache Spark集群-本地计算机
· Docker&Spark —本地计算机
· Docker&Spark —多台机器
· 奖励:Docker Stack和Spark
让我们开始吧!
Docker —本地计算机
首先,我们需要掌握一些基本的Docker网络。 我们将首先在同一台计算机上运行的容器中执行此操作。
· 首先要做的是要么使用我的仓库中的Dockerfile来构建Docker镜像,要么更方便地使用以下命令提取Docker镜像
docker pull sdesilva26/spark_master:0.0.2
docker pull sdesilva26/spark_worker:0.0.2
注意:就本节而言,任何图像都可以。
2.通过运行创建网桥网络
docker network create --driver bridge spark-net-bridge
3.通过运行以下命令,在此用户定义的桥网络上运行两个容器
docker run -dit --name spark-master --network spark-net-bridge --entrypoint /bin/bash sdesilva26/spark_master:0.0.2
docker run -dit --name spark-worker1 --network spark-net-bridge --entrypoint /bin/bash sdesilva26/spark_worker:0.0.2
4.检查网络并找到两个容器的IP地址
docker network inspect spark-net-bridge
上面的输出应如下图所示
5.附加到spark-master容器,并使用其IP地址和容器名称测试其与spark-worker容器的通信
ping -c 2 172.24.0.3
ping -c 2 spark-worker
由于这些容器已部署到同一Docker桥接网络中,因此它们能够使用该容器的名称来解析其他容器的IP地址。 这称为自动服务发现,将在以后对我们有很大的帮助。
架构
使用以上命令,我们创建了以下架构。
Docker —多台机器
1.继续并在您喜欢的云提供商上设置2个实例
2.在配置实例的网络时,请确保将其部署到同一子网中
3.打开以下端口以使容器彼此通信并覆盖网络流量(入站和出站);
Protocol | Port(s) | SourceTCP | 2377 |
TCP | 7946 |
UDP | 7946 |
UDP | 4789 |
4.为该实例打开以下端口,以与Docker Hub通信(入站和出站);
Protocol | Port(s) | SourceHTTPS | 443 | 0.0.0/0, ::/0
例如,在AWS上,部署了两个实例的我的安全组具有以下安全组设置
其中" sg-0140fc8be109d6ecf(docker-spark-tutorial)"是安全组本身的名称,因此只有来自网络内部的流量才能使用端口2377、7946和4789进行通信。
5.安装docker。
sudo yum install docker -ysudo service docker startsudo usermod -a -G docker ec2-user # This avoids you having to use sudo everytime you use a docker command (log out and then in to your instance for this to take affect)
6.在实例1上,拉出您选择的docker映像。
docker pull sdesilva26/spark_master:0.0.2
7.将另一个图像拉到实例2上。
docker pull sdesilva26/spark_worker:0.0.2
8.初始化docker swarm,并通过运行将实例1设置为swarm管理器
docker swarm init
在实例1上。
9.从实例1复制上面命令的输出,然后在实例2上运行它,以将swarm作为工作节点加入
10.在实例1(群管理器)上创建一个覆盖网络
docker network create -d overlay --attachable spark-net
11.在实例1上,运行一个容器
docker run -it --name spark-master --network spark-net --entrypoint /bin/bash sdesilva26/spark_master:0.0.2
12.在实例2上,在由群管理器创建的覆盖网络内运行一个容器
docker run -it --name spark-worker --network spark-net --entrypoint /bin/bash sdesilva26/spark_worker:0.0.2
13.从实例2的容器内部,通过ping在实例1上运行的容器来检查容器通信
ping -c 2 spark-master
14.同样,检查从实例1的容器到实例2的容器的向后连接
ping -c 2 spark-worker
与以前一样,由于容器位于同一个覆盖网络中,因此它们只能使用容器名称来解析彼此的IP地址。
架构
按照上面的说明进行操作之后,您创建了与下面类似的体系结构。
Apache Spark —本地计算机
现在我们已经掌握了如何使两个不同的Docker主机进行通信的方法,我们将开始在本地计算机上创建Spark集群。
1.从他们的网站安装Spark
2.从命令行导航到Spark安装的bin目录
3.设置Spark主节点
./spark-class org.apache.spark.deploy.master.Master
4.通过导航到http:// localhost:8080,检查主节点是否已成功部署。 您应该看到以下内容
5.将工作程序节点附加到集群
./spark-class org.apache.spark.deployerer -c 1 -m 3G spark://localhost:7077
这两个标志定义了您希望该工作人员拥有的核心和内存量。 最后一个输入是前缀为" spark://"的主节点的地址和端口,因为我们使用的是Spark的独立集群管理器
6.通过返回http:// localhost:8080,检查辅助服务器是否已成功在主节点上注册。 现在,您应该将工作程序节点视为集群的资源。 (您也可以通过访问http:// localhost:8081来检查工作程序的UI)
7.通过从spark安装的bin目录中打开一个scala shell来测试集群。
./spark-shell --master spark://localhost:7077
并运行
val NUM_SAMPLES=10000var count=sc.parallelize(1 to NUM_SAMPLES).filter { _=> val x=math.random
val y=math.random xx + yy < 1}.count() * 4/(NUM_SAMPLES.toFloat)
这将返回pi的估计值。
8.转到http:// localhost:4040,检查应用程序的UI。 您应该看到类似的内容
您现在拥有功能齐全的Spark集群!
Spark&Docker —本地计算机
现在是时候将两者捆绑在一起了。 现在,我们将通过在本地计算机上的Docker容器内运行运行的Spark集群来学习运行前的行走
1.创建用户定义的网桥网络(如果尚未创建)
docker create network -d bridge spark-net
2.在网桥网络内部创建一个Spark主节点
docker run -it --name spark-master --network spark-net -p 8080:8080 sdesilva26/spark_master:0.0.2 bash
3.通过导航到http:// localhost:8080,检查容器是否已成功启动学历证书Spark主节点。 我已将sdesilva26 / spark_master:0.0.2映像设置为默认情况下设置主节点。 请参阅dockerfile。
4.在网桥网络内部创建一个Spark worker节点
docker run -dit --name spark-worker1 --network spark-net -p 8081:8081 -e MEMORY=2G -e CORES=1 sdesilva26/spark_worker:0.0.2 bash
默认情况下,sdesilva26 / spark_worker:0.0.2映像在运行时将尝试通过主节点位于spark:// spark-master:7077来加入一个Spark集群。
如果更改运行Spark主节点的容器的名称(步骤2),则需要将此容器名称传递给上述命令,例如 -e 。 在这里查看dockerfile。
5.同样,通过导航到http:// localhost:8080和http:// localhost:8081,验证工作服务器已成功在主节点上注册。
6.将第二个Spark Worker附加到集群
docker run -dit --name spark-worker2 --network spark-net -p 8082:8081 -e MEMORY=2G -e CORES=1 sdesilva26/spark_worker:0.0.2 bash
我们必须对步骤4中的命令进行的唯一更改是,我们必须为容器指定一个唯一的名称,并且还必须将容器的端口8081映射到本地计算机的端口8082,因为spark-worker1容器已经存在 使用本地计算机端口8081。
7.启动一个Spark提交节点
docker run -it --name spark-submit --network spark-net -p 4040:4040 sdesilva26/spark_submit bash
您现在应该在spark-submit容器中。
8.打开一个scala shell并连接到Spark集群
$SPARK_HOME/bin/spark-shell --conf spark.executormory=2G --conf spark.executor.cores=1 --master spark://spark-master:7077
和以前一样,如果运行Spark主节点的容器的名称与spark-master不同,则可以使用— master spark:// :7077更改上述命令。
上面的命令还要求在您的群集上,您希望每个执行程序包含2G内存和1个内核。 Spark主节点将分配这些执行程序,前提是每个工作程序上都有足够的可用资源来允许执行此操作。 有关执行者和工人的说明,请参见以下文章。
9.在交互式scala shell中运行示例作业
val myRange=spark.range(10000).toDF(“number”)val divisBy2=myRange.where(“number % 2=0”)divisBy2.count()
10.通过导航到http:// localhost:4040来检查应用程序UI。 您应该看到以下内容
您刚刚在Docker容器中运行了Spark作业。 Spocker出生了!
架构
上面我们所做的是在Docker中创建了一个网络,我们可以在其中部署容器,并且它们可以彼此自由通信。
下图中的白色箭头表示容器之间的开放式通信。 容器上的端口以绿色显示,本地计算机的端口以黄色显示。
您可以看到所有容器都已部署在网桥网络中。 如果我们现在在该网络外部部署一个容器,则仅使用它们的容器名称就无法解析其他容器的IP地址。
Docker和Spark —多台机器
现在,将所有内容包装在一起,以形成在Docker容器内部运行的完全分布式的Spark集群。
注意:对于这一部分,您将需要使用我创建的3张图像。
docker pull sdesilva26/spark_master:0.0.2docker pull sdesilva26/spark_worker:0.0.2docker pull sdesilva26/spark_submit:0.0.2
您还可以通过下载Dockerfile自己构建它们
1.在您选择的云提供商上启动实例,并使其成为docker swarm manager
docker swarm init
2.复制以上命令的输出并将其粘贴到至少两个其他实例。 我在其他4个实例上执行了此操作-3个将充当Spark工作者,而1个将成为我的Spark提交节点
3.在实例1上,像以前一样创建一个覆盖网络
docker network create -d overlay --attachable spark-net
4.运行spark_master映像以创建将成为Spark主节点的容器
docker run -it --name spark-master --network spark-net -p 8080:8080 sdesilva26/spark_master:0.0.2
5.通过将以下内容添加到安全组的入站规则中,打开端口8080–8090和4040
Protocol | Port(s) | Source Custom
TCP | 8080-8090 | 0.0.0/0 Custom
TCP | 4040 | 0.0.0/0, ::/0
注意:在AWS安全组中,安全组是有状态的,因此自动允许从实例到用户的返回流量,因此您无需修改安全组的出站规则。 在其他云提供商上,您可能必须向出站规则添加类似的规则。
我的入站安全组规则现在看起来像这样
6.在http:// :8080中检查Spark主节点UI。 您应该看到与之前相同的UI。
7.现在,在您的另一个实例上,运行以下命令将Spark worker节点附加到集群
docker run -it --name spark-worker1 --network spark-net -p 8081:8081 -e MEMORY=6G -e CORES=3 sdesilva26/spark_worker:0.0.2
注意:通常,以内存=实例1GB的内存,核心=实例的核心-1的方式启动Spark工作程序节点。这将为实例OS留下1个内核和1GB的内存,以执行后台任务。
8.再次检查主节点的Web UI,以确保成功添加了工作进程。
9.冲洗并重复步骤7,以根据需要添加任意数量的Spark工人。 确保将容器的名称从spark-worker1增加到spark-worker2,依此类推。
我已经连接了3个工作人员,而我的主节点的网络用户界面如下
10.在另一个实例中,启动一个Spark提交节点
docker run -it --name spark-submit --network spark-net -p 4040:4040 sdesilva26/spark_submit:0.0.2 bash
11.启动pyspark交互式shell并连接到集群
$SPARK_HOME/bin/pyspark --conf spark.executormory=5G --conf spark.executor.cores=3 --master spark://spark-master:7077
注意:您可以使用— conf标志指定将应用程序连接到群集时希望每个执行者拥有的资源。 Spark调整的主题本身就是一整篇文章,因此在这里我将不做任何详细介绍。 我发现这两部分Cloudera博客文章是了解资源分配的好资源:第1部分和第2部分。也是C2FO的Anthony Shipman的博客文章,我发现非常有用,并且还包括一个方便的Excel工作表来进行设置 用于内存,内核和并行化。
12.通过同时检查Spark主节点的UI和Spark提交节点的UI,检查提交节点已成功连接到集群。 它们看起来应如下图所示。
13.从pyspark shell运行示例作业
from random import random
def inside§:
x, y=random(), random()
return xx + yy < 1NUM_SAMPLES=100000
count=sc.parallelize(range(0, NUM_SAMPLES)).filter(inside).count()
print(“Pi is roughly {:0.4f}”.format(4.0 * count / NUM_SAMPLES))
将作业提交到Spark集群的更常见方法是使用Spark安装中随附的spark-submit脚本。 让我们也这样做。
14.退出pyspark并将程序提交给集群上的执行者
$SPARK_HOME/bin/spark-submit --conf spark.executor.cores=3 --conf spark.executormory=5G --master spark://spark-master:7077 $SPARK_HOME/examples/src/main/python/pi.py 20
它的语法几乎与以前相同,只是我们调用了spark-submit脚本,并将其传递给.py文件以及其他要执行的配置。
快乐的时光! 现在,我们已经创建了一个在Docker容器内部运行的完全分布式Spark集群,并将应用程序提交给了该集群。
架构
我们刚刚创建的架构如下所示
每个Spark辅助节点和主节点都在位于其自己的计算实例上的Docker容器内运行。 Spark驱动程序节点(Spark提交节点)也位于在单独实例上运行的自己的容器内。 在这种情况下,所有Docker守护程序都通过覆盖网络连接,Spark主节点是Docker群管理器。
在覆盖网络中,容器可以通过引用利用自动服务发现的容器名称来轻松解析彼此的地址。
如果需要,可以在其他实例上启动更多Spark辅助节点。
欢迎来到终点线!
> Photo by Jonathan Chng on Unsplash
结论
在本教程中,我们成功地逐步解决了设置在Docker容器内部运行的Spark集群的各种复杂程度。
我们首先从一些简单的Docker网络原理开始,在我们使用桥接网络的本地机器上,然后在使用带有docker swarm的覆盖网络的分布式机器上。
接下来,我们在本地计算机上运行一个Spark集群,以设法在集群中添加工作程序。
然后,我们将Docker重新引入了混合环境,并在本地计算机上的Docker容器内部运行了一个Spark集群。
最后,我们将所有内容组合在一起,以构建在Docker容器中运行的完全分布式Spark集群。
希望您对这两种技术如何结合在一起有清楚的了解,并且可以为您的特定问题或项目带来好处。
现在是您开始尝试并了解使用该体系结构可以学到什么的时候了。
请享用!
奖金
上面手动创建集群的步骤比实际更具信息性,因为它需要大量的手动键入和重复的命令。
对于仅需要4或5个计算实例资源的小问题,此工作量可能低于您的痛苦阈值。
但是,随着数据真正变大并且所需的计算能力开始增加,按照上述步骤进行操作将使您成为全职集群创建者。
建立集群的一种更实用,更优雅的方法是利用Docker compose
Docker Compose
对于那些刚接触Docker compose的人,它使您可以启动所谓的"服务"。
服务由单个Docker映像组成,但是您可能希望运行该映像的多个容器。 例如,从docker镜像sdesilva26 / spark_worker:0.0.2运行多个Spark worker容器将构成一个服务。
要启动一组服务,请创建一个docker-compose.yml文件,该文件指定有关您要运行的各种服务的所有内容。
但是,Docker compose用于创建在单个主机上运行的服务。 它不支持跨主机部署容器。
输入Docker堆栈。
Docker堆栈是对Docker compose的简单扩展。 现在,您不必在单个主机上运行服务,而是可以在作为Docker群连接的多个主机上运行服务。
最好的是,如果您有Docker撰写文件,则只需进行很少的修改即可使其与Docker堆栈命令一起使用。
让我们看看如何使用撰写文件和Docker堆栈创建在Docker容器内运行的分布式Spark集群。
1.第一步是标记Docker群中的节点。 从Docker群管理器中,列出群中的节点。
docker node ls
您应该获得与下图类似的输出。
2.对于希望成为Spark工作者的任何实例,请为其添加标签
docker node update --label-add role=worker x5kmfd8akvvtnsfvmxybcjb8w
3.现在,使用主角色将要运行Spark主节点的实例标记为
docker node update --label-add role=master
4.创建一个docker-compose.yml文件或拉出我创建的文件。
在此撰写文件中,我定义了两个服务-spark-master和spark-worker。
第一项服务将单个容器部署到群集中任何标签为" role=master"的节点上。
第二个服务将sdesilva26 / spark_worker:0.0.2映像的3个容器部署到标签为" role=worker"的节点上。 如果在群集中找不到3个合适的节点,它将部署尽可能多的节点。
最后,所有这些容器将部署到一个名为spark-net的覆盖网络中,该网络将为我们创建。
5.将docker-compose.yml复制到集群管理器实例中。
scp -i .pem /path/to/docker-compose.yml ec2-user@:/home/ec2-user/docker-compose.yml
[查看此处的其他替代方法]
6.最后,从群组管理器运行您的Docker堆栈并为其命名。
docker stack deploy --compose-file docker-compose.yml sparkdemo
注意:您的堆栈名称将放在所有服务名称之前。 因此,服务" spark-master"变为" sparkdemo_spark-master"。 您可以通过使用以下命令检查正在运行的服务
docker service ls
7.检查spark_worker映像是否在标记为" worker"的实例上运行,并且spark_master映像在标记为" master"的节点上运行。
恭喜,我们已经将本文中的所有工作简化为Docker swarm Manager中的一些命令。
Docker服务最好的一点是,扩展非常容易。 例如,如果稍后我们在Docker群中添加了另一个实例,然后希望扩展" sparkdemo_spark-worker"服务,则只需运行
docker service scale sparkdemo_spark-worker=4
现在您的集群中有4个Spark Worker!
Docker FTW。
> Photo by J E W E L M I T CH E L L on Unsplash
共同学习,写下你的评论
评论加载中...
作者其他优质文章