docker是一个轻量化部署工具,相比虚拟机,Docker构建部署包更小,启动更快速,占用资源更少。
接下来,我们考虑在单机上创建5个Docker容器,包括一个master容器和四个slave容器,容器之间相互隔离,通过加入创建的Docker虚拟网络hadoop_network实现网络互联。
下载与安装
地址:https://hub.docker.com/editions/community/docker-ce-desktop-mac
构建JDK镜像
我们考虑直接下载Docker hub上的Ubuntu系统来编写镜像。
我们创建一个镜像目录image_jdk,下载的jdk文件放到该目录下,然后在目录中编写两个文件build.sh和Dockerfile:
#build.sh
Docker image build -t centos_jdk:1.0 .
#Dockerfile
#初始镜像继承centos
FROM centos:centos7.7.1908
#镜像维护者信息
MAINTAINER wenhuan
#构建容器命令
#安装openssh-server、openssh-clients、sudo、vim和net-tools软件包
RUN yum -y install openssh-server openssh-clients sudo vim net-tools
#设置密码
RUN echo "root:wenhuan" | chpasswd
#生成相应的主机密钥文件【rsa、ecdsa、ed25519都是算法名称】
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
RUN ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key
RUN ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key
#将JDK文件放到镜像/opt目录下,ADD命令会自动解压。
ADD ./jdk-8u181-linux-x64.tar.gz /opt/
#重命名解压后的JDK文件目录
RUN mv /opt/jdk1.8.0_181 /opt/java
#创建环境变量
ENV JAVA_HOME /opt/java
ENV JRE_HOME ${JAVA_HOME}/jre
ENV CLASSPATH .:${JAVA_HOME}/lib:${JRE_HOME}/lib
ENV PATH $PATH:$JAVA_HOME/bin
之后执行以下命令即构建了centos_jdk1.0,至此JDK镜像构建成功:
sh build.sh
构建Hadoop镜像
先创建一个镜像目录image_hadoop, 下载hadoop压缩包和解压后的安装包放到image_hadoop目录下,编写构建命令,保存到build.sh:
Docker image build -t cluster_hadoop:1.0 .
编辑hadoop-env.sh文件如下:
export JAVA_HOME=/opt/java
export HADOOP_CONF_DIR=/opt/hadoop/etc/hadoop
编辑core-site.xml文件如下:
<configuration>
<property>
<!--hadoop临时目录-->
<name>hadoop.tmp.dir</name>
<value>file:/data/hadoop/tmp</value>
<description>默认存在/tmp目录</description>
</property>
<property>
<!--HDFS NameNode地址-->
<name>fs.defaultFS</name>
<value>hdfs://master:9000</value>
<description>指定hdfs的主节点</description>
</property>
</configuration>
编辑hdfs-site.xml文件如下:
<configuration>
<property>
<!--HDFS副本数-->
<name>dfs.replication</name>
<value>2</value>
<description>指定hdfs的副本数</description>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>file:/home/hadoop/hadoop/tmp/dfs/name</value>
<description>指定namenode数据的目录</description>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>file:/home/hadoop/hadoop/tmp/dfs/data</value>
<description>指定datanode数据的目录</description>
</property>
<property>
<name>dfs.namenode.secondary.http-address</name>
<value>master:9001</value>
<description>指定secondarynamenode的节点</description>
</property>
<property>
<name>dfs.permissions</name>
<value>false</value>
<description>任何人都可以hdfs上操作文件</description>
</property>
</configuration>
编辑mapred-site.xml文件如下:
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
<description>指定MapReduce运行在yarn上</description>
</property>
<property>
<name>mapreduce.jobhistory.address</name>
<value>master:10020</value>
<description>任务历史服务器地址</description>
</property>
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>master:19888</value>
<description>任务历史服务器web-ui地址</description>
</property>
</configuration>
编辑yarn-site.xml文件如下:
<configuration>
<property>
<name>yarn.resourcemanager.hostname</name>
<value>master</value>
<description>指定yarn的主节点</description>
</property>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
<description>允许MapReduce运行在yarn上</description>
</property>
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value>
</property>
<property>
<name>yarn.log-aggregation.retain-seconds</name>
<value>604800</value>
</property>
</configuration>
编辑slaves文件,填写从属节点的主机名:
slave1
slave2
slave3
slave4
编写Dockerfile文件:
#继承之前构建的镜像
FROM centos_jdk:1.0
#将Hadoop包复制到镜像中
ADD hadoop-2.7.7.tar.gz /opt/
RUN mv /opt/hadoop-2.7.7 /opt/hadoop
#将本地的配置文件复制到镜像中并覆盖对应的文件
COPY hadoop/etc/hadoop/hadoop-env.sh /opt/hadoop/etc/hadoop
COPY hadoop/etc/hadoop/core-site.xml /opt/hadoop/etc/hadoop
COPY hadoop/etc/hadoop/hdfs-site.xml /opt/hadoop/etc/hadoop
COPY hadoop/etc/hadoop/mapred-site.xml /opt/hadoop/etc/hadoop
COPY hadoop/etc/hadoop/yarn-site.xml /opt/hadoop/etc/hadoop
COPY hadoop/etc/hadoop/slaves /opt/hadoop/etc/hadoop
ENV HADOOP_HOME /opt/hadoop
ENV HADOOP_INSTALL=$HADOOP_HOME
ENV HADOOP_MAPRED_HOME=$HADOOP_HOME
ENV HADOOP_COMMON_HOME=$HADOOP_HOME
ENV HADOOP_HDFS_HOME=$HADOOP_HOME
ENV YARN_HOME=$HADOOP_HOME
ENV PATH ${HADOOP_HOME}/bin:${HADOOP_HOME}/sbin:$PATH
EXPOSE 22
ENV HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_HOME/lib/native
执行build.sh构建镜像。
构建Hive镜像
先创建一个镜像目录image_hive, 下载Hive压缩包和解压后的安装包放到image_hive目录下,编写构建命令,保存到build.sh:
Docker image build -t cluster_hive:1.0 .
编写Docker文件:
#继承之前的镜像
FROM cluster_hadoop:1.0
#复制hive文件到镜像/opt目录下
ADD apache-hive-1.2.2-bin.tar.gz /opt
#修改镜像hive目录名称,创建/opt/data及以下目录
RUN mv /opt/apache-hive-1.2.2-bin/ /opt/hive/ && mkdir -p /opt/data/hive_resources /opt/data/hive && chmod 666 /opt/data/hive
#声明环境变量
ENV HIVE_HOME /opt/hive
ENV PATH ${HIVE_HOME}/bin:$PATH
#目录切换到/opt/hive/conf
WORKDIR /opt/hive/conf
RUN mv hive-default.xml.template hive-site.xml && mv hive-log4j.properties.template hive-log4j.properties
#sed替换hive-site.xml的配置项
RUN sed -i "s?\${system:java.io.tmpdir}?/opt/data?g" hive-site.xml &&
sed -i "s?\${system:user.name}?hive?g" hive-site.xml
RUN cp -r /opt/hive/lib/jline-2.12.jar /opt/hadoop/share/hadoop/yarn/lib
执行build.sh构建镜像。
构建Spark镜像
先创建一个镜像目录image_spark, 下载Spark压缩包和解压后的安装包放到image_spark目录下,编写构建命令,保存到build.sh:
Docker image build -t cluster_spark:1.0 .
spark解压包更名为spark, 在spark/conf/目录下找到文件spark-env.sh.template改名为spark-env.sh,并打开文件,在末尾追加一行:
export SPARK_DIST_CLASSPATH=$(${HADOOP_HOME}/bin/hadoop classpath)
这样,spark才能共享hadoop的hdfs等组件。
在spark/conf/目录下找到文件slaves.template改名为slaves,并编辑:
slave1
slave2
slave3
slave4
接下来编写Docker文件:
#继承之前的镜像
FROM cluster_hive:1.0
#复制spark文件到镜像/opt目录下
ADD spark-2.4.6-bin-hadoop2.7.tgz /opt
#修改镜像spark目录名称
RUN mv /opt/spark-2.4.6-bin-hadoop2.7/ /opt/spark/
#将本地的配置文件复制到镜像中并覆盖对应的文件
COPY spark/conf/spark-env.sh /opt/spark/conf/spark-env.sh
#声明环境变量
ENV SPARK_HOME /opt/spark
ENV PATH ${SPARK_HOME}/bin:$PATH
WORKDIR /opt
#运行容器,启动SSH服务
CMD ["sh","-c","service ssh start; bash"]
执行build.sh构建镜像。
配置集群网络
输入以下命令可以查看当前docker的网络:
docker network ls
返回结果如下:
NETWORK ID NAME DRIVER SCOPE
d0b83392d44a bridge bridge local
a7ee8fd045f8 host host local
1c9ccc5dc18a none null local
如果不做任何网络配置的情况下,容器默认使用bridge方式连接网络,这样容器每次重启后,IP都会发生变动。
我们先查看一下默认bridge这个网络的信息:
docker network inspect d0b83392d44a
可以看到返回一段信息:
......
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
......
可以看到docker默认使用的是一个B类段段子网IP,接下来我们配置一个名为hadoop_network的子网,给它分配一个C类段的子网:
docker network create --subnet=172.22.0.0/24 hadoop_network
启动集群
接下来编写一个启动集群的脚本start.sh:
#!/usr/bin/env bash
#自定义网络名称
NETWORK_NAME=hadoop_network
#自定义镜像网络名称
IMAGE_ID=405d71c96bca
sudo Docker rm -f master &> /dev/null
echo "start master container..."
sudo Docker run -itd --name master --hostname master --net ${NETWORK_NAME} --ip 172.22.0.2 -P -p 50070:50070 -p 8088:8088 -p 7077:7077 --privileged=true ${IMAGE_ID} /usr/sbin/init
i=1
while [ $i -lt 5 ]
do
sudo Docker rm -f slave$i &> /dev/null
echo "start slave$i container..."
sudo Docker run -itd --name slave$i --hostname slave$i --net ${NETWORK_NAME} --ip 172.22.0.$[$i+2] -P --privileged=true ${IMAGE_ID} /usr/sbin/init
i=$(($i + 1))
done
sudo Docker exec -it master bash
执行以上脚本,创建基于同一份镜像的5个容器后,依次进入5个节点,修改etc/hosts文件配置IP映射:
172.22.0.2 master
172.22.0.3 slave1
172.22.0.4 slave2
172.22.0.5 slave3
172.22.0.6 slave4
接下来,把每个节点的公钥传送给其他节点:
ssh-copy-id -i ~/.ssh/id_rsa.pub master
ssh-copy-id -i ~/.ssh/id_rsa.pub slave1
ssh-copy-id -i ~/.ssh/id_rsa.pub slave2
ssh-copy-id -i ~/.ssh/id_rsa.pub slave3
ssh-copy-id -i ~/.ssh/id_rsa.pub slave4
之后输入以下命令:
start-dfs.sh
start-yarn.sh
mr-jobhistory-daemon.sh start historyserver