本案例介绍在 CentOS 宿主机上使用 Docker 搭建一主两从(master、slave01、slave02)的 Hadoop 2.7.7 完全分布式集群。内容包括 Docker 安装与测试、基于 CentOS 镜像制作内含 JDK 与 Hadoop 的自定义镜像、Hadoop 集群配置(core-site/hdfs-site/mapred-site/yarn-site、masters/slaves)、三个容器的启动与 hosts 配置、SSH 免密、NameNode 格式化、启动集群,以及安装后的 WordCount 功能验证与常用运维命令。
参考:http://dblab.xmu.edu.cn/blog/1233/
集群角色规划:
| 容器(主机名) | 角色 |
|---|---|
| master | NameNode、SecondaryNameNode、ResourceManager,同时兼任 DataNode、NodeManager |
| slave01 | DataNode、NodeManager |
| slave02 | DataNode、NodeManager |
7. Docker 安装与启动
7.1 安装 Docker
yum install docker -y
7.2 关闭 SELinux
编辑 Docker 配置文件:
vi /etc/sysconfig/docker
将其中的 --selinux-enabled 修改为 --selinux-enabled=false:
Modify string from "--selinux-enabled" to "--selinux-enabled=false"
7.3 启动并设置开机自启
systemctl start docker
systemctl status docker
systemctl enable docker
7.4 测试 Docker 是否正常
运行官方 hello-world 镜像。本地没有时会自动从 Docker Hub 拉取:
docker run hello-world
Unable to find image 'hello-world:latest' locally
Trying to pull repository docker.io/library/hello-world ...
latest: Pulling from docker.io/library/hello-world
b04784fba78d: Pull complete
Digest: sha256:f3b3b28a45160805bb16542c9531888519430e9e6d6ffc09d72261b0d26ff74f
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an centos container with:
$ docker run -it centos bash
Share images, automate workflows, and more with a free Docker ID:
https://cloud.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/engine/userguide/
8. 制作包含 JDK 与 Hadoop 的基础镜像
本案例采用"交互式容器内手工安装,再 docker commit 成镜像"的方式,便于逐步观察每一步的效果;熟悉流程后也可改写成 Dockerfile 一次构建。
8.1 拉取 CentOS 基础镜像
docker pull centos
8.2 准备构建上下文目录
在宿主机个人目录下创建 /root/build,用于向容器内传输文件,并将 JDK 与 Hadoop 压缩包复制到该目录:
mkdir /root/build
# 将 jdk-8u191-linux-x64.tar.gz 和 hadoop-2.7.7.tar.gz 复制到 /root/build
8.3 启动交互式容器并挂载目录
docker run -it -v /root/build:/root/build --name centos centos
参数说明:
| 参数 | 含义 |
|---|---|
docker run |
运行一个镜像 |
-i |
开启交互式(保持 STDIN 打开) |
-t |
分配一个 tty(控制台) |
-it |
在当前终端与容器内 CentOS 交互 |
-v /root/build:/root/build |
将宿主机 /root/build 挂载到容器同路径,方便双向传输文件 |
--name centos |
指定容器名称为 centos,不指定则随机分配 |
centos |
要启动的镜像名 |
8.4 在容器内安装基础工具
此时已进入容器内部 shell,安装 Vim、SSH 与网络工具:
yum -y install vim
yum install openssh* -y
yum install net-tools -y
8.5 配置 SSH 免密登录
ssh-keygen
cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys
启动 sshd 服务,并将其加入 ~/.bashrc,使容器每次启动时自动拉起:
/etc/init.d/sshd start
vim ~/.bashrc
在 ~/.bashrc 末尾加入:
/etc/init.d/sshd start
容器里没有 systemd 常规环境,Hadoop 的
start-all.sh依赖 SSH 登录到各节点拉起进程,所以 sshd 必须随容器启动而运行,把启动命令写进~/.bashrc是这里最简单的做法。
8.6 安装 JDK 与 Hadoop
cd /root/build
tar -zxvf hadoop-2.7.7.tar.gz -C /usr/local
tar -zxvf jdk-8u191-linux-x64.tar.gz -C /usr/local/
cd /usr/local/
mv hadoop-2.7.7/ hadoop
mv jdk1.8.0_191/ jdk
8.7 配置环境变量
vim /etc/profile
export JAVA_HOME=/usr/local/jdk
export HADOOP_HOME=/usr/local/hadoop
export PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbin:
export CLASS_PATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
source /etc/profile
8.8 验证 Hadoop 版本
若仅搭建单机版 Hadoop,到此已安装完成。执行版本检查:
/usr/local/hadoop/bin/hadoop version
Hadoop 2.7.7
Subversion Unknown -r c1aad84bd27cd79c3d1a7dd58202a8c3ee1ed3ac
Compiled by stevel on 2018-07-18T22:47Z
Compiled with protoc 2.5.0
From source with checksum 792e15d20b12c74bd6f19a1fb886490
This command was run using /usr/local/hadoop/share/hadoop/common/hadoop-common-2.7.7.jar
9. 配置 Hadoop 集群
以下操作在已安装 JDK 与 Hadoop 的容器内进行。配置文件都在 /usr/local/hadoop/etc/hadoop/ 目录下。
9.1 hadoop-env.sh
vim /usr/local/hadoop/etc/hadoop/hadoop-env.sh
export JAVA_HOME=/usr/local/jdk
9.2 core-site.xml
vim /usr/local/hadoop/etc/hadoop/core-site.xml
<configuration>
<property>
<name>hadoop.tmp.dir</name>
<value>file:///usr/local/hadoop/tmp</value>
<description>Abase for other temporary directories.</description>
</property>
<property>
<name>fs.defaultFS</name>
<value>hdfs://master:9000</value>
</property>
</configuration>
fs.defaultFS 指向 hdfs://master:9000,这里用的是主机名 master,所以后面必须保证各容器的 /etc/hosts 能解析它。
9.3 hdfs-site.xml
vim /usr/local/hadoop/etc/hadoop/hdfs-site.xml
<configuration>
<property>
<name>dfs.namenode.name.dir</name>
<value>file:///usr/local/hadoop/namenode_dir</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>file:///usr/local/hadoop/datanode_dir</value>
</property>
<property>
<name>dfs.replication</name>
<value>3</value>
</property>
</configuration>
副本数设为 3,对应一主两从共三个 DataNode(master 同时承担 NameNode 与 DataNode 角色)。
9.4 mapred-site.xml
由模板复制并编辑:
cp /usr/local/hadoop/etc/hadoop/mapred-site.xml.template \
/usr/local/hadoop/etc/hadoop/mapred-site.xml
vim /usr/local/hadoop/etc/hadoop/mapred-site.xml
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>
9.5 yarn-site.xml
vim /usr/local/hadoop/etc/hadoop/yarn-site.xml
<configuration>
<!-- Site specific YARN configuration properties -->
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.resourcemanager.hostname</name>
<value>master</value>
</property>
</configuration>
9.6 masters 与 slaves
echo master > /usr/local/hadoop/etc/hadoop/master
vim /usr/local/hadoop/etc/hadoop/slaves
slaves 文件内容:
slave01
slave02
slaves 列出所有从节点主机名,start-all.sh 会依次 SSH 到这些主机启动 DataNode/NodeManager。
10. 提交镜像并启动三个容器
10.1 查看容器并提交为新镜像
在宿主机上查看容器(容器退出后仍可 commit):
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f0caefc2276c centos_java "/bin/bash" 9 minutes ago Exited (1) 4 seconds ago centos-jdkinstalled1
将配置好 JDK/Hadoop 的容器提交为新镜像 centos_hadoopinstalled(将下面的容器 ID 替换为实际值):
docker commit 96c3b817a518 centos_hadoopinstalled
10.2 启动 master、slave01、slave02
分别打开三个终端执行:
# 第一个终端
docker run -it -h master --name master centos_hadoopinstalled
# 第二个终端
docker run -it -h slave01 --name slave01 centos_hadoopinstalled
# 第三个终端
docker run -it -h slave02 --name slave02 centos_hadoopinstalled
-h 参数用于设置容器主机名,使其与 Hadoop 配置中的 master、slave01、slave02 一致。
10.3 容器间网络与 /etc/hosts
三个容器默认接入 Docker 的 bridge 网络,彼此 IP 互通,但默认桥接网络不提供按容器名的 DNS 解析,因此需要手工写 /etc/hosts。
在每个容器内通过 ifconfig 查询各自 IP(若没有该命令,先执行 yum install net-tools -y)。
典型容器 IP 分配为:
| 容器 | IP |
|---|---|
| master | 172.17.0.2 |
| slave01 | 172.17.0.3 |
| slave02 | 172.17.0.4 |
在三台容器内都执行:
vim /etc/hosts
写入:
172.17.0.2 master
172.17.0.3 slave01
172.17.0.4 slave02
容器重启后 IP 可能变化,需要重新核对并修改三台容器的
/etc/hosts。
10.4 配置 master 到两个 slave 的 SSH 免密
在三台容器上分别生成密钥:
ssh-keygen
在 master 上配置授权并分发公钥:
cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys
ssh-copy-id -i ~/.ssh/id_rsa.pub slave02
ssh-copy-id -i ~/.ssh/id_rsa.pub slave01
11. 格式化并启动集群
在 master 上执行:
hdfs namenode -format
start-all.sh
启动后通过 jps 检查各节点进程:
jps
- master 上应存在 NameNode、SecondaryNameNode、ResourceManager、DataNode、NodeManager。
- slave01、slave02 上应存在 DataNode、NodeManager。
hdfs namenode -format只在首次搭建或重建集群时执行;对已有数据的集群重复格式化会导致数据不可用。
12. Web UI 访问验证
Hadoop 2.x 自带的 Web 界面可用于直观查看集群状态:
| 界面 | 地址 | 用途 |
|---|---|---|
| HDFS NameNode | http://master:50070/ |
查看 HDFS 容量、DataNode 列表(Live Nodes)、浏览文件系统 |
| YARN ResourceManager | http://master:8088/ |
查看 NodeManager 节点、提交的作业与运行进度 |
| SecondaryNameNode | http://master:50090/ |
查看检查点信息 |
由于这些端口在容器内部,从宿主机浏览器访问有两种方式:
- 启动容器时做端口映射,例如把 master 的相关端口暴露出来:
docker run -it -h master --name master \
-p 50070:50070 -p 8088:8088 -p 9000:9000 \
centos_hadoopinstalled
- 或者在容器内用
curl直接验证服务是否已监听:
curl -s -o /dev/null -w "HTTP %{http_code}\n" http://master:50070/
curl -s -o /dev/null -w "HTTP %{http_code}\n" http://master:8088/
返回 HTTP 200 说明对应服务已正常启动。
13. 功能验证(WordCount)
以下步骤为安装后的验证流程,在 master 上执行。
13.1 在 HDFS 中创建测试目录
hadoop fs -mkdir /input
13.2 准备并上传测试文件
echo this is my computer this is my computer > /root/input.txt
hadoop fs -put /root/input.txt /input/
hadoop fs -cat /input/input.txt
this is my computer this is my computer
以上输出表示文件上传成功。
13.3 执行 WordCount
注意:执行 JAR 时必须保证
/output目录在 HDFS 中不存在。
cd /root
hadoop jar /usr/local/hadoop/share/hadoop/mapreduce/sources/hadoop-mapreduce-examples-2.7.7-sources.jar \
org.apache.hadoop.examples.WordCount /input/input.txt /output
13.4 查看结果
hadoop fs -cat /output/part-r-00000
computer 2
is 2
my 2
this 2
结果表示词频分析成功。作业能跑通说明 HDFS 读写、YARN 调度、MapReduce 执行三条链路都正常。
13.5 再次运行前清理输出目录
Hadoop 要求输出目录不能预先存在,否则会抛出:
org.apache.hadoop.mapred.FileAlreadyExistsException: Output directory hdfs://localhost:9000/user/hadoop/output already exists
重新执行前删除输出目录:
hdfs dfs -rm -r /output
14. 集群停止与清理
14.1 关闭 Hadoop
stop-dfs.sh
也可使用 stop-all.sh 一并停止 HDFS 与 YARN 相关进程。
14.2 常用验证与运维命令
hdfs namenode -format # 格式化 NameNode(仅首次/重建时执行)
hdfs fsck / # 检查 HDFS 文件系统健康状况
hdfs dfsadmin -report # 查看各 DataNode 存活与容量报告
hdfs dfsadmin -report 输出中若 Live datanodes 数量符合预期(例如 3),即表示集群 DataNode 正常加入。
14.3 容器停止与清理
在宿主机上操作:
# 停止三个容器
docker stop master slave01 slave02
# 下次实验时重新启动并进入
docker start master slave01 slave02
docker attach master
# 彻底删除容器(HDFS 数据一并丢失)
docker rm -f master slave01 slave02
# 删除自制镜像
docker rmi centos_hadoopinstalled
容器内的 HDFS 数据目录(
namenode_dir、datanode_dir)没有挂载到宿主机,docker rm后数据无法恢复。如需持久化,启动容器时用-v把这些目录挂载到宿主机。
15. 常见问题
15.1 输出目录已存在
报错 FileAlreadyExistsException,说明 HDFS 上的输出目录已存在。执行 hdfs dfs -rm -r /output 删除后重跑(见 13.5)。
15.2 slave 上看不到 DataNode 进程
排查顺序:
- 三台容器的
/etc/hosts是否都写了正确的master/slave01/slave02映射,容器重启后 IP 是否已变化; slaves文件是否正确列出了slave01、slave02;- sshd 是否在各容器内运行(
/etc/init.d/sshd start),master 能否ssh slave01免密登录; - 是否对已有数据的集群重复执行了
hdfs namenode -format,导致 NameNode 与 DataNode 的 clusterID 不一致——此时可清理各节点的namenode_dir/datanode_dir/tmp后重新格式化。
15.3 容器内 ifconfig / jps 命令找不到
ifconfig需要安装 net-tools:yum install net-tools -y。jps属于 JDK 自带工具,若提示找不到,说明环境变量未生效,执行source /etc/profile或检查JAVA_HOME、PATH配置。
15.4 容器重启后 Hadoop 命令不可用
/etc/profile 中的环境变量在新的交互 shell 里通常会自动加载;若未生效,可手动 source /etc/profile,或把导出语句一并写入 ~/.bashrc。
15.5 SELinux 导致 Docker 挂载或运行异常
按 7.2 将 /etc/sysconfig/docker 中的 --selinux-enabled 改为 --selinux-enabled=false 并重启 Docker 服务。
Hadoop 本身的原理与非容器部署详见 阶段16-大数据
此处评论已关闭