官方镜像
apache/hive和apache/hadoop
坑1:没有latest镜像
坑2 hadoop好像必须要docker composer的方式 详见官方文档
https://blog.51cto.com/u_16175516/13317362
参考命令:
docker run -d --name hadoop -p 9000:9000 -p 8088:8088 -v 你自己设置个路径/hadoop:/hadoop apache/hadoop:3.4.1
上面这个命令无法 需要用composer
docker run -d --name hive --link hadoop:hadoop -p 10000:10000 apache/hive
注意这里制定了和hadoop的关联
简化方法
一、5 分钟速成版(单容器,自带 hadoop)
适合:本地测试、写 SQL、体验 Hive
镜像:bde2020/hive:2.3.2(已含 Hadoop 3.x)
安装 Docker 后一键启动
bash
复制
go
docker pull bde2020/hive:2.3.2
docker network create hadoop-network # 让 Hive 与 Hadoop 互通
docker run -d --name hive --network hadoop-network -p 10000:10000 -p 9083:9083 \
-e HIVE_METASTORE_URI=thrift://localhost:9083 \
bde2020/hive:2.3.2
进入容器直接玩 Hive
go
docker exec -it hive bash
go
# 容器内已配好 Hadoop 环境变量
hive
hive> CREATE TABLE t(id INT);
hive> INSERT INTO t VALUES(1),(2);
hive> SELECT * FROM t;
停止:docker stop hive && docker rm hive
二、完整三件套版(Hadoop + Hive + Postgres Metastore)
适合:学习 DFS/YARN/Hive 全流程,数据不丢
文件:docker-compose.yml(2025-02 更新)
yaml
version: "3.8"
services:
namenode:
image: bde2020/hadoop-namenode:2.0.0-hadoop3.2.1-java8
container_name: namenode
ports: ["9870:9870", "9000:9000"]
environment:
- CLUSTER_NAME=hive
- CORE_CONF_fs_defaultFS=hdfs://0.0.0.0:9000 # ← 显式指定
volumes: ["namenode:/hadoop/dfs/name"]
datanode:
image: bde2020/hadoop-datanode:2.0.0-hadoop3.2.1-java8
ports:
- "9866:9866"
environment:
# 对外声明
- DATANODE_CONF_dfs_datanode_hostname=121.43.141.135 #这个好像改了没效果···
# 关键:让 NameNode 保存宿主 IP 而不是容器 IP
- HDFS_CONF_dfs_namenode_datanode_registration_ip_hostname_check=false
- HDFS_CONF_dfs_client_use_datanode_hostname=true
# 防止 DataNode 自己监听 127.0.0.1
- DATANODE_CONF_dfs_datanode_address=0.0.0.0:9866
- DATANODE_CONF_dfs_datanode_http_address=0.0.0.0:9864
volumes: ["datanode:/hadoop/dfs/data"]
hive-server:
image: bde2020/hive:2.3.2
container_name: hive-server
depends_on: [hive-metastore]
ports: ["10000:10000"]
environment:
HIVE_METASTORE_URI: thrift://hive-metastore:9083
hive-metastore:
image: bde2020/hive:2.3.2
container_name: hive-metastore
depends_on: [postgres]
ports: ["9083:9083"]
environment:
HIVE_METASTORE_DB: postgres
HIVE_METASTORE_USER: hive
HIVE_METASTORE_PASS: hive
HIVE_METASTORE_JDBC_URL: jdbc:postgresql://postgres:5432/hive
postgres:
image: postgres:15
container_name: postgres-hive
ports: ["5432:5432"]
environment:
POSTGRES_DB: hive
POSTGRES_USER: hive
POSTGRES_PASSWORD: hive
volumes: ["postgres:/var/lib/postgresql/data"]
volumes:
namenode:
datanode:
postgres:
一键启动
go
docker compose up -d # 后台拉镜像并启动
docker compose ps # 看到 5 个服务全部 Running 即可
访问
go
NameNode UI: http://localhost:9870
HiveServer2: beeline -u jdbc:hive2://localhost:10000
停止
go
docker compose down -v # 加 -v 删除数据卷
方案2的数据挂载到哪了
在"方案 2"里,我把所有需要持久化的目录都声明成了 具名卷(named volumes),因此数据默认挂在 Docker 自己管理的区域,而不是你当前目录。具体对应关系如下:
表格
复制
服务 容器内路径 卷名(具名卷) 宿主机默认位置(Docker 原生路径)
namenode /hadoop/dfs/name namenode /var/lib/docker/volumes/_namenode/_data
datanode /hadoop/dfs/data datanode /var/lib/docker/volumes/_datanode/_data
postgres /var/lib/postgresql/data postgres /var/lib/docker/volumes/_postgres/_data
说明
是你所在的目录名(docker-compose 会自动加前缀)。
Windows / macOS 上因为 Docker 运行在虚拟机里,上面路径其实在 VM 内部,直接在宿主机是看不到的;如果想在宿主机文件夹里看到实体文件,需要把"具名卷"改成 bind mount(见下方示例)。
卷的生命周期独立于容器,所以 docker compose down 不会删除数据;只有 docker compose down -v 才会把卷一起清掉。
如何把数据放到你能看到的目录(可选)
把 docker-compose.yml 里对应部分改成 bind mount 即可,例如:
yaml
复制
services:
namenode:
...
volumes:
- ./data/namenode:/hadoop/dfs/name # 当前目录下 data/namenode
datanode:
...
volumes:
- ./data/datanode:/hadoop/dfs/data
postgres:
...
volumes:
- ./data/postgres:/var/lib/postgresql/data
方案2的五个容器干啥的
在"方案 2"的 docker-compose.yml 里一共启动了 5 个容器,它们各自的作用可以一句话概括为:
namenode
HDFS 的主控节点,负责管理整个文件系统的元数据(文件名、目录结构、块位置等),并对外提供 9870 管理界面。
datanode
HDFS 的存储节点,真正保存数据块,定期向 namenode 发送心跳和块报告,对外提供 9864 界面查看本地磁盘使用情况。
postgres
Hive Metastore 的底层数据库,保存所有表结构、分区信息、字段类型等元数据;换成 MySQL 也能工作,这里用 Postgres 免授权。
hive-metastore
把 Postgres 里的元数据包装成 Thrift 服务(端口 9083),让后续 HiveServer2 或其他计算引擎(Spark/Trino)能查到表结构。
hive-server
对外提供 JDBC/ODBC 接口(端口 10000),接收 "select * from ..." 等 SQL,解析后生成 MapReduce 或 Tez 任务,提交给 YARN(这里复用 hive 镜像里自带的简易 MR 框架),最终读取 HDFS 上的数据返回结果。
五个容器通过同一个网络 hadoop-network 互联,顺序启动:先起 Postgres → metastore → server,同时 namenode/datanode 提供分布式存储,就组成了一套最精简的"Hadoop+Hive"学习和开发环境。
问题记录
为什么一堆128mb的文件
128 MB 是 HDFS 的默认「块大小」(block size),跟你代码里写多少字节无关------
只要单个文件 ≥ 1 byte,HDFS 都会按 128 MB 切块存储,因此:
你上传的每个 .json 文件 实际只有几 KB;
但 HDFS 会为它们各自申请 一整块 128 MB(逻辑占用 = 128 MB,物理只存几 KB,空间不会真浪费)。
想看真实大小
WebUI 点文件名 → 右边 Block Size 显示 128 MB,File Size 显示真实字节。
CLI
bash
复制
docker exec namenode hdfs dfs -du -h /user/hive/warehouse/reco.db/user_behavior/dt=2025-12-07/03
会输出
3.2 K 3.2 K /user/.../behavior_xxx.json
第 1 列就是真实大小。
如果想调小块大小(测试时省内存)
在 NameNode 的 hdfs-site.xml 里加:
xml
复制
dfs.blocksize
8m
然后重启集群,再上传就会按 8 MB 切块了。
生产环境保持 128 MB 即可,对性能最好。
linux测试环境跑没问题 但是本地有问题
这个镜像好像没有读取hostname配置 所以实际写的时候只能局域网地址......所以本地开发创建文件夹没问题 但是实际写是写不进去的
目录格式
是正常的/ 访问的时候是正常的文件格式
你在本地开发使用的是win 可能出问题
go
// 创建目录 - 获取文件所在目录
// 使用strings.LastIndex查找最后一个/的位置,确保使用HDFS路径格式
lastSlashIndex := strings.LastIndex(filePath, "/")
if lastSlashIndex <= 0 {
return fmt.Errorf("invalid HDFS file path: %s", filePath)
}
dirPath := filePath[:lastSlashIndex]
//dirPath := filepath.Dir(filePath) //这个好像在win上 会变成\分割 而linux上需要/分割 所以导致文件路径错误
// 确保目录以/开头(HDFS路径格式)
if !strings.HasPrefix(dirPath, "/") {
dirPath = "/" + dirPath
}
三、生产级拆分版(自行编译 / 挂载配置)
适合:公司内网、需要 kerberos、ranger、tez 等二次开发
步骤要点(仅列大纲,详细可追问我)
用官方 hadoop:3.3.6 基础镜像,编译 hive-4.0.0 得到 tar 包
编写多阶段 Dockerfile,把 hadoop、hive、tez、mysql-connector 分层打镜像
docker-compose 拆成
zk、hdfs-nn、hdfs-dn、yarn-rm、yarn-nm、hms、postgres、hiveserver2
将 hive-site.xml、core-site.xml、yarn-site.xml 外挂到 configmap / volume,方便热更新
资源限制 & 日志收集:给每个 service 加
deploy: {resources: {limits: {cpus: '2', memory: 4G}}}
日志走 stdout → filebeat → es
安全:开启 kerberos,ranger-hive-plugin 做列级权限,ssl 终端在 traefik
监控:hive-metastore jmx → prometheus;grafana 模板 id 15334
问题记录
docker exec namenode netstat -tnlp | grep 9000 没有输出
编辑
复制
分享
那就是 NameNode 进程根本没在听 9000,所以外面怎么放行都连不上------问题回到容器内部。
一分钟让 9000 监听出来
进容器先看启动脚本里把 RPC 端口指到哪
bash
复制
docker exec -it namenode bash
grep 9000 $HADOOP_HOME/etc/hadoop/core-site.xml
正常应该看到
hdfs://0.0.0.0:9000
如果 value 是 localhost/127.0.0.1 → 改绑到 0.0.0.0(见下)。
如果 文件里根本不是 9000 → 把端口换回去或改环境变量。
官方镜像用环境变量就能改,最省事:
把 docker-compose.yml 里 namenode 加一行:
yaml
复制
namenode:
image: bde2020/hadoop-namenode:2.0.0-hadoop3.2.1-java8
container_name: namenode
ports:
-
"9870:9870"
-
"9000:9000"
environment:
-
CLUSTER_NAME=hive
-
CORE_CONF_fs_defaultFS=hdfs://0.0.0.0:9000 # ← 显式指定
volumes:
- namenode:/hadoop/dfs/name
重新启动
bash
复制
docker compose down
docker compose up -d
再查监听
bash
复制
docker exec namenode netstat -tnlp | grep 9000
这次应该出现
tcp 0 0 0.0.0.0:9000 0.0.0.0:* LISTEN /java
本地/远程再测
powershell
复制
Test-NetConnection 121.43.141.135 -Port 9000
看到 TcpTestSucceeded : True 就全部打通。
一句话
netstat 没输出 = 进程没开 9000 → 在 compose 里加 CORE_CONF_fs_defaultFS=hdfs://0.0.0.0:9000 → 重启 → 监听出现 → 外面就能连。
常见坑提示
Windows 用户务必在 Settings → Resources → File Sharing 把 Docker 项目目录加进去,否则挂载失败
M1/M2 芯片需要镜像带 linux/arm64 标签,否则拉 x86 镜像会启动报错
如果 10000 端口被占,改 docker-compose 的 ports 为 "10001:10000" 即可
第一次启动 metastore 会初始化 schema,看日志出现 "schemaTool completed" 才算成功
总结
只想写 SQL 选方案一
想完整体验 Hadoop+Hive 选方案二
要上生产选方案三,并可继续问我拿 Dockerfile 与 compose 模板
祝使用愉快!