使用 Docker 部署 Hadoop 集群
一、前言
本文基于虚拟机中的 Docker 引擎部署 Hadoop 集群,适合入门用户参考。Docker 官网提供了详细的安装教程(Docker 安装教程),本文将逐步讲解具体操作流程。
二、知识准备
1. 什么是虚拟机?
虚拟机(Virtual Machine, VM)是通过软件模拟物理计算机硬件运行环境的程序或系统,允许多个操作系统在同一物理机上同时运行。其通过虚拟化技术抽象物理资源(CPU、内存等),为每个虚拟机提供独立环境,彼此隔离。
- 类型:系统虚拟机(如 VMware、VirtualBox,可运行完整操作系统)和进程虚拟机(如 Java 虚拟机,用于特定应用)。
- 优势:资源利用率高、灵活性强、易于管理,适用于服务器虚拟化、开发测试等场景。
- 本文使用 VMware,参考安装教程:VMware 安装保姆级教程。
2. 什么是 Docker?
Docker 是开源的应用开发、交付和运行平台,支持在 Windows、macOS、Linux 上运行,将应用及依赖打包到容器中,实现跨环境一致运行。
核心概念:
- 容器(Container):镜像的运行实例,轻量级可执行软件包,包含代码、运行时、系统工具等,确保应用在任何环境运行一致。
- 镜像(Image):构建容器的只读模板,通过 Dockerfile 定义构建指令。
- 仓库(Registry):存储和分发镜像的平台(如公共 Docker Hub)。
特点:
- 可移植性:跨平台运行,部署迁移简单。
- 隔离性:容器间相互隔离,互不影响。
- 轻量级:无需启动完整操作系统,启动快、资源占用少。
- 安全性:隔离环境限制资源访问,提供额外安全层。
工作流程:
- 编写 Dockerfile(定义依赖、环境等);
- 构建镜像;
- 运行容器实例;
- 管理容器(启动、停止等);
- 推送镜像到仓库供其他机器使用。
3. 什么是 Hadoop?
Hadoop 是 Apache 基金会的分布式系统基础架构,简化分布式程序开发,利用集群进行高速运算和存储。核心组件包括:
- HDFS(Hadoop Distributed File System):高容错的分布式文件系统,适合部署在低成本硬件,提供高吞吐量访问,放宽 POSIX 要求以支持流式数据访问。
- MapReduce:分布式计算框架,处理海量数据。
三、所需软件清单
软件名称 | 作用 | 下载 / 安装地址 |
---|---|---|
VMware | 虚拟化硬件和操作系统 | VMware 安装教程 |
CentOS | 操作系统 | 百度网盘:CentOS-7.5-x86_64-DVD-1804.iso(提取码:udwy) |
JDK + Hadoop | 运行环境和框架 | 百度网盘:资料包(提取码:h2xv) |
四、详细步骤
1. 安装 VMware 并创建虚拟机
参考VMware 安装教程完成安装,然后新建虚拟机,硬件配置及操作系统安装步骤如下:(注:原文图片展示了虚拟机配置流程,实际操作中需根据向导完成磁盘、内存等设置,并加载 CentOS 镜像文件)
(1) 硬件配置
在这里插入图片描述
(2)操作系统安装,[安装包附上](通过网盘分享的文件:CentOS-7.5-x86_64-DVD-1804.iso链接: https://pan.baidu.com/s/17IDhheZHzKiKSTbXIiBxyA 提取码: udwy --来自百度网盘超级会员v3的分享)
(3)打开虚拟机进行初始化(时间较长,耐心等待)
配置完成后,点击“安装”
2. 在 CentOS 中安装 Docker 引擎
(1)更新 yum 到最新
sudo yum update -y
yum
:CentOS 包管理器;-y
:自动确认所有操作。
(2)卸载旧版本 Docker
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
(3)安装依赖工具
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
device-mapper-persistent-data
:Docker 管理支持;lvm2
:逻辑卷管理工具。
(4)添加阿里云 Docker 源
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
(5)安装 Docker 社区版
sudo yum install -y docker-ce
(6)配置镜像加速器(解决下载慢问题)
编辑配置文件:
sudo vim /etc/docker/daemon.json
添加内容:
{
"registry-mirrors": [
"https://docker.m.daocloud.io",
"https://docker.jianmuhub.com",
"https://huecker.io",
"https://dockerhub.timeweb.cloud",
"https://dockerhub1.beget.com",
"https://noohub.ru"
],
"dns": ["114.15.15.114", "8.8.8.8"]
}
重启 Docker 服务:
sudo systemctl daemon-reload # 重新加载配置
sudo systemctl start docker # 启动Docker
sudo systemctl restart docker # 重启Docker(如需)
(7)设置 Docker 开机启动
sudo systemctl enable docker
(8)验证 Docker 安装
systemctl status docker # 查看状态(应显示active)
docker -v # 查看版本
3. 部署 Hadoop 集群
A. 构建基础 CentOS 镜像(含 SSH 服务)
(1)拉取 CentOS 基础镜像
docker pull centos:7.9.2009
(2)编写 Dockerfile 配置 SSH
vim Dockerfile # 创建并编辑文件
内容如下
# 基础镜像
FROM centos:centos7.9.2009
# 创建目录
RUN mkdir -p /opt/software && mkdir -p /opt/module
# 更换阿里云yum源
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && \
sed -i -e '/mirrors.cloud.aliyuncs.com/d' -e '/mirrors.aliyuncs.com/d' /etc/yum.repos.d/CentOS-Base.repo && \
yum makecache
# 安装工具和中文支持
RUN yum -y install kde-l10n-Chinese glibc-common vim openssh-server openssh-clients net-tools lrzsz && \
localedef -c -f UTF-8 -i zh_CN zh_CN.utf8 && \
echo "LANG=zh_CN.UTF-8" >> /etc/locale.conf
# 配置SSH服务
RUN sed -i '/^HostKey/'d /etc/ssh/sshd_config && \
echo 'HostKey /etc/ssh/ssh_host_rsa_key' >> /etc/ssh/sshd_config && \
echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config && \
echo 'PasswordAuthentication yes' >> /etc/ssh/sshd_config
# 生成SSH密钥
RUN ssh-keygen -t rsa -b 2048 -f /etc/ssh/ssh_host_rsa_key -N ""
# 设置root密码(123456)
RUN echo 'root:123456' | chpasswd
# 暴露SSH端口
EXPOSE 22
# 启动命令
CMD ["/usr/sbin/init"]
保存退出(Esc + :wq
)。
(3)构建镜像
docker build -t="centos7-ssh" . # 镜像名自定义
docker images # 查看是否构建成功
B. 集成 JDK 和 Hadoop 到镜像
(1)上传 JDK 和 Hadoop 安装包
- 通过 Xshell 连接虚拟机(IP 获取命令:
ip -4 addr show | grep inet | awk '{print $2}' | cut -d'/' -f1
)。 - 使用 Xftp 将下载的
jdk-8u212-linux-x64.tar.gz
和hadoop-3.1.3.tar.gz
上传到虚拟机。
)
(2)编写 Dockerfile 集成环境
vim Dockerfile # 编辑文件(可覆盖之前的)
内容如下:
FROM centos7-ssh # 基于之前的镜像
# 安装JDK
ADD jdk-8u212-linux-x64.tar.gz /usr/local/
RUN mv /usr/local/jdk1.8.0_212 /usr/local/jdk1.8
ENV JAVA_HOME /usr/local/jdk1.8
ENV PATH $JAVA_HOME/bin:$PATH
# 安装Hadoop
ADD hadoop-3.1.3.tar.gz /usr/local
RUN mv /usr/local/hadoop-3.1.3 /usr/local/hadoop
ENV HADOOP_HOME /usr/local/hadoop
ENV PATH $HADOOP_HOME/bin:$PATH
# 安装额外工具
RUN yum install -y which sudo
(3)构建 Hadoop 镜像
docker build -t="hadoop" . # 镜像名自定义
C. 配置集群网络
(1)创建 Docker 网桥(用于容器通信)
docker network create --driver bridge hadoop-net
(2)启动 3 个容器(1 主 2 从)
docker run -itd --name hadoop1 --network hadoop-net --hostname hadoop1 hadoop
docker run -itd --name hadoop2 --network hadoop-net --hostname hadoop2 hadoop
docker run -itd --name hadoop3 --network hadoop-net --hostname hadoop3 hadoop
(3)检查网络
docker network inspect hadoop-net # 查看容器IP(如172.18.0.2、172.18.0.3、172.18.0.4)
D. 配置 SSH 免密登录
(1)分别进入 3 个容器并配置 hosts
# 打开3个终端,分别执行
docker exec -it hadoop1 bash
docker exec -it hadoop2 bash
docker exec -it hadoop3 bash
# 每个容器中编辑hosts文件
vi /etc/hosts
# 添加以下内容(IP替换为实际查看到的地址)
172.18.0.2 hadoop1
172.18.0.3 hadoop2
172.18.0.4 hadoop3
(2)配置免密登录(3 个容器均执行)
# 安装SSH客户端
yum install -y openssh-clients
# 生成密钥(一路回车)
ssh-keygen
# 分发公钥到所有节点(密码为123456)
ssh-copy-id -i /root/.ssh/id_rsa root@hadoop1
ssh-copy-id -i /root/.ssh/id_rsa root@hadoop2
ssh-copy-id -i /root/.ssh/id_rsa root@hadoop3
E. 配置 Hadoop 集群
部署规划:
- 主节点(hadoop1):NameNode、ResourceManager
- 从节点(hadoop2、hadoop3):DataNode、NodeManager
- SecondaryNameNode 部署在 hadoop1(测试环境简化,生产环境建议分离)
配置文件(在 hadoop1 上操作,后拷贝到从节点)
core-site.xml(核心配置)
vi /usr/local/hadoop/etc/hadoop/core-site.xml
添加内容:
<property>
<name>fs.defaultFS</name>
<value>hdfs://hadoop1:9000</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>file:/home/hadoop/tmp</value>
</property>
<property>
<name>io.file.buffer.size</name>
<value>131702</value>
</property>
hdfs-site.xml(HDFS 配置)
vi /usr/local/hadoop/etc/hadoop/hdfs-site.xml
添加内容:
<property>
<name>dfs.namenode.name.dir</name>
<value>file:/home/hadoop/hdfs_name</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>file:/home/hadoop/hdfs_data</value>
</property>
<property>
<name>dfs.replication</name>
<value>2</value> <!-- 副本数,与从节点数量一致 -->
</property>
<property>
<name>dfs.namenode.secondary.http-address</name>
<value>hadoop1:9001</value>
</property>
<property>
<name>dfs.webhdfs.enabled</name>
<value>true</value>
</property>
mapred-site.xml(MapReduce 配置)
vi /usr/local/hadoop/etc/hadoop/mapred-site.xml
添加内容:
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value> <!-- 指定使用YARN框架 -->
</property>
<property>
<name>mapreduce.jobhistory.address</name>
<value>hadoop1:10020</value>
</property>
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>hadoop1:19888</value>
</property>
<property>
<name>yarn.app.mapreduce.am.env</name>
<value>HADOOP_MAPRED_HOME=${HADOOP_HOME}</value>
</property>
<property>
<name>mapreduce.map.env</name>
<value>HADOOP_MAPRED_HOME=${HADOOP_HOME}</value>
</property>
<property>
<name>mapreduce.reduce.env</name>
<value>HADOOP_MAPRED_HOME=${HADOOP_HOME}</value>
</property>
yarn-site.xml(YARN 配置)
vi /usr/local/hadoop/etc/hadoop/yarn-site.xml
添加内容:
<property>
<name>yarn.resourcemanager.hostname</name>
<value>hadoop1</value> <!-- 资源管理器部署在主节点 -->
</property>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value> <!-- 启用Shuffle服务 -->
</property>
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value> <!-- 启用日志聚合 -->
</property>
<property>
<name>yarn.log-aggregation.retain-seconds</name>
<value>604800</value> <!-- 日志保留7天 -->
</property>
workers(从节点列表)
vi /usr/local/hadoop/etc/hadoop/workers
添加内容:
hadoop2
hadoop3
配置环境变量(hadoop1 上操作)
修改 Hadoop 启动脚本
# 编辑start-dfs.sh和stop-dfs.sh
cd /usr/local/hadoop/sbin
vi start-dfs.sh # 在第二行添加
vi stop-dfs.sh # 在第二行添加
添加内容:
HDFS_DATANODE_USER=root
HADOOP_SECURE_DN_USER=hdfs
HDFS_NAMENODE_USER=root
HDFS_SECONDARYNAMENODE_USER=root
# 编辑start-yarn.sh和stop-yarn.sh
vi start-yarn.sh # 在第二行添加
vi stop-yarn.sh # 在第二行添加
添加内容:
YARN_RESOURCEMANAGER_USER=root
HADOOP_SECURE_DN_USER=yarn
YARN_NODEMANAGER_USER=root
配置 Hadoop 环境变量
vi /usr/local/hadoop/etc/hadoop/hadoop-env.sh
添加:
export JAVA_HOME=/usr/local/jdk1.8
配置系统环境变量
vi ~/.bashrc
添加:
export JAVA_HOME=/usr/local/jdk1.8
export HADOOP_HOME=/usr/local/hadoop
export PATH=$PATH:/bin:/usr/bin:$JAVA_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
生效配置:
source ~/.bashrc
同步配置到从节点
scp -r /usr/local/hadoop/ hadoop2:/usr/local/
scp -r /usr/local/hadoop/ hadoop3:/usr/local/
4. 启动并测试集群
(1)格式化 HDFS(仅首次启动时执行)
hdfs namenode -format
(2)启动集群
start-all.sh
(3)验证进程(在各节点执行jps
)
- hadoop1 应包含:NameNode、ResourceManager、SecondaryNameNode
- hadoop2、hadoop3 应包含:DataNode、NodeManager
同步配置到从节点
scp -r /usr/local/hadoop/ hadoop2:/usr/local/
scp -r /usr/local/hadoop/ hadoop3:/usr/local/
4. 启动并测试集群
(1)格式化 HDFS(仅首次启动时执行)
hdfs namenode -format
(2)启动集群
start-all.sh
(3)验证进程(在各节点执行jps
)
- hadoop1 应包含:NameNode、ResourceManager、SecondaryNameNode
- hadoop2、hadoop3 应包含:DataNode、NodeManager
五、Docker 安装与直接虚拟机安装的深度差异及亲手实践细节(附问题排查与数据记录)
一、Docker 与直接虚拟机安装的底层差异(附实操数据支撑)
Docker 的 “进程级虚拟化” 与虚拟机的 “硬件级虚拟化”,并非简单的 “轻量” 与 “重量级” 区别,而是从架构设计、资源调度到环境管理的全维度差异。以下结合我在 Hadoop 部署中的实际测试数据(宿主机配置:CPU i5-1035G1,内存 16GB,磁盘 512GB SSD),从 6 个核心维度展开对比:
对比维度 | Docker(容器化) | 直接虚拟机(以 VMware 为例) | 我的实操细节与数据记录 |
---|---|---|---|
底层架构 | 共享宿主机 Linux 内核(如 CentOS 7 的 3.10 内核),容器仅包含应用及依赖(无独立 OS 内核) | 通过 Hypervisor(VMware Workstation 16)模拟 x86 硬件,每个虚拟机运行完整 OS(如 CentOS 7,含独立内核、驱动、系统进程) | 1. Docker 容器内执行uname -r ,输出与宿主机一致(3.10.0-1160.el7.x86_64 );2. 虚拟机内执行uname -r ,输出相同内核版本,但通过ls /boot 可见独立的 vmlinuz(内核文件)和 initramfs(初始化镜像),占用约 500MB 磁盘空间。 |
资源占用 | 无 OS 开销,仅占用应用运行资源(MB 级) | 需预分配固定硬件资源(GB 级),含 OS 后台进程开销 | 1. Docker 部署 Hadoop(1 主 2 从):- 启动前:Docker 服务占用内存≈200MB;- 启动后:3 个容器共占用内存≈1.2GB(hadoop1:500MB,hadoop2:350MB,hadoop3:350MB),CPU 使用率≈5%;2. 虚拟机部署 Hadoop(1 主 2 从):- 每台虚拟机预分配 2GB 内存、2 核 CPU;- 启动后:每台虚拟机 OS 后台进程(如 sshd、rsyslog、NetworkManager)已占用≈800MB 内存,3 台共占用≈6.8GB 内存,CPU 使用率≈15%(开机后无任务状态)。 |
启动速度 | 秒级启动(容器创建→SSH 可连接) | 分钟级启动(开机自检→OS 加载→服务初始化) | 1. Docker 启动流程计时:- docker run -itd hadoop1 :2 秒创建容器;- docker exec -it hadoop1 bash :1 秒进入容器;- 启动 SSH 服务(systemctl start sshd ):3 秒;- 总计:≤6 秒可操作;2. 虚拟机启动流程计时:- 开机自检:15 秒;- CentOS 加载内核与 init 进程:25 秒;- 启动 NetworkManager、sshd 等服务:20 秒;- 总计:60-80 秒才可通过 Xshell 连接。 |
隔离性 | 进程级隔离(PID、网络、文件系统隔离),共享内核,无硬件隔离 | 系统级隔离(CPU、内存、磁盘、网络完全独立),OS 级故障不扩散 | 1. Docker 隔离性测试:- 在 hadoop2 容器中执行kill -9 1 (尝试终止容器 init 进程),仅 hadoop2 容器退出,hadoop1、hadoop3 正常运行;- 但容器无法修改内核参数(如sysctl -w net.ipv4.ip_forward=1 需宿主机授权);2. 虚拟机隔离性测试:- 故意在 hadoop2 虚拟机中执行rm -rf /boot (破坏系统引导),仅 hadoop2 无法启动,hadoop1、hadoop3 不受影响;- 每台虚拟机可独立修改内核参数(如调整 swap 分区大小),不影响其他虚拟机。 |
环境一致性 | 镜像打包 “应用 + 依赖 + 配置 + 系统库”,一次构建可跨环境复用 | 依赖虚拟机快照,快照含完整 OS 状态,跨硬件易出兼容问题 | 1. Docker 复用测试:- 在宿主机 A 构建的hadoop:3.1.3 镜像(大小 820MB),导出为hadoop.tar (压缩后 380MB);- 拷贝到宿主机 B(CPU i7-1265U,内存 32GB),导入镜像(docker load -i hadoop.tar )后,直接启动容器,Hadoop 集群 10 分钟内正常运行,无任何配置修改;2. 虚拟机复用测试:- 导出 hadoop1 虚拟机快照(大小 12GB),拷贝到宿主机 B;- 导入后启动报错:“VMware Workstation 无法使用此虚拟机,因为它是在不同的硬件版本上创建的”,需手动升级虚拟机硬件版本(耗时 20 分钟),且启动后网卡无法识别(需重新配置ifcfg-ens33 文件)。 |
存储与数据持久化 | 容器默认存储为 “临时层”,需手动挂载宿主机目录或使用数据卷 | 虚拟机磁盘为独立文件(.vmdk),数据默认存储在虚拟机内部 | 1. Docker 数据持久化实操:- 启动 hadoop1 时挂载数据目录:docker run -itd --name hadoop1 -v /home/myhadoop/data:/home/hadoop/hdfs_data hadoop ;- 测试:在容器内hdfs dfs -put test.txt / ,删除容器后重新启动,挂载目录下仍能找到test.txt (数据未丢失);2. 虚拟机数据处理:- 若需备份 Hadoop 数据,需通过 Xftp 从虚拟机内下载(1GB 文件需 10 分钟);- 曾因虚拟机快照损坏(.vmdk 文件出错),导致 3 天的测试数据全部丢失,重新部署耗时 4 小时。 |
二、亲手实践过程:从虚拟机踩坑到 Docker 高效部署(附错误日志与解决步骤)
我先后用虚拟机部署 3 次(前 2 次失败,第 3 次成功)、Docker 部署 2 次(1 次成功,1 次因镜像缓存问题调试),整个过程累计耗时约 20 小时,以下是详细的实践细节、踩坑记录与解决思路:
(一)直接虚拟机安装 Hadoop 的踩坑与解决(2 次失败复盘)
失败案例 1:虚拟机分区配置错误导致磁盘不足
-
操作细节:首次创建 VM 时,为图方便选择 “自动分区”,仅给
/
分区分配 20GB 空间;安装 Hadoop(解压后约 800MB)和 JDK(约 300MB)后,执行hdfs namenode -format
时突然报错:No space left on device
(设备无剩余空间)。 -
排查过程:
- 执行
df -h
查看磁盘使用:/
分区已用 100%(日志文件/var/log/messages
因 SSH 连接失败日志占了 15GB); - 原因:自动分区未单独划分
/var
分区,SSH 多次连接失败的日志(sshd[1234]: Connection closed by 192.168.6.1 port 54321 [preauth]
)填满了/
分区。
- 执行
-
解决方法:
-
删除旧虚拟机,重新创建时选择 “手动分区”:
/boot:200MB(引导分区);
swap:4GB(内存 2 倍,用于内存溢出时临时存储);
/var:10GB(日志与临时文件);
/home:20GB(Hadoop 数据存储);
/:剩余空间(系统文件);
-
配置 SSH 连接超时时间:
vi /etc/ssh/sshd_config
,添加ClientAliveInterval 60
(每 60 秒发送心跳包),避免频繁断连产生冗余日志。
-
失败案例 2:静态 IP 配置错误导致集群节点无法通信
-
操作细节:为避免 DHCP 导致 IP 变化,给 3 台虚拟机配置静态 IP(hadoop1:192.168.6.128,hadoop2:192.168.6.129,hadoop3:192.168.6.130);修改
/etc/sysconfig/network-scripts/ifcfg-ens33
后,执行systemctl restart network
报错:Job for network.service failed because the control process exited with error code
。 -
排查过程:
- 查看网络日志:
journalctl -u network
,发现错误:Invalid IP address '192.168.6.128/24'
(IP 格式错误); - 检查配置文件:发现将
IPADDR=192.168.6.128
误写为IPADDR=192.168.6.128/24
(子网掩码应单独用PREFIX=24
配置)。
- 查看网络日志:
-
解决方法:
-
修正
ifcfg-ens33
配置:IPADDR=192.168.6.128;
PREFIX=24;
GATEWAY=192.168.6.1(与宿主机 VMnet8 网卡网关一致);
DNS1=114.114.114.114;
-
重启网络服务:
systemctl restart network
,执行ping 192.168.6.129
(hadoop2),丢包率 0%,通信正常。
-
虚拟机部署成功后的痛点:效率极低
即使第 3 次成功部署,仍遇到 2 个难以解决的问题:
- 资源占用过高:3 台虚拟机运行 Hadoop 时,宿主机内存占用达 85%(≈13.6GB),打开浏览器就卡顿,无法同时进行代码编写;
- 配置同步繁琐:修改
core-site.xml
后,需通过 Xshell 分别登录 3 台虚拟机,手动替换文件(曾因 hadoop3 忘记替换,导致 DataNode 无法加入集群,排查 2 小时才发现)。
(二)Docker 部署 Hadoop 的实践细节(从镜像构建到集群验证)
1. 镜像构建:解决 “缓存失效” 与 “依赖缺失” 问题
-
初始问题:首次编写 Dockerfile 时,将
ADD jdk-8u212.tar.gz /usr/local/
放在yum install
之后,导致每次修改yum
相关命令时,JDK 解压步骤都要重新执行(Docker 构建按层缓存,前层修改后后续层缓存失效),构建时间从 10 分钟延长到 25 分钟。 -
优化方案:调整 Dockerfile 指令顺序,将 “不变的步骤”(如 JDK/Hadoop 解压)放在前面,“易变的步骤”(如
yum install
)放在后面:dockerfile
# 先解压JDK(仅首次构建时执行,后续缓存复用) ADD jdk-8u212-linux-x64.tar.gz /usr/local/ RUN mv /usr/local/jdk1.8.0_212 /usr/local/jdk1.8 # 再执行yum安装(修改时仅重新执行这层) RUN yum install -y which sudo openssh-clients
-
验证结果:修改
yum
命令后,重新构建镜像仅需 5 分钟(复用前层缓存),效率提升 60%。
2. 网络配置:自定义网桥与端口映射的实操
-
问题场景:首次用 Docker 默认
bridge
网络启动容器,执行ssh hadoop2
时报错:ssh: Could not resolve hostname hadoop2: Name or service not known
(无法解析主机名)。 -
解决步骤:
-
创建自定义网桥并指定子网:
docker network create --driver bridge --subnet 172.18.0.0/16 hadoop-net
(子网 172.18.0.0,确保容器 IP 固定段);
-
启动容器时指定 IP(避免 DHCP 分配变化):
docker run -itd --name hadoop1 --network hadoop-net --ip 172.18.0.2 hadoop
docker run -itd --name hadoop2 --network hadoop-net --ip 172.18.0.3 hadoop
docker run -itd --name hadoop3 --network hadoop-net --ip 172.18.0.4 hadoop
-
配置宿主机端口映射(方便浏览器访问 Hadoop Web 界面):
启动 hadoop1 时添加
-p 9870:9870 -p 8088:8088
(将容器 9870 端口映射到宿主机 9870,8088 同理);
-
-
验证:宿主机浏览器输入
http://127.0.0.1:9870
,成功打开 HDFS 管理界面,查看 DataNode 状态:hadoop2、hadoop3 均在线(副本数 2,符合配置)。
3. SSH 免密登录:权限与密钥分发的细节排查
-
问题现象:在 hadoop1 执行
ssh-copy-id hadoop2
,输入密码 123456 后报错:Permission denied, please try again
(权限拒绝)。 -
排查过程:
- 进入 hadoop2 容器,查看
/etc/ssh/sshd_config
:发现PasswordAuthentication no
(默认禁用密码登录); - 检查
/root/.ssh
目录权限:ls -ld /root/.ssh
显示drwxrwxrwx
(权限过宽,SSH 要求.ssh 目录权限必须为 700)。
- 进入 hadoop2 容器,查看
-
解决方法:
-
在 Dockerfile 中添加权限配置:
RUN chmod 700 /root/.ssh && echo 'PasswordAuthentication yes' >> /etc/ssh/sshd_config
-
重新构建镜像并启动容器,再次执行
ssh-copy-id hadoop2
,成功分发密钥; -
验证:
ssh hadoop2
无需输入密码,直接进入 hadoop2 容器,免密配置生效。
-
4. Hadoop 启动:进程缺失与日志排查
-
问题场景:执行
start-all.sh
后,在 hadoop2 执行jps
,发现缺少 DataNode 进程(仅显示 NodeManager 和 Jps)。 -
排查步骤:
-
查看 DataNode 日志:
cd /usr/local/hadoop/logs
,打开hadoop-root-datanode-hadoop2.log
,发现错误:Incompatible clusterIDs: namenode clusterID = CID-xxx; datanode clusterID = CID-yyy
(DataNode 与 NameNode 的 clusterID 不一致);
-
原因:首次格式化 HDFS 后,删除过 hadoop2 容器,重新启动后 DataNode 保留了旧的 clusterID(存储在
/home/hadoop/hdfs_data/current/VERSION
文件中);
-
-
解决方法:
-
在 hadoop2、hadoop3 容器中删除旧数据目录:
rm -rf /home/hadoop/hdfs_data/* /home/hadoop/tmp/*
-
在 hadoop1 重新格式化 HDFS:
hdfs namenode -format
(注意:仅首次启动或 clusterID 不一致时执行,重复格式化会导致数据丢失); -
重启集群:
stop-all.sh && start-all.sh
,再次执行jps
,hadoop2、hadoop3 的 DataNode 进程正常显示。
-
三、实践总结:从 “会部署” 到 “懂原理” 的认知升级
- 对 “虚拟化” 的理解深化:最初以为虚拟机和 Docker 只是 “大小区别”,直到亲手排查
clusterID
错误时发现:虚拟机的 DataNode 数据存储在独立 OS 中,删除虚拟机后数据彻底消失;而 Docker 容器的数据默认在临时层,但通过挂载宿主机目录可实现持久化 —— 这让我明白:容器化的核心是 “隔离应用而非隔离 OS”,虚拟机则是 “隔离完整 OS 环境”。 - 效率意识的建立:虚拟机部署时,仅 “重复配置 3 台机器” 就耗时 8 小时;而 Docker 通过镜像复用,第二次部署仅用 30 分钟(含启动集群)。这让我意识到:开发测试环境中,“可复用性” 比 “强隔离性” 更重要,容器化技术正是解决了 “环境一致性” 和 “部署效率” 的痛点。
- 问题排查能力的提升:从最初遇到错误就 “百度复制命令”,到后来学会查看日志(如
hadoop logs
、journalctl
)、分析配置文件(如sshd_config
、core-site.xml
),再到理解底层原理(如 Docker 分层缓存、HDFS 的 clusterID 机制)—— 每一次踩坑都是对 “原理” 的具象化理解,比如知道Dockerfile
指令顺序影响缓存,本质是 “分层构建” 的设计逻辑。
如果用一句话总结:虚拟机让我 “学会了部署 Hadoop”,而 Docker 让我 “懂了为什么这么部署”,也让我真正体会到:技术选型不是 “哪个更好”,而是 “哪个更适合场景”—— 对于需要快速迭代、频繁部署的学习场景,Docker 无疑是更优解。
版权声明
本文部分内容参考自 CSDN 博主「吾仄 lo 咚锵」的原创文章(原文链接:https://blog.csdn.net/qq_45034708/article/details/115413751),遵循 CC 4.0 BY-SA 版权协议。