1. 为什么选择Docker Compose部署Hadoop

在传统Hadoop集群部署中,我们需要手动配置多台物理机或虚拟机,每台机器都要单独安装Java环境、配置SSH免密登录、修改大量XML配置文件。这个过程不仅耗时费力,而且环境差异经常导致各种"玄学"问题。我曾在凌晨三点调试过因为主机名大小写不一致导致的DataNode注册失败问题,这种经历相信很多运维同学都深有体会。

Docker的出现让这个问题有了转机。通过容器化技术,我们可以把Hadoop的各个组件打包成标准镜像,但单纯使用Docker命令管理多个容器仍然不够优雅。这时候Docker Compose的价值就凸显出来了——它允许我们用YAML文件定义整个集群的拓扑结构,包括:

  • 各个服务的镜像版本
  • 容器之间的网络连接
  • 数据卷挂载规则
  • 资源限制和环境变量

最让我心动的是:当我们需要调整集群规模时,只需修改docker-compose.yml中的replicas参数,然后重新up就能完成扩容。这种声明式的编排方式,比手动创建容器然后配置网络要可靠得多。

2. 环境准备与基础镜像构建

2.1 准备Docker环境

首先确保你的系统已经安装Docker Engine(版本≥19.03)和Docker Compose(版本≥1.25)。可以用以下命令检查:

docker --version
docker-compose --version

提示:生产环境建议使用Docker的静态二进制包安装,避免包管理器带来的版本滞后问题。

2.2 构建基础镜像

我们基于官方CentOS镜像构建包含SSH和Java环境的基准镜像。创建Dockerfile文件:

FROM centos:7

# 安装基础工具
RUN yum install -y openssh-server openssh-clients sudo vim which

# 配置SSH
RUN ssh-keygen -A && \
    sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config && \
    echo "root:123456" | chpasswd

# 安装Java
ADD jdk-8u301-linux-x64.tar.gz /usr/local/
ENV JAVA_HOME=/usr/local/jdk1.8.0_301
ENV PATH=$JAVA_HOME/bin:$PATH

# 暴露SSH端口
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]

构建镜像并测试SSH连接:

docker build -t hadoop-base .
docker run -d -p 32222:22 --name test-ssh hadoop-base
ssh root@localhost -p 32222  # 密码123456

3. 编写Hadoop集群编排文件

3.1 网络与数据卷规划

在docker-compose.yml中,我们首先定义两个自定义网络:

  • hadoop-net:用于HDFS内部通信
  • yarn-net:用于YARN资源调度

数据卷配置:

volumes:
  namenode-data:
  datanode1-data:
  datanode2-data:

3.2 NameNode服务配置

NameNode是HDFS的核心,需要持久化存储元数据:

services:
  namenode:
    image: hadoop-base
    hostname: namenode
    volumes:
      - namenode-data:/hadoop/dfs/name
    ports:
      - "50070:50070"  # Web UI
      - "8020:8020"    # HDFS服务端口
    networks:
      - hadoop-net
    environment:
      - SERVICE_PRECONDITION="datanode1:9864 datanode2:9864"

3.3 DataNode服务配置

配置两个DataNode实现数据冗余:

datanode1:
  image: hadoop-base
  hostname: datanode1
  volumes:
    - datanode1-data:/hadoop/dfs/data
  networks:
    hadoop-net:
      aliases:
        - dn1
  depends_on:
    - namenode

datanode2:
  image: hadoop-base
  hostname: datanode2
  volumes:
    - datanode2-data:/hadoop/dfs/data
  networks:
    hadoop-net:
      aliases:
        - dn2

4. Hadoop配置自动化

4.1 使用entrypoint脚本

为了避免手动配置每个容器,我们创建entrypoint.sh自动生成配置文件:

#!/bin/bash

# 生成core-site.xml
cat > $HADOOP_HOME/etc/hadoop/core-site.xml <<EOF
<?xml version="1.0"?>
<configuration>
  <property>
    <name>fs.defaultFS</name>
    <value>hdfs://namenode:8020</value>
  </property>
</configuration>
EOF

# 生成hdfs-site.xml
cat > $HADOOP_HOME/etc/hadoop/hdfs-site.xml <<EOF
<?xml version="1.0"?>
<configuration>
  <property>
    <name>dfs.replication</name>
    <value>2</value>
  </property>
</configuration>
EOF

exec "$@"

4.2 容器启动顺序控制

通过healthcheck确保服务依赖关系:

healthcheck:
  test: ["CMD-SHELL", "nc -z localhost 8020"]
  interval: 10s
  timeout: 5s
  retries: 3

5. 集群启动与验证

5.1 一键启动集群

docker-compose up -d

启动后会自动:

  1. 创建自定义网络
  2. 挂载数据卷
  3. 按依赖顺序启动容器
  4. 执行配置初始化

5.2 验证集群状态

检查HDFS状态:

docker exec -it namenode hdfs dfsadmin -report

运行WordCount测试:

docker exec -it namenode hadoop jar \
  $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-*.jar \
  wordcount /input /output

6. 生产环境优化建议

6.1 资源限制配置

为每个服务设置资源配额:

deploy:
  resources:
    limits:
      cpus: '2'
      memory: 4G
    reservations:
      memory: 2G

6.2 高可用方案

通过修改配置实现NameNode HA:

<property>
  <name>dfs.namenode.shared.edits.dir</name>
  <value>qjournal://journalnode1:8485;journalnode2:8485;journalnode3:8485/mycluster</value>
</property>

7. 常见问题排查

7.1 DataNode无法注册

检查点:

  1. 确认网络连通性:docker network inspect hadoop_hadoop-net
  2. 查看NameNode日志:docker logs namenode
  3. 检查防火墙规则

7.2 Web UI无法访问

可能原因:

  • 端口映射错误
  • 服务未正常启动
  • 浏览器缓存问题

调试命令:

docker port namenode
curl http://localhost:50070

我在实际项目中发现,使用Docker Compose部署Hadoop集群后,环境一致性得到极大提升。曾经需要半天才能搭建好的测试环境,现在只需5分钟就能获得一个完全干净的集群。当需要测试不同Hadoop版本时,只需修改镜像标签重新部署,完全不用担心污染主机环境。

更多推荐