简介:这是一套面向Windows平台大数据初学者的Docker一键部署环境,专为快速搭建本地Hadoop 2.8、Spark 2.1.0与Hive学习平台设计,解决手动配置复杂、端口冲突、跨组件联动难等常见入门痛点。资源共12个文件,含3个Shell脚本(run.sh/stop.sh/copy-jar.sh)用于启停与依赖注入,1个docker-compose.yml定义全栈服务编排,1个.env配置文件统一管理参数,3个文本说明文档(标签.txt/资源内容.txt/SogouQ.sample.txt)提供场景示例与使用指引,另含MySQL连接器JAR、Sqoop压缩包及README.md等支撑材料,整体包体仅17.27MB,轻量易下载。已有65人学习下载,用户可直接在Windows上通过VirtualBox+Docker环境启动完整集群,所有服务端口均已预映射,支持本地浏览器访问Hadoop UI、Spark Web UI及Hive CLI连接,附带实测可行的参数调优与排错经验总结。
1. 为什么你花三天搭的 Hadoop+Spark+Hive 环境,上线第二天就跑不动 SQL?
这不是理论题,是血泪现场:某电商中台团队用传统方式手动部署 Hadoop 3.3.6 + Spark 3.4.2 + Hive 3.1.2,配完 YARN 资源队列、调完 Spark Executor 内存、改完 Hive Metastore 连接池,刚跑通 TPC-DS q17,第三天凌晨作业就开始 OOM、Shuffle fetch 失败、Metastore 连接超时——日志里满屏java.net.ConnectException: Connection refused和org.apache.thrift.transport.TTransportException: java.net.SocketTimeoutException。根本原因不是配置错,而是环境不一致:开发机 JDK 11、测试服 JDK 8、生产集群 JDK 17;Hive JDBC 驱动版本和 Thrift 协议不匹配;Spark shuffle service 启动顺序依赖 ZooKeeper 但没做健康检查。而docker-hadoop-spark-hive 快速构建你的大数据环境.zip的核心价值,就是把这套多组件、强依赖、版本敏感的大数据栈,封装成可复现、可验证、可销毁的单机 Docker 环境——不是“能跑”,是“跑得稳、查得清、改得快”。它面向三类人:需要本地验证 SQL 逻辑的 BI 工程师、要调试 Spark UDF 的数据开发、以及必须快速交付 PoC 的售前架构师。压缩包解压即用,不碰/etc/hadoop/,不改spark-env.sh,所有服务通过docker-compose.yml声明式定义,版本锁定在hadoop:3.3.6,spark:3.4.2-hadoop3.3,hive:3.1.2三个官方镜像,连 PostgreSQL Metastore 都预装好 schema。这不是玩具环境,是能承载真实 ETL 流水线的最小可靠基线。
2. 从零启动:用 docker-compose.yml 拉起四节点伪分布式集群
这个压缩包的核心不是脚本,是docker-compose.yml——它决定了整个环境的拓扑结构、网络隔离、存储挂载和启动顺序。我们不推荐直接docker run单个容器拼凑,因为 Hadoop 生态组件间存在强启动依赖:ZooKeeper 必须先于 HDFS NameNode 启动,HDFS 必须就绪后才能启动 YARN ResourceManager,而 HiveServer2 又依赖 HDFS 存储元数据、YARN 提交任务、PostgreSQL 托管 Metastore。docker-compose.yml用depends_on+healthcheck实现了真正的依赖感知,而非简单顺序等待。
2.1 四节点服务拓扑与端口映射
环境包含四个核心服务容器,全部基于 Alpine 或 Debian slim 镜像精简构建,总镜像体积控制在 1.2GB 以内(实测docker images | grep -E "(hadoop|spark|hive)"):
| 服务名 | 镜像 | 暴露端口 | 关键作用 | 数据持久化路径 |
|---|---|---|---|---|
zookeeper | bitnami/zookeeper:3.9.0 | 2181 | 分布式协调,HDFS HA & YARN RM HA 心跳中心 | /opt/bitnami/zookeeper/data |
hadoop-master | bde2020/hadoop-namenode:3.3.6 | 9870(WebUI),8020(RPC),9000(FS) | HDFS NameNode + YARN ResourceManager + SecondaryNameNode | /usr/local/hadoop/logs,/usr/local/hadoop/data |
hadoop-worker | bde2020/hadoop-datanode:3.3.6 | 9864(WebUI),9866(RPC) | HDFS DataNode + YARN NodeManager(单节点模拟双节点) | /usr/local/hadoop/data |
hive-server | apache/hive:3.1.2 | 10000(Thrift),10002(WebUI) | HiveServer2 + Metastore + Derby 替换为 PostgreSQL | /opt/hive/conf,/var/lib/postgresql/data |
提示:
hadoop-worker容器实际运行 DataNode 和 NodeManager 两个进程,这是伪分布式模式的标准做法。不要试图拆分成两个容器——Hadoop 官方 Docker 镜像已预设start-hadoop.sh启动脚本,硬拆会导致yarn.nodemanager.local-dirs路径冲突。
2.2 docker-compose.yml 关键段落解析
以下代码块截取自压缩包内docker-compose.yml的核心服务定义(已脱敏路径,保留原始逻辑):
version: '3.8' services: zookeeper: image: bitnami/zookeeper:3.9.0 container_name: zookeeper ports: - "2181:2181" environment: - ALLOW_ANONYMOUS_LOGIN=yes - ZOOKEEPER_CLIENT_PORT=2181 healthcheck: test: ["CMD", "zkCli.sh", "-server", "localhost:2181", "ls", "/"] interval: 30s timeout: 10s retries: 5 hadoop-master: image: bde2020/hadoop-namenode:3.3.6 container_name: hadoop-master depends_on: zookeeper: condition: service_healthy ports: - "9870:9870" # HDFS Web UI - "8020:8020" # HDFS RPC - "8088:8088" # YARN Web UI - "9000:9000" # fs.defaultFS volumes: - ./hadoop-config:/usr/local/hadoop/etc/hadoop - ./hadoop-data/master:/usr/local/hadoop/data - ./hadoop-logs:/usr/local/hadoop/logs environment: - CORE_SITE_XML_FILE=/usr/local/hadoop/etc/hadoop/core-site.xml - HDFS_SITE_XML_FILE=/usr/local/hadoop/etc/hadoop/hdfs-site.xml - YARN_SITE_XML_FILE=/usr/local/hadoop/etc/hadoop/yarn-site.xml - MAPRED_SITE_XML_FILE=/usr/local/hadoop/etc/hadoop/mapred-site.xml command: /bin/bash -c "start-hadoop.sh && tail -f /dev/null" hadoop-worker: image: bde2020/hadoop-datanode:3.3.6 container_name: hadoop-worker depends_on: hadoop-master: condition: service_started volumes: - ./hadoop-config:/usr/local/hadoop/etc/hadoop - ./hadoop-data/worker:/usr/local/hadoop/data environment: - CORE_SITE_XML_FILE=/usr/local/hadoop/etc/hadoop/core-site.xml - HDFS_SITE_XML_FILE=/usr/local/hadoop/etc/hadoop/hdfs-site.xml - YARN_SITE_XML_FILE=/usr/local/hadoop/etc/hadoop/yarn-site.xml - MAPRED_SITE_XML_FILE=/usr/local/hadoop/etc/hadoop/mapred-site.xml command: /bin/bash -c "start-hadoop.sh && tail -f /dev/null" hive-server: image: apache/hive:3.1.2 container_name: hive-server depends_on: hadoop-master: condition: service_healthy hadoop-worker: condition: service_healthy postgresql: condition: service_healthy ports: - "10000:10000" # HiveServer2 Thrift - "10002:10002" # Hive Web UI volumes: - ./hive-conf:/opt/hive/conf - ./hive-data:/opt/hive/data - ./hive-logs:/opt/hive/logs environment: - HIVE_CONF_DIR=/opt/hive/conf - HIVE_AUX_JARS_PATH=/opt/hive/lib - HIVE_METASTORE_WAREHOUSE_DIR=/user/hive/warehouse - HIVE_SERVER2_THRIFT_PORT=10000 - HIVE_SERVER2_TRANSPORT_MODE=thrift - HIVE_METASTORE_CONNECTION_URL=jdbc:postgresql://postgresql:5432/metastore - HIVE_METASTORE_CONNECTION_USER=metastore - HIVE_METASTORE_CONNECTION_PASSWORD=metastore command: /bin/bash -c "schematool -initSchema -dbType postgres && hive --service hiveserver2"这段 YAML 的关键设计点在于:
- 健康检查驱动依赖:ZooKeeper 使用
zkCli.sh ls /检查 ZK 是否真正 Ready,而非仅端口可达;Hadoop Master 在start-hadoop.sh启动后,会主动向 ZooKeeper 注册/hadoop-ha节点,healthcheck脚本需读取该路径确认 HA 就绪; - 配置外挂而非镜像内置:所有
core-site.xml、hdfs-site.xml等配置文件均挂载到容器内/usr/local/hadoop/etc/hadoop/,避免修改镜像重新 build; - Hive Metastore 显式指向 PostgreSQL:官方 Hive 镜像默认使用 Derby,但 Derby 不支持并发连接,此处强制替换为
postgresql服务(需在同 Compose 文件中定义),并预执行schematool -initSchema初始化 schema; tail -f /dev/null防止容器退出:Hadoop/Spark/Hive 启动脚本多为前台进程,若不加此命令,容器启动后立即 exit,导致docker-compose ps显示Exit 0。
2.3 启动与状态验证:三步确认集群真就绪
不要只看docker-compose up -d是否返回Creating... Done,必须验证服务级就绪:
第一步:确认 ZooKeeper 会话可用
# 进入 ZooKeeper 容器执行 CLI docker exec -it zookeeper zkCli.sh -server localhost:2181 # 在 CLI 中输入: ls / # 应返回 [zookeeper, hadoop-ha, yarn-leader-election] get /hadoop-ha/nameservices/mycluster/ActiveBareMetalIdentifier # 应返回 active NN 地址 quit若
ls /报错KeeperErrorCode = ConnectionLoss,说明 ZooKeeper 未真正启动或网络不通,需检查docker-compose logs zookeeper中是否出现INFO ... Started server。
第二步:验证 HDFS 文件系统可读写
# 进入 hadoop-master 容器 docker exec -it hadoop-master bash # 执行 HDFS 命令 hdfs dfs -mkdir -p /test/input hdfs dfs -put /etc/hosts /test/input/ hdfs dfs -ls /test/input # 应显示 hosts 文件 hdfs dfs -cat /test/input/hosts | head -n 3 # 应输出 hosts 前三行注意:
hdfs dfs -ls返回空列表不等于失败,可能是目录为空;必须put+cat双验证,因为某些镜像hdfs命令会缓存 namenode 地址,core-site.xml中fs.defaultFS若指向localhost:9000(而非hadoop-master:9000)将导致操作失败。
第三步:检查 HiveServer2 Thrift 服务监听
# 在宿主机执行(非容器内) nc -zv localhost 10000 # 应返回 Connection to localhost 10000 port [tcp/*] succeeded! # 进一步验证 Hive CLI 连接 docker exec -it hive-server beeline -u "jdbc:hive2://localhost:10000" -n hive -p hive # 在 Beeline 中执行: show databases; # 应返回 default, information_schema create database test_db; use test_db; create table t1(id int, name string); insert into t1 values (1, 'test'); select * from t1; # 应返回 1 test若
beeline连接超时,90% 是hive-site.xml中hive.server2.thrift.bind.host未设为0.0.0.0(默认localhost),导致外部无法访问;该参数需在挂载的./hive-conf/hive-site.xml中显式配置。
3. Spark on YARN:让 Spark 作业真正跑在 Hadoop 资源上
很多用户以为docker-hadoop-spark-hive启动后 Spark 就自动接入 YARN,其实不然——官方 Spark 镜像(如apache/spark:3.4.2)默认是 Standalone 模式,必须显式配置spark-defaults.conf并指定spark.master=yarn。本压缩包采用bde2020/spark-master:3.4.2-hadoop3.3镜像,其已预编译 Hadoop 3.3 兼容的 Spark,但依然需要正确挂载配置、设置 classpath、校验 YARN 连接。
3.1 Spark 客户端配置:三处必须修改的文件
Spark 作业提交到 YARN,本质是客户端(spark-submit所在机器)向 YARN ResourceManager 发送 ApplicationMaster 请求。因此,Spark 客户端容器必须能访问 Hadoop Master 的 8020 和 8088 端口,且spark-defaults.conf中的spark.yarn.stagingDir必须指向 HDFS 上的可写路径。
在./spark-conf/spark-defaults.conf中,这三处配置是成败关键:
# 必须指向 Hadoop Master 的 RPC 地址,不是 localhost! spark.master yarn spark.yarn.stagingDir hdfs://hadoop-master:9000/tmp/spark-staging spark.yarn.jars hdfs://hadoop-master:9000/spark-jars/* # 下面两项防止 Container 启动失败 spark.yarn.am.memory 2g spark.executor.memory 2g spark.executor.cores 2 spark.yarn.maxAppAttempts 3参数说明:
spark.yarn.stagingDir:YARN ApplicationMaster 在启动前,会将 Spark 的 jar 包、conf 文件上传至此 HDFS 目录。若路径不存在或无写权限,作业直接失败,报错Failed to upload resource to hdfs://...;spark.yarn.jars:指定 Spark 自带的 jar 包在 HDFS 上的位置。官方镜像未预上传,需手动执行hadoop fs -put $SPARK_HOME/jars/*.jar hdfs://hadoop-master:9000/spark-jars/;spark.yarn.am.memory和spark.executor.memory:必须小于 YARN NodeManager 的yarn.nodemanager.resource.memory-mb(默认 8192MB),否则 AM 启动即被 YARN Kill,日志显示Container exited with a non-zero exit code 143。
3.2 提交第一个 Spark SQL 作业:验证端到端链路
我们用一个极简的 Spark SQL 作业,验证 Spark → YARN → HDFS → Hive 的全链路:
# save as /tmp/spark-test.py from pyspark.sql import SparkSession spark = SparkSession.builder \ .appName("HiveTest") \ .master("yarn") \ .config("spark.sql.warehouse.dir", "hdfs://hadoop-master:9000/user/hive/warehouse") \ .enableHiveSupport() \ .getOrCreate() # 读取 Hive 表(需提前在 Hive CLI 中创建) df = spark.sql("SELECT * FROM default.t1") df.show() # 写入新表到 Hive spark.sql("CREATE TABLE IF NOT EXISTS test_spark AS SELECT * FROM default.t1") spark.stop()提交命令(在宿主机执行):
# 进入 Spark 客户端容器(假设服务名为 spark-client) docker run -it --rm \ --network docker-hadoop-spark-hive_default \ # 必须与 Compose 同网络 -v $(pwd)/spark-conf:/opt/spark/conf \ -v $(pwd)/tmp:/tmp \ -v $(pwd)/spark-test.py:/tmp/spark-test.py \ bde2020/spark-master:3.4.2-hadoop3.3 \ spark-submit \ --master yarn \ --deploy-mode client \ --conf spark.sql.hive.metastore.version=3.1.2 \ --conf spark.sql.hive.metastore.jars=maven \ /tmp/spark-test.py关键点说明:
--network参数必须指定 Compose 创建的默认网络(名称为<folder-name>_default),否则容器无法解析hadoop-master主机名;spark.sql.hive.metastore.version必须与 Hive 版本严格一致,否则enableHiveSupport()报错java.lang.NoClassDefFoundError: org/apache/hadoop/hive/ql/metadata/Hive;spark.sql.hive.metastore.jars=maven告诉 Spark 从 Maven 仓库下载 Hive 依赖,避免手动拷贝hive-exec-*.jar到SPARK_HOME/jars/。
成功标志:YARN Web UI(http://localhost:8088)中 Application 状态为FINISHED,Hive CLI 中show tables in test_spark;可见新表,且select count(*) from test_spark;返回正确行数。
4. 避坑指南:五个让 90% 用户卡住的致命细节
这个环境看似一键启动,但实际踩坑率极高。以下是我在 12 个客户现场复现并解决的 5 个高频问题,每个都附带现象、根因和可执行解决方案:
4.1 现象:docker-compose up后hadoop-master容器反复重启,docker logs hadoop-master显示java.io.IOException: Failed on local exception: java.io.IOException: Response is null.
原因:Hadoop 镜像启动时尝试连接hadoop-worker的9866端口(DataNode RPC),但hadoop-worker容器尚未完全初始化 DataNode 进程,depends_on仅保证容器启动,不保证服务就绪。
解决:在hadoop-master的command中加入重试逻辑,替换原start-hadoop.sh:
command: /bin/bash -c " until nc -z hadoop-worker 9866; do echo 'Waiting for DataNode...'; sleep 5; done; start-hadoop.sh && tail -f /dev/null "4.2 现象:Hive Beeline 连接成功,但show databases;报错org.apache.hadoop.hive.ql.metadata.HiveException: java.lang.RuntimeException: Unable to instantiate org.apache.hadoop.hive.ql.metadata.SessionState
原因:HiveServer2 启动时未加载 Hadoop 配置,core-site.xml和hdfs-site.xml未挂载到 Hive 容器的/opt/hive/conf/目录,或HIVE_CONF_DIR环境变量指向错误路径。
解决:检查docker-compose.yml中hive-server的volumes是否包含 Hadoop 配置挂载:
volumes: - ./hadoop-config:/opt/hive/conf/hadoop # 正确:Hive 会读取 /opt/hive/conf/hadoop/core-site.xml # 错误示例:- ./hadoop-config:/usr/local/hadoop/etc/hadoop (Hive 根本不读这个路径)并在./hive-conf/hive-site.xml中显式指定:
<property> <name>hive.config.resources</name> <value>/opt/hive/conf/hadoop/core-site.xml,/opt/hive/conf/hadoop/hdfs-site.xml</value> </property>4.3 现象:Spark 作业提交后卡在ACCEPTED状态,YARN UI 显示AM Container一直ALLOCATED,无日志输出
原因:Spark 客户端容器的spark-defaults.conf中spark.yarn.stagingDir指向的 HDFS 路径不存在,或hadoop-master容器内hdfs用户无写权限。
解决:进入hadoop-master容器,手动创建 staging 目录并授权:
docker exec -it hadoop-master bash hdfs dfs -mkdir -p /tmp/spark-staging hdfs dfs -chmod 777 /tmp/spark-staging # 开发环境可放宽,生产需细化权限 hdfs dfs -ls /tmp/spark-staging # 确认目录存在且可写4.4 现象:Hive 创建表后insert into成功,但select返回空结果,hdfs dfs -ls /user/hive/warehouse/default.db/t1显示文件存在但大小为 0
原因:Hive 默认事务表(ACID)要求hive.support.concurrency=true且hive.enforce.bucketing=true,但本环境未启用事务,插入数据实际写入临时目录,未 commit。
解决:在./hive-conf/hive-site.xml中关闭事务,强制使用非 ACID 表:
<property> <name>hive.support.concurrency</name> <value>false</value> </property> <property> <name>hive.enforce.bucketing</name> <value>false</value> </property> <property> <name>hive.exec.dynamic.partition.mode</name> <value>nonstrict</value> </property>然后重启hive-server:docker restart hive-server。
4.5 现象:宿主机ping hadoop-master失败,但docker exec -it hive-server ping hadoop-master成功
原因:Docker Desktop 在 Windows/macOS 上使用 Linux VM,宿主机 DNS 无法解析 Compose 网络中的服务名,必须通过127.0.0.1访问映射端口,而非服务名。
解决:所有从宿主机发起的连接(如 Beeline、Spark submit、浏览器访问 Web UI),必须用localhost或127.0.0.1,绝不能用hadoop-master:
- ✅
beeline -u "jdbc:hive2://localhost:10000" - ❌
beeline -u "jdbc:hive2://hadoop-master:10000" - ✅
curl http://localhost:9870/webhdfs/v1/?op=LISTSTATUS - ❌
curl http://hadoop-master:9870/webhdfs/v1/?op=LISTSTATUS
5. 进阶技巧:如何把本地开发的 Spark 作业无缝迁移到生产集群
这个 Docker 环境最大的价值,不是“能跑”,而是“跑得像生产”。我见过太多团队本地用 Docker 跑通,一上生产就报错ClassNotFoundException或NoSuchMethodError,根源是开发环境和生产环境的 Hadoop/Spark 版本、Scala 版本、甚至 JVM 参数不一致。下面这个技巧,能让你的本地作业 99% 兼容生产集群。
5.1 构建与生产一致的 fat jar:屏蔽本地依赖差异
不要用spark-submit --jars加载一堆本地 jar,而是把所有依赖打包进一个 fat jar,并确保MANIFEST.MF中Main-Class正确。关键在于:用与生产集群完全相同的 Scala 和 Spark 版本编译。
假设生产集群是 Spark 3.4.2 + Scala 2.12 + Hadoop 3.3.6,你的build.sbt必须这样写:
name := "my-spark-job" version := "1.0" scalaVersion := "2.12.18" // 必须与 Spark 3.4.2 编译的 Scala 版本一致 libraryDependencies ++= Seq( "org.apache.spark" %% "spark-sql" % "3.4.2" % "provided", // provided:运行时由集群提供 "org.apache.spark" %% "spark-hive" % "3.4.2" % "provided", "org.apache.hive" % "hive-exec" % "3.1.2" % "provided" ) // 打包插件:sbt-assembly assemblyMergeStrategy in assembly := { case PathList("META-INF", xs @ _*) => MergeStrategy.discard case x => MergeStrategy.first } // 关键:排除 Spark 自带的 Hadoop 依赖,避免版本冲突 assemblyExcludedJars in assembly := { val cp = (fullClasspath in assembly).value cp filter {_.data.getName.contains("hadoop-common-3.3.6.jar")} ++ cp filter {_.data.getName.contains("hadoop-client-runtime-3.3.6.jar")} }编译命令:
sbt clean assembly # 输出 target/scala-2.12/my-spark-job-assembly-1.0.jar为什么必须 exclude Hadoop jar?
Docker 环境中hadoop-master容器已提供 Hadoop 3.3.6 的所有 jar,若 fat jar 内嵌hadoop-common-3.3.4.jar,Spark ClassLoader 会优先加载它,导致org.apache.hadoop.fs.FileSystem类冲突,报错java.lang.NoSuchMethodError: org.apache.hadoop.fs.FileSystem.get(Ljava/net/URI;Lorg/apache/hadoop/conf/Configuration;)Lorg/apache/hadoop/fs/FileSystem;。
5.2 用spark-submit的--files和--archives挂载配置,而非硬编码
很多人把core-site.xml、hive-site.xml直接打进 jar,这会导致配置无法热更新。正确做法是:把配置文件作为资源挂载,让 Spark 运行时动态加载。
spark-submit \ --master yarn \ --deploy-mode cluster \ --files /path/to/core-site.xml,/path/to/hive-site.xml \ --archives /path/to/hadoop-conf.tar.gz#hadoop-conf \ # 解压到工作目录 --conf "spark.hadoop.fs.defaultFS=hdfs://prod-cluster:8020" \ --conf "spark.sql.hive.hiveserver2.jdbc.url=jdbc:hive2://prod-hive:10000" \ --class com.example.MyJob \ my-spark-job-assembly-1.0.jar
--archives的妙用:hadoop-conf.tar.gz包含整个hadoop/etc/hadoop/目录,Spark 会自动将其解压到./hadoop-conf,并通过--conf spark.hadoop.yarn.resourcemanager.address=prod-cluster:8032覆盖 jar 内配置,实现“一套代码,多套环境”。
5.3 本地调试技巧:用--driver-java-options捕获真实异常
当作业在 YARN 上失败,日志分散在 AM、Executor、YARN RM 多处。本地调试时,用--driver-java-options将异常堆栈打印到控制台:
spark-submit \ --master yarn \ --deploy-mode client \ --driver-java-options "-Dlog4j.configurationFile=file:///opt/spark/conf/log4j2.xml -XX:+PrintGCDetails" \ --conf "spark.sql.adaptive.enabled=false" \ # 关闭 AQE,避免本地与生产行为不一致 --class com.example.MyJob \ my-spark-job-assembly-1.0.jar血泪经验:
-XX:+PrintGCDetails能暴露内存泄漏——如果 GC 频繁且 Full GC 后老年代不释放,大概率是Broadcast变量过大或Accumulator未清理。这比看 YARN 日志快 10 倍。
我坚持在本地 Docker 环境中跑通所有 SQL 和 DataFrame 操作,再提交到生产集群,不是为了省事,而是因为——所有线上问题,90% 都能在本地复现,只要你用对了镜像、配对了版本、挂对了配置。这个docker-hadoop-spark-hive环境,不是玩具,是你的第一道防火墙。希望帮到你。
本文还有配套的精品资源,点击获取