# Docker 部署 Hadoop 集群

# 前言

服务器/虚拟机至少4G内存,本文制作的 Hadoop 镜像: Java 1.8、Hadoop 2.9.2 。

# 一、制作 Hadoop 镜像

获取 CentOS 镜像 要求该 CentOS 镜像安装 SSH,已经制作好了,直接下载即可

docker pull ryaning/centos-ssh
1

构建 Hadoop 镜像 编辑 Dockerfile

vi Dockerfile
1

新增以下内容

# 基础镜像
FROM ryaning/centos-ssh
# 作者
MAINTAINER  Ryan <me@ryana.cn>
# 构建镜像
ADD jdk-8u162-linux-x64.tar.gz /usr/local/
RUN mv /usr/local/jdk1.8.0_162 /usr/local/jdk1.8
ENV JAVA_HOME /usr/local/jdk1.8
ENV PATH $JAVA_HOME/bin:$PATH

ADD hadoop-2.9.2.tar.gz /usr/local
RUN mv /usr/local/hadoop-2.9.2 /usr/local/hadoop
ENV HADOOP_HOME /usr/local/hadoop
ENV PATH $HADOOP_HOME/bin:$PATH

RUN yum install -y which sudo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

基于 centos-ssh 镜像,把 Java 和 Hadoop 的环境都配置好,构建成 Docker Hadoop 镜像。

构建镜像(不推荐)

docker build -t ryaning/hadoop .
1

或者直接下载已经构建好的镜像(推荐)

docker pull ryaning/hadoop
1

# 二、搭建 Hadoop 分布式集群

# 规划

准备搭建一个具有三个节点的集群,一主两从

  • 主节点:hadoop0 ip:192.168.10.10
  • 从节点1:hadoop1 ip:192.168.10.11
  • 从节点2:hadoop2 ip:192.168.10.12

# 配置 IP

docker 容器在启动时默认使用的是 bridge 模式,docker 容器启动后,会连接到一个名为 docker0 的虚拟网桥,故每次启动 docker 容器的 IP 都不是固定的,不方便管理,有时候需要进行固定 IP 映射,比如 docker 集群管理时。docker 在 1.9 版本版后,提供了创建自定义网络功能命令。

# 创建自定义网络 

# ip段为:192.168.10.1/24,名字为:hadoop
docker network create --subnet=192.168.10.1/24 hadoop
# 显示自定义网络列表
docker network ls
1
2
3
4
5
6

# 运行

运行3个 hadoop 容器,分别命名为 hadoop0,hadoop1,hadoop2,其中 hadoop0 作为 master, 并且映射了端口号,50070 和 8088,用来在浏览器中访问 hadoop WEB 界面的。

命令说明:

  • -e TZ="Asia/Shanghai" 增加环境变量,指定时区
  • -v /etc/localtime:/etc/localtime:ro:挂载系统时间到容器内
  • --net hadoop --ip 192.168.10.10:配置 Hadoop 集群节点的固定 IP
  • --add-host hadoop1:192.168.10.11:除了需要配置好 Hadoop 集群节点的固定 IP 外,还需要修改 Hadoop 容器内部的 hosts 文件,设置主机名与 ip 的映射。在 docker 中直接修改 /etc/hosts 文件,在重启容器后会被重置、覆盖。因此需要通过容器启动脚本 docker run 的 --add-host 参数将主机和 ip 地址的对应关系传入,容器在启动后会写入 hosts 文件中。
# hadoop0
docker run --name hadoop0 \
--hostname hadoop0 \
--net hadoop --ip 192.168.10.10 \
--add-host hadoop1:192.168.10.11 \
--add-host hadoop2:192.168.10.12 \
-p 50070:50070 \
-p 50010:50010 \
-p 50075:50075 \
-p 9000:9000 \
-p 8088:8088 \
-p 2222:22 \
-d -P ryaning/hadoop

# hadoop1
docker run --name hadoop1 \
--hostname hadoop1 \
--net hadoop --ip 192.168.10.11 \
--add-host hadoop0:192.168.10.10 \
--add-host hadoop2:192.168.10.12 \
-d -P ryaning/hadoop

# hadoop2
docker run --name hadoop2 \
--hostname hadoop2 \
--net hadoop --ip 192.168.10.12 \
--add-host hadoop0:192.168.10.10 \
--add-host hadoop1:192.168.10.11 \
-d -P ryaning/hadoop
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

# 设置 SSH 免密码登录

前面已经为容器配置 IP 了,在进行 ssh 时需要输入要登陆的容器的 root 密码,Hadoop 集群要求集群间机器 SSH 连接时无密码登陆,下面讲述容器间如何配置 SSH 无密码登陆。

以 hadoop0 容器为例,hadoop1、hadoop2 容器同样需要修改。

进入 hadoop0 容器内

docker exec -it hadoop0 bash
1

执行后会有多个输入提示,不用输入任何内容,全部直接回车即可

ssh-keygen
1

执行命令后需要输入登录密码,默认为 123456

ssh-copy-id -i /root/.ssh/id_rsa -p 22 root@hadoop0
ssh-copy-id -i /root/.ssh/id_rsa -p 22 root@hadoop1
ssh-copy-id -i /root/.ssh/id_rsa -p 22 root@hadoop2
1
2
3

# 修改 Hadoop 配置文件

要想真正的运行 hadoop 应用还需要修改 hadoop 运行参数;以 hadoop0 为例,进入到容器内

cd /usr/local/hadoop/etc/hadoop
1

目录下,需要修改的可执行文件与配置文件包括:hadoop-env.sh、yarn-env.sh、core-site.xml、hdfs-site.xml、yarn-site.xml、mapred-site.xml。

# 1

vi hadoop-env.sh
1

注释掉原有的配置 export JAVA_HOME=${JAVA_HOME},修改成当前的 export JAVA_HOME=/usr/local/jdk1.8。

export JAVA_HOME=/usr/local/jdk1.8
1

# 2

vi yarn-env.sh
1

同样是重新指定 export JAVA_HOME=/usr/local/jdk1.8。

export JAVA_HOME=/usr/local/jdk1.8
1

# 3

vi core-site.xml
1
<configuration>
    <!-- 指定 HDFS 中 NameNode 的地址 -->
    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://hadoop0:9000</value>
    </property>
    <!-- 设置静态用户 -->
    <property>
    <name>hadoop.http.staticuser.user</name>
    <value>root</value>
    </property>
    <!-- 关闭dfs权限检查 -->
    <property>
    <name>dfs.permissions.enabled</name>
    <value>false</value>
    </property>
    <!-- 指定 hadoop 运行时产生文件的存储目录 -->
    <property>
        <name>hadoop.tmp.dir</name>
        <value>/usr/local/hadoop/tmp</value>
    </property>
     <property>
         <name>fs.trash.interval</name>
         <value>1440</value>
    </property>
</configuration>
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

# 4

vi hdfs-site.xml
1
<configuration>
    <property>
        <name>dfs.replication</name>
        <value>1</value>
    </property>
    <property>
        <name>dfs.permissions</name>
        <value>false</value>
    </property>
</configuration>
1
2
3
4
5
6
7
8
9
10

# 5

vi yarn-site.xml
1
<configuration>
    <property>
       <name>yarn.nodemanager.aux-services</name>
        <value>mapreduce_shuffle</value>
    </property>
    <property>
        <name>yarn.nodemanager.auxservices.mapreduce.shuffle.class</name>
        <value>org.apache.hadoop.mapred.ShuffleHandler</value>
    </property>
    <property>
        <name>yarn.resourcemanager.address</name>
        <value>hadoop0:8032</value>
    </property>
    <property>
        <name>yarn.resourcemanager.scheduler.address</name>
        <value>hadoop0:8030</value>
    </property>
    <property>
        <name>yarn.resourcemanager.resource-tracker.address</name>
        <value>hadoop0:8031</value>
    </property>
    <property>
        <name>yarn.resourcemanager.admin.address</name>
        <value>hadoop0:8033</value>
    </property>
    <property>
        <name>yarn.resourcemanager.webapp.address</name>
        <value>hadoop0:8088</value>
    </property>
</configuration>
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

# 6

mapred-site.xml这个文件默认不存在,需要从 mapred-site.xml.template 复制过来。

mv mapred-site.xml.template mapred-site.xml
1
vi mapred-site.xml
1
<configuration>
    <property>
        <name>mapreduce.framework.name</name>
        <value>yarn</value>
    </property>
</configuration>
1
2
3
4
5
6

# 7

slaves 配置 修改 hadoop0 中的从机(slaves)配置

vi /usr/local/hadoop/etc/hadoop/slaves
1

删除原来的所有内容,修改为如下

hadoop1
hadoop2
1
2

# 8

hadoop 集群配置分发 在 hadoop0 中执行命令,将 hadoop0 中的配置复制到其他两个节点中。

scp -r /usr/local/hadoop hadoop1:/usr/local
scp -r /usr/local/hadoop hadoop2:/usr/local
1
2

# 三、启动

第一次启动集群时,需要初始化

# 初始化

hdfs namenode -format
1

出现类似下面命令说明格式化成功。

19/01/20 14:51:17 INFO namenode.FSImage: Allocated new BlockPoolId: BP-417246956-172.17.0.9-1547995877501
19/01/20 14:51:17 INFO common.Storage: Storage directory /usr/local/hadoop/tmp/dfs/name has been successfully formatted.
19/01/20 14:51:17 INFO namenode.FSImageFormatProtobuf: Saving image file /usr/local/hadoop/tmp/dfs/name/current/fsimage.ckpt_0000000000000000000 using no compression
19/01/20 14:51:17 INFO namenode.FSImageFormatProtobuf: Image file /usr/local/hadoop/tmp/dfs/name/current/fsimage.ckpt_0000000000000000000 of size 323 bytes saved in 0 seconds .
19/01/20 14:51:17 INFO namenode.NNStorageRetentionManager: Going to retain 1 images with txid >= 0
19/01/20 14:51:17 INFO namenode.NameNode: SHUTDOWN_MSG: 
/************************************************************
SHUTDOWN_MSG: Shutting down NameNode at hadoop0/172.17.0.9
************************************************************/
1
2
3
4
5
6
7
8
9

注:格式化操作不能重复执行。如果一定要重复格式化,带参数 -force 即可。

# 启动 hadoop 集群

cd /usr/local/hadoop
1

目录下执行

sbin/start-all.sh
1

第一次启动的过程中需要输入 yes 确认一下。 使用 jps,检查进程是否正常启动?能看到下面几个进程表示启动成功

[root@hadoop0 hadoop]# jps
1040 SecondaryNameNode
884 DataNode
759 NameNode
1389 Jps
1247 NodeManager
383 ResourceManager
1
2
3
4
5
6
7

# 停止 hadoop 集群

cd /usr/local/hadoop
1

目录下执行

sbin/stop-all.sh
1

注:在主节点 hadoop0 启动 hadoop,从节点 hadoop1、hadoop2 会自动启动。

浏览器中访问
http://localhost:8088
或者
外部宿主机ip:8088
1
2
3
4

# 四、验证集群是否正常

可以正常访问的话,说明集群启动成功了,但不一定能正常运行,还需要下面的实际验证。

# 测试验证

创建本地测试文件,在 /opt 目录下创建测试文件目录。

mkdir wcinput
cd wcinput
vi wc.input
1
2
3

wc.input文件内容如下:

hadoop mapreduce
hadoop yarn
hadoop hdfs
mapreduce spark
hadoop hello
1
2
3
4
5

创建 HDFS 目录

hdfs dfs -mkdir -p /user/hadoop/input
1

上传文件,把测试文件上传到刚刚创建的目录中

hdfs dfs -put /opt/wcinput/wc.input /user/hadoop/input
1

查看文件上传是否正确

hdfs dfs -ls /user/hadoop/input
1
[root@hadoop0 wcinput]# hdfs dfs -ls /user/hadoop/input
Found 1 items
-rw-r--r--   1 root supergroup         70 2019-01-21 10:07 /user/hadoop/input/wc.input
1
2
3

# 运行 mapreduce 程序

hadoop 安装包中提供了一个示例程序,我们可以使用它对刚刚上传的文件进行测试

hadoop jar /usr/local/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.9.2.jar wordcount /user/hadoop/input /user/hadoop/output
1

注:在执行过程中,如果长时间处于 Running 状态不动,虽然没有报错,但实际上是出错了,后台在不断重试,需要到 logs 目录下(/usr/local/hadoop/logs)查看日志文件中的错误信息。

查看输出结果

hdfs dfs -ls /user/hadoop/output
1
[root@hadoop0 wcinput]# hdfs dfs -ls /user/hadoop/output
Found 2 items
-rw-r--r--   1 root supergroup          0 2019-01-22 05:35 /user/hadoop/output/_SUCCESS
-rw-r--r--   1 root supergroup         51 2019-01-22 05:35 /user/hadoop/output/part-r-00000
1
2
3
4

_SUCCESS 表示 HDFS 文件状态,生成的结果在 part-r-00000 中查看。

hdfs dfs -cat /user/hadoop/output/part-r-00000
1
[root@hadoop0 wcinput]# hdfs dfs -cat /user/hadoop/output/part-r-00000
hadoop    4
hdfs    1
hello    1
mapreduce    2
spark    1
yarn    1
1
2
3
4
5
6
7

以上就是使用 Docker 环境搭建 Hadoop 镜像容器,配置 Hadoop 集群,并启动和测试的实例,测试用的是 hadoop 官方给的一个 wordcount 统计,利用 hadoop 安装包里的 mapreduce 示例 jar 计算指定 HDFS 文件里的单词数,并将结果输出到指定 HDFS 目录。 链接1 链接2