动手搭建docker并在docker容器中建spark集群

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动手搭建docker并在docker容器中建spark集群相关的知识,希望对你有一定的参考价值。

本人亲自测试搭建,由于是初学一路搭建下来走了不少弯路。如有不对或更简洁的步骤请提出
环境: win10上安装的虚拟机,虚拟机装的centos7,并liunx界面化(之前搭建一次在网和端口都可以telnet前提下,就是访问不了docker容器中的服务地址,此次是为了防止宿机不能访问下用虚拟机界面浏览器),centos7的命令和centos6有区别,而且centos7中是没有iptables命令,如要使用自己安装.
本人搭建的 虚拟机ip:192.168.20.129
spark master节点IP: 172.17.0.2 对应docker容器名称cloud1
spark worker节点IP: 172.17.0.3 对应docker容器名称cloud2
spark worker节点IP: 172.17.0.4 对应docker容器名称cloud3

安装docker容器步骤:
1.root权限下命令查看当前内核版本 $uname -r , docker要求CentOS系统内核版本高于3.10
技术分享图片
2.使用root权限登陆Centos,确保yum包更新到最新
命令: yum update
技术分享图片
3.如果有安装旧版本先卸载旧的docker
命令: yum remove docker docker-common docker-selinux docker-engine
4.安装需要的软件包(或叫依赖包)
命令: yum install -y yum-utils device-mapper-persistent-data lvm2
技术分享图片
5.设置yum源
命令: yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
技术分享图片
6.查看仓库中所有docker版本,并选择
命令: yum list docker-ce --showduplicates | sort -r
技术分享图片
7.安装docker
命令: yum install docker-ce #由于repo中默认只开启stable仓库,故这里安装的是最新稳定版17.12.0
命令: yum install <FQPN> # 例如:sudo yum install docker-ce-17.12.0.ce
8.启动并加入开机启动
命令: systemctl start docker
systemctl enable docker
9.检查是否安装成功
命令: docker version
技术分享图片

docker容器里搭建spark集群,这里安装的 hadoop2.7,jdk1.8, spark2.4, scala2.12.8, zookeeper3.4.12
docker容器搭建spark集群步骤:
1.先拉取一个ubuntn到docker中
命令: docker pull ubuntu
如果pull太慢可以配置加速镜像https://www.daocloud.io注册自己的用户,然后在加速页面找到自己的liun加速命令拷贝在liunx执行即可,具体参考网址: http://blog.51cto.com/14159501/2338377
2.下载好的ubuntu到本地后可以查看镜像
命令: docker images
技术分享图片
在centos7中 路径/usr/local下建一个java目录(命令 mkdir java),该目录存放要安装的jdk,spark,scala等安装包,用SSH直接拖到这个目录即可。目录的安装包后面要copy到docker容器中.本人安装完centos7后SSH端口是默认开启的可以用命令 ps -ef|grep ssh查看SSH是否启动(注意:docker 容器中也要安装并自启动SSH,否则在后面启动Hadoop节点时候会有问题,后面建容器时具体讲)
3.运行镜像
命令: docker run --name cloud1 -h cloud1 --add-host cloud1:172.17.0.2 -it ubuntu
运行镜像给起一个cloud1的名称并且分配IP地址为172.17.0.2
技术分享图片
技术分享图片
通过命令: docker network inspect bridge可以看到container中有启动的容器名称以及IP地址
技术分享图片
根据命令 docker inspect 容器名称 |grep IPAddress 查看容器的ip地址
4.配置容器中的SSH
查看SSH状态: service ssh status
如果没有就安装:
apt-get update ---更新
apt install net-tools ----如果ifconfig命令没有安装
apt install iputils-ping ----如果ping命令没有安装
apt-get install vim ----安装vim命令
apt-get install ssh ---安装SSH
安装完成后命令 vim ~/.bashrc 中加入 /usr/sbin/sshd
如果ssh默认配置root无法登陆将 /etc/ssh/sshd_config中PermitRootLogin no改为yes
生成访问密钥
cd ~/ 切换到根目录
ssh-keygen -t rsa -P ‘’ -f ~/.ssh/id_rsa
cd .ssh进入ssh目录
cat id_rsa.pub >> authorized_keys
service ssh start 开启ssh
ssh localhost date 验证是否可以使用SSH
ssh [email protected] 测试是否能连接成功
检查是否安装SSH: which ssh
Which sshd
技术分享图片
查看SSH服务是否启动:
ps aux |grep ssh
技术分享图片
5.在容器 /usr/local 里建一个java目录放置要安装的工具包
在liunx下而不是容器,用命令
docker cp /usr/local/java/ 容器ID:/usr/local/ 这样就把所有java下的安 装工具全部拷贝到容器中了(同一个路径下)。 这里还有一种方式 就是在启动镜像的时候把liunx下的/usr/local/java 目录映射到容器中 命令:docker run -v /usr/local/java/:/usr/local -it ubuntu 或者命令 docker run -i -t -v /usr/local/java:/usr/local/java 镜像ID /bin/bash
6.开始安装 JDK. ZOOKEEPER, SCALA,HADOOP,SPARK
切换目录到 /usr/local/java中,所有的安装包都在这个此目录下
6.1:安装JDK:
命令: tar -xzvf jdk.xx.xx.tar.gz 解压压缩包
赋权: chmod 777 解压后的jdk包
删除压缩包: rm -rf jdk.xx.xx.tar.gz
vim ~/.bashrc添加JDK的参数
export JAVA_HOME=/usr/local/java/jdk1.8.0_191
export PATH=$PATH:$JAVA_HOME/bin
保存退出 命令: source ~/.bashrc 让更改后的文件生效
检查是否安装成功 java -version
技术分享图片

6.2:安装 scala
解压: tar -zxvf scala-2.12.8.tgz
赋权: chmod 777 scala-2.12.8
删除压缩包:rm -rf scala-2.12.8
vim ~/.bashrc 添加scala的参数
export SCALA_HOME=/usr/local/java/scal-2.12.8
export PATH=$PATH:$SCALA_HOME/bin
保存退出 命令 source ~/.bashrc
命令检查安装成功否: scala -version
技术分享图片

6.3:Zookeeper安装
解压: tar -zxvf zookeeper-3.4.12.tar.gz
赋权: chmod 777 zookeeper-3.4.12
删除压缩包: rm -rf zookeeper-3.4.12.tar.gz
vim ~/.bashrc 添加zookeeper的参数
export ZOOKEEPER_HOME=/usr/local/java/zookeeper-3.4.12
export PATH=$PATH:$ZOOKEEPER_HOME/bin
保存退出 命令 source ~/.bashrc
生成zookeeper配置文件
在zookeeper解压包下 zookeeper-3.4.12/conf下执行命令 cp /usr/local/java/zookeeper-3.4.12/conf/zoo_sample.cfg /usr/local/java/zookeeper-3.4.12/conf/zoo.cfg

修改zoo.cfg文件
#数据存储目录修改为:
dataDir=/root/zookeeper/tmp (要先在root下建zookeeper目录,tmp目录 命令: mkdir ~/zookeeper ; mkdir ~/zookeeper/tmp)
#在最后添加Zkserver配置信息:
server.1=cloud1:2888:3888
server.2=cloud2:2888:3888
server.3=cloud3:2888:3888
在 /root/zookeeper/tmp 路径下建文件myid 命令: touch ~/zookeeper/tmp/myid
/root/zookeeper/tmp下执行命令:echo 1 > ~/zookeeper/tmp/myid
打开vim myid 可以看到myid里写入了1
6.4: 安装Hadoop
命令 tar -zxvf Hadoop-2.7.7.tar.gz
vim ~/.bashrc 添加hadoop的参数(命令: vi ~/.bashrc)
export HADOOP_HOME=/usr/local/java/hadoop-2.7.7(根据实际目录填写)
export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin

6.4.1: 修改Hadoop启动配置文件(/usr/local/java/hadoop-2.6.4/etc/hadoop/hadoop-env.sh):
#修改JAVA_HOME
export JAVA_HOE=/usr/local/java/jdk1.8.0_191

6.4.2:配置核心配置文件(/usr/local/java/Hadoop-2.6.4/etc/Hadoop/core-site.xml)
<property>
<name>fs.defaultFS</name>
<value>hdfs://ns1</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/root/hadoop/tmp</value>
</property>
<property>
<name>ha.zookeeper.quorum</name>
<value>cloud1:2181,cloud2:2181,cloud3:2181</value>
</property>

6.4.3: 修改HDFS配置文件(/usr/local/java/Hadoop-2.6.4/etc/Hadoop/hdfs-site.xml)
<property>
<name>dfs.nameservices</name>
<value>ns1</value>
</property>
<property>
<name>dfs.ha.namenodes.ns1</name>
<value>nn1,nn2</value>
</property>
<property>
<name>dfs.namenode.rpc-address.ns1.nn1</name>
<value>cloud1:9000</value>
</property>
<property>
<name>dfs.namenode.http-address.ns1.nn1</name>
<value>cloud1:50070</value>
</property>
<property>
<name>dfs.namenode.rpc-address.ns1.nn2</name>
<value>cloud2:9000</value>
</property>
<property>
<name>dfs.namenode.http-address.ns1.nn2</name>
<value>cloud2:50070</value>
</property>
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://cloud1:8485;cloud2:8485;cloud3:8485/ns1</value>
</property>
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/root/hadoop/journal</value>
</property>
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
<property>
<name>dfs.client.failover.proxy.provider.ns1</name>
<value>
org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider
</value>
</property>
<property>
<name>dfs.ha.fencing.methods</name>
<value>
sshfence
shell(/bin/true)
</value>
</property>
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/root/.ssh/id_rsa</value>
</property>
<property>
<name>dfs.ha.fencing.ssh.connect-timeout</name>
<value>30000</value>
</property>
<property>
<name>dfs.http.address</name>
<value>0.0.0.0:50070</value>
</property>

6.4.4:修改Yarn的配置文件(/usr/local/java/Hadoop-2.6.4/etc/Hadoop/yarn-site.xml)
<property>
<name>yarn.resourcemanager.hostname</name>
<value>cloud1</value>
</property>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>

6.4.5:修改maprep-site.xml 文件(/usr/local/java/Hadoop-2.6.4/etc/Hadoop/maprep-site.xml)
mv mapred-site.xml.template mapred-site.xml

vim mapred-site.xml

<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>

6.4.6:修改指定DataNode和NodeManager的配置文件(/usr/local/java/Hadoop-2.6.4/etc/Hadoop/slaves)
cloud1
cloud2
cloud3

5安装spark
命令 tar -zxvf spark-2.4.0-bin-hadoop2.7.tgz
在宿主机 ~/.bashrc 添加scala的参数(命令: vi ~/.bashrc)
export SPARK_HOME=/usr/local/java/spark-1.6.1-bin-hadoop2.6
export PATH=PATH:$SPARK_HOME/bin:$SPARK_HOME/sbin
spark启动配置文件:
cp /usr/spark-1.6.1-bin-hadoop2.6/conf/spark-env.sh.template /usr/spark-1.6.1-bin-hadoop2.6/conf/spark-env.sh
修改spark-env.sh配置文件内容:
export SPARK_MASTER_IP=cloud1
export SPARK_WORKER_MEMORY=128m
export JAVA_HOME=/usr/local/java/jdk1.8.0_191
export SCALA_HOME=/usr/local/java/scala-2.12.8
export SPARK_HOME=/usr/local/java/spark-1.6.1-hadoop2.6
export HADOOP_CONF_DIR=/usr/local/java/hadoop-2.6.4/etc/hadoop
export SPARK_LIBRARY_PATH=$$SPARK_HOME/lib
export SCALA_LIBRARY_PATH=$SPARK_LIBRARY_PATH
export SPARK_WORKER_CORES=1
export SPARK_WORKER_INSTANCES=1
export SPARK_MASTER_PORT=7077

修改指定Worker的配置文件(/usr/local/java/spark-1.6.1-bin-hadoop2.6/conf/slaves):
cloud1
cloud2
cloud3

集群部署:
1 #提交cloud1容器,命令返回新镜像的编号
2 docker commit cloud1
4 返回一个id
3 #为新镜像打标签为Spark
4 docker tag <mirror id> cloud1
将这个容器commit成一个新的image
然后用这个image运行2个容器,分别是cloud2~cloud3
#-h指定容器运行起来后的hostname
docker run --name cloud2 -h cloud2 --add-host cloud2:172.17.0.3 --add-host cloud3:172.17.0.4 --add-host cloud1:172.17.0.2 -it cloud1
docker run --name cloud3 -h cloud3 --add-host cloud3:172.17.0.4 --add-host cloud1:172.17.0.2 --add-host cloud2:172.17.0.3 -it cloud1...
#在cloud2~cloud3中分别手动修改myid
cloud2中: echo 2 > ~/zookeeper/tmp/myid 打开myid里面就是一个2
cloud3中: echo 3 > ~/zookeeper/tmp/myid 打开myid里面就是一个3

#启动zookeeper集群(分别在cloud1、cloud2、cloud3上启动zk)
~/zookeeper/bin/zkServer.sh start

#使用status查看是否启动(cloud1到cloud3 全部启动才能看到status)
~/zookeeper/bin/zkServer.sh status

#启动journalnode(在cloud1上启动所有journalnode,注意:是调用的hadoop-daemons.sh这个脚本,注意是复数s的那个脚本)
#运行jps命令检验,cloud1、cloud2、cloud3上多了JournalNode进程
~/hadoop/sbin/hadoop-daemon.sh start journalnode ===》每一个cloud中启动
~/hadoop/sbin/hadoop-daemons.sh start journalnode ===》启动的是所有的

#格式化HDFS(在bin目录下),在cloud1上执行命令:
~/hadoop/bin/hdfs namenode -format

#格式化ZK(在cloud1上执行即可,在bin目录下)
~/hadoop/bin/hdfs zkfc -formatZK

#启动HDFS(在cloud1上执行)
~/hadoop/sbin/start-dfs.sh

#在cloud1上执行start-yarn.sh
~/hadoop/sbin/start-yarn.sh

#启动spark集群
~/spark/sbin/start-all.sh
~/spark/sbin/start-master.sh ---启动主节点
~/spark/sbin/slaves.sh --启动所有的worker节点,slave不带s的是单独启用本地worker节点

启动完成后浏览器访问 spark=>cloud1:8080 yarn=>cloud1:8088 hdfs=> cloud1:50070
注意:三个容器 cloud1, cloud2, cloud3 必须要保证SSH是开启的,各个节点之间通讯要用到
保证每一个容器 /etc/hosts 中都有三个节点ip和名称, 必须保证 虚拟机防火墙是关闭的

=========================================================
搭建过程中遇到的解决问题:
安装curl命令:>sudo apt-get install curl
如果安装curl过程中提示“Temporary failure resolving ‘archive.ubuntu.com‘”, 在/etc/resolv.conf 文件中添加 nameserver 202.96.134.133 nameserver 8.8.8.8

如果想在虚拟机中用本地ip访问的化就得从docker容器中映射出端口:
添加端口映射 (来源:https://blog.csdn.net/hp_satan/article/details/77531794)
a, 获取容器ip
docker inspect $container_name | grep IPAddress
b. 添加转发规则
iptables -t nat -A DOCKER -p tcp --dport $host_port -j DNAT --to-destination $docker_ip:$docker_port
123456
删除端口映射规则

a. 获取规则编号
iptables -t nat -nL --line-number
b. 根据编号删除规则
iptables -t nat -D DOCKER $num

[[email protected] ~]# iptables -t nat -A DOCKER -p tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:8080
[[email protected] ~]# iptables -t nat -A DOCKER -p tcp --dport 50070 -j DNAT --to-destination 172.17.0.2:50070

liunx查看进程命令:
查看进程:
1、ps 命令用于查看当前正在运行的进程。
grep 是搜索
例如: ps -ef | grep java
表示查看所有进程里 CMD 是 java 的进程信息
2、ps -aux | grep java
-aux 显示所有状态
ps

  1. kill 命令用于终止进程
    例如: kill -9 [PID]
    -9 表示强迫进程立即停止
    通常用 ps 查看进程 PID ,用 kill 命令终止进程

centos7中关闭防火墙的命令
systemctl stop firewalld.service #停止firewall
systemctl disable firewalld.service #禁止firewall开机启动
firewall-cmd --state #查看默认防火墙状态(关闭后显示notrunning,开启后显示running)
技术分享图片

Docker网络问题:
docker network ls 展现docker的网络连接方式
docker network inspect bridge 此时container中为空的
docker run --name cloud1 -h cloud1 --add-host cloud1:172.17.0.2 -it ubuntu 执行后container里就有cloud1名称了
systemctl restart docker
docker inspect container_name | grep IPAddress 查看容器的ip地址
Docker的Ubuntu镜像安装的容器无ifconfig命令和ping命令
解决:
apt-get update
apt install net-tools # ifconfig
apt install iputils-ping # ping
apt-get install vim命令
从主机复制到容器 docker cp host_path containerID:container_path
从容器复制到主机 docker cp containerID:container_path host_path
技术分享图片
技术分享图片

启动容器
? 启动容器并启动bash(交互方式):
$docker run -i -t <image_name/continar_id> /bin/bash
? 启动容器以后台方式运行(更通用的方式):
$docker run -d -it image_name
ps:这里的 image_name 包含了tag:hello.demo.kdemo:v1.0
docker start 容器ID或容器名 ----》此启动没有交互式
docker run -d -p 80:12345 weba:v0.1(容器名) ----》后台线程启动把主机的80端口和镜像内的12345端口映射在一起
docker run -d -p 80:12345 –name web weba:v0.1(容器名) --?就是把容器名weba:v0.1的改为web
docker attach 容器名或容器ID ?一般生产环境不用此命令,进入一些web服务会一直卡无反应,猜测是监听阻塞进入了
docker exec -it 容器ID /bin/bash 如果 /bin/bash未找到 可以改成: docker exec -it 容器ID sh

? 附着到正在运行的容器
docker attach <id、container_name>
? 进入正在运行的容器内部,同时运行bash(比attach更好用)
docker exec -t -i <id/container_name
docker关于时间问题:
统一两者的时区有下面几种方法
1)共享主机的localtime
创建容器的时候指定启动参数,挂载localtime文件到容器内,保证两者所采用的时区是一致的。

docker run -ti -d --name my-nginx -v /etc/localtime:/etc/localtime:ro docker.io/nginx /bin/bash

2)复制主机的localtime
[[email protected] ~]# docker cp /etc/localtime 87986863838b:/etc/

进入Centos后使用ps -ef | grep docker查看docker进程。
进入Centos后管理docker服务:
service docker start
service docker stop
service docker restart
docker守护进程的配置和操作模式:
docker -d [OPTIONS]
-d 以后台方式运行容器。

查看网络模式:docker network ls
查看docker里容器的IP地址: docker inspect 容器ID | grep IPAddress

使用start命令来启动一个容器:
docker start -a <container id|name>
docker run -it 镜像id /bin/bash
删除一个镜像(我们直接删除某个name,系统只会删除latest标签的那一条记录):
Docker rmi imagesname
我们要从v1升级到v2,首先我们将导入的v2镜像强制重命名为image:latest,命令为docker tag -f image:v2 image:latest
启用docker run image,此时image的等价镜像image:latest就是最新的V2镜像。
删除image
1:先停掉container
命令docker ps -a 查询出容器
停止容器 docker stop 容器id(即:container id)
删除容器 docker rm 容器id(即:container id)
2: 查看当前的images
命令 docker images
3: 删除images
Docker rmi <image Id>

停止所有的container: docker stop $(docker ps -a -p)
删除所有的container: docker rm $(docker ps -a -p)
删除全部image: docker rmi $(docker images -q)
技术分享图片
运行镜像(镜像id),并将宿主机/opt/soft目录挂载到容器的/opt/soft上 :
docker run -i -t -v /opt/soft/:/opt/soft/ 9b9cb95443b5 /bin/bash
(docker run -i -t -v 宿主机文件目录 : 容器文件目录 镜像id /bin/bash)
例如:
技术分享图片

如果bashrc中配置错误 ,ls,ll所有命令不好使的情况下用命令: 在命令行中输入:export PATH=/usr/bin:/usr/sbin:/bin:/sbin:/usr/X11R6/bin 这样可以保证命令行命令暂时可以使用。

以上是关于动手搭建docker并在docker容器中建spark集群的主要内容,如果未能解决你的问题,请参考以下文章

docker下安装centos,并在其上搭建lnmp环境

物理机centos6上使用docker创建centos7容器并在容器中使用KVM搭建win10系统

Docker 十分钟动手教程

docker 私有镜像服务器搭建

《自己动手写Docker》pdf

动手玩转Docker