学习Hadoop,首先想到的是用虚拟机,但是虚拟机配置繁琐,而且多个节点占用资源也很大,那就用docker吧

在dockerhub上找了一圈,发现这个还不错:

docker pull harisekhon/hadoop:2.9

只是版本最高只有2.9,但是练习应该够了

查看项目可以发现,在根目录下有一个entrypoint.sh文件,作为入口,如果不传任何参数,就会执行初始化,如果传了参数,就会把这个参数作为命令执行

所以我们创建一个容器

docker run -d IMAGE-ID /entrypoint.sh

容器运行成功后,就可以执行hadoop命令了

docker exec -it CONTAINER-ID /entrypoint.sh hadoop

hadoop streaming藏的比较深/hadoop-2.9.0/share/hadoop/tools/lib/,所以我们创建一个软链,便于以后操作

ln -s /hadoop-2.9.0/share/hadoop/tools/lib/hadoop-streaming-2.9.0.jar /hadoop-2.9.0/hadoop-streaming.jar

因为我比较熟悉python,所以用python做MapReduce,安装python

yum -y install https://centos7.iuscommunity.org/ius-release.rpm
yum install python36u

将本地的测试文件上传到hadoop中

hadoop fs -mkdir /app/test
hadoop fs -put ./test.txt /app/test

在本地新建一个项目,用MapReduce统计单词个数

mapper.py

#!/usr/bin/python
import sys

for line in sys.stdin:
    line = line.strip()
    if line != '':
        print(line)

reducer.py

#!/usr/bin/python
import sys

result = {}

for line in sys.stdin:
    line = line.strip()
    if line in result:
        result[line] = result[line] + 1
    else:
        result[line] = 1

for item in result:
    print("{}: {}".format(item, result[item]))

在创建一个脚本用来跑任务,run.sh

work_dir=`pwd`
mapper_file="mapper.py"
reducer_file="reducer.py"
mapper="python $mapper_file"
reducer="python $reducer_file"
mapper_src=$work_dir/$mapper_file
reducer_src=$work_dir/$reducer_file
input=/app/test/test.txt
run_time=`date +%Y%m%d%H%M%S`
output=/app/test/$run_time
log_file_name="result.log"

hadoop jar $HADOOP_HOME/hadoop-streaming.jar \
-D mapred.job.map.capacity=5000 \
-D mapred.job.reduce.capacity=5000 \
-D stream.num.map.output.key.fields=1 \
-D num.key.fields.for.partition=1 \
-mapper "$mapper" \
-reducer "$reducer" \
-input "$input" \
-output "$output" \
-file "$mapper_src" \
-file "$reducer_src" \
-partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner \

[ $? -eq 0 ] && echo "hadoop task succ!" || { echo "hadoop task fail!" ; exit 1; }
hadoop fs -lsr $output
hadoop fs -cat $output/* > $log_file_name

运行成功后,就会把结果保存在当前目录下的result.log文件中

如何构建hadoop集群

首先需要生成一个子网,这样就可以为容器指定静态ip

docker network create --subnet=172.18.0.0/16 mynet123

然后同时运行三个容器,一个master,两个slave

docker run -d --name="master" -h "master" --net mynet123 --ip 172.18.0.2 IMAGE-ID /entrypoint.sh
docker run -d --name="slave1" -h "slave1" --net mynet123 --ip 172.18.0.3 IMAGE-ID /entrypoint.sh
docker run -d --name="slave2" -h "slave2" --net mynet123 --ip 172.18.0.4 IMAGE-ID /entrypoint.sh

修改三个容器中的hosts,以便他们能够用hostname相互访问

# /etc/hosts
172.18.0.2  master
172.18.0.3  slave1 
172.18.0.4  slave2

设置免密登录,将master的公钥复制到slave中去

# 在master上运行
ssh-copy-id -i ~/.ssh/id_rsa.pub slave1
ssh-copy-id -i ~/.ssh/id_rsa.pub slave2

在复制过程中需要输入slave机器的root密码,如果不知道需要登录slave,然后用passwd修改密码即可

将master和slave关联,在master中修改slaves配置,添加slave的hostname

# /hadoop-2.9.0/etc/hadoop/slaves
slave1
slave2

在slave中修改hdfs的地址

# /hadoop-2.9.0/etc/hadoop/core-site.xml
<configuration>
    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://master:8020</value>
    </property>
</configuration>

将三台的服务都关闭

/hadoop/sbin/stop-dfs.sh
/hadoop/sbin/stop-yarn.sh

然后只需要在master中启动就可以了

/hadoop/sbin/start-dfs.sh
/hadoop/sbin/start-yarn.sh

可以通过jps命令查看服务运行情况