一套完整的 lakehouse——SQL 网关、湖表格式、元数据、对象存储、流引擎、OLAP、检索——通常被默认是「一个集群的事」。但 PoC、私有化交付前的验证、小团队起步,手里往往只有一台机器。可私有化部署的数据平台「我的数据空间」(datastudiohappy.cn)的底座就是这么跑的:单机 k3s,十几个常驻组件,高峰三四十个 pod,长期稳定。这篇讲清楚怎么做对:选型、部署顺序、资源分配、数据持久化、日志与安全。
一、全景与选型:为什么是 k3s
| 组件 | 角色 |
|---|---|
| MinIO | S3 对象存储,Iceberg warehouse |
| MySQL | HMS 元数据 + 平台元数据 |
| Hive Metastore | 表元数据,四个引擎共享同一份 |
| Kyuubi + Spark | SQL 网关 + 批计算,引擎按需拉起 |
| Flink | 流引擎,每作业一个独立集群 |
| Trino | Iceberg + 跨源联邦查询 |
| Doris | OLAP,高并发点查 / 聚合 |
| Iceberg | 湖表格式,以 jar 进各引擎,非独立进程 |
| ZooKeeper / Kafka / ES | 协调 / 消息 / 检索 |
底座选 k3s 而不是 docker-compose,三个理由:
- 引擎的现代部署形态是 K8s 原生的:Spark on K8s 是 driver 拉 executor,Flink native application 是 JM 自建 TM,都需要真正的 K8s API;compose 只能退回 standalone 模式,和生产形态是两个物种。
- 隔离与排队机制 K8s 白送:namespace + ResourceQuota 天然提供作业配额与排队,不必自己造。
- k3s 是单二进制的完整 K8s:直跑宿主、没有虚拟化夹层,PVC 就是宿主目录,排障直观;写出的清单将来搬多节点集群几乎不用改。原则一句话:部署形态可以单机,清单和抽象必须是生产形态。
二、部署顺序:依赖即顺序
地基(MySQL、ZooKeeper、MinIO)→ HMS → Kyuubi → Trino / Doris / ES / Kafka(相互独立,可并行)→ 各工作空间 namespace 与配额 → 平台层。两个要点:
- HMS 是咽喉。四个引擎全指向它,它值得最优先的稳定性投入:元数据放 MySQL 而非内嵌库;并逐一核对「谁在什么时刻访问对象存储」——不止引擎写数据,HMS 服务端建库时也要直接写对象存储,默认镜像不带这部分依赖,要提前补齐(设计依据:漏一处就是建库即报错)。
- 验收按链路,不看 pod 全绿。用 SQL 网关建一张 Iceberg 表、插数、查回,一条命令打通网关→计算→元数据→存储;再用 Trino 查同一张表,验证元数据确实共享;起一个 Kafka 入湖流作业,确认 checkpoint 持续成功;最后重启宿主机,把三步重跑一遍——能活过重启的环境才算搭完。
搭好之后,组件健康、资源水位、作业状态收进一个页面盯:
三、资源三层策略
以 64G 内存为例,全家桶挤得下,靠的是三层:
- 常驻压到最低。MySQL / ZK / MinIO / HMS / ES / Kafka / Trino / Doris 逐个设 JVM 堆和容器 limits,常驻层整体控制在 12–16G。
- 弹性按需拉起。Spark 引擎按用户复用、空闲自动回收;Flink 每个作业一个独立集群,作业停即销毁;History Server 也按需拉起。核心判断:永远不会同时用到所有引擎,「空闲即归零」远比「常驻等任务」划算。
- ResourceQuota 兜底。每个工作空间独立 namespace 配配额,作业申请超额就 Pending 排队,而不是把机器打爆(设计依据:单机没有配额约束时,一个失控作业就是一次宕机)。
在「我的数据空间」里,这层配额直接可视化:每个空间的查询引擎用了多少、还剩多少,页面上一眼可见(产品介绍)。
磁盘同样要提前规划:装 k3s 之前就把容器运行时与 PVC 的数据目录挂到大容量数据盘,事后迁移要停集群搬数据;引擎日志这类只增不减的数据,入对象存储的设桶生命周期、入 ES 的配索引过期,别「先存着再说」。
四、有状态数据:持久化四原则
- 有状态组件一律挂 PVC,且逐个数据目录核对。像 Doris 这种元数据与数据分离的组件,漏挂一个目录就丢一类数据(设计依据:容器可写层在重建后归零,重启即蒸发)。
- 身份不绑 pod IP。以 IP 为身份的有状态组件,pod 重建换 IP 后会拒绝服务;用固定网络身份(StatefulSet、FQDN 或固定宿主网络)一劳永逸。
- 重启演练当验收。上线前真实 reboot 一次、逐组件验数据,比任何 review 都可靠。
- 不可再生资产单列保护。本地构建的镜像、引擎元数据、HMS 库,没了就是没了:自建镜像推私有 registry 或保证可离线重建,批量清理类操作在这类机器上一律禁止。另一条经验:服务端 pod 重建后,顺手滚动重启它的长连接客户端——很多大数据组件的连接池对「对端换了 IP」没有自愈能力(设计依据:不重启就是一片过期连接报错)。
五、日志:边产边发,而不是事后去抓
Spark executor、Flink TM 退出后,pod 会被上层引擎立刻删除,「失败了再去抓日志」是在和删除动作竞速(设计依据:实测命中率约一半)。正确做法是节点级日志采集器边产边发:采集器持有日志文件句柄,pod 被删后仍能读完缓冲。落点做双路——全量压缩进对象存储,设 7 天生命周期,便宜;告警级以上进 ES,设 2 天过期,能搜。单机也值得做:排障时「有没有日志」是 10 分钟和一下午的区别。
六、安全基线:第一天就是生产姿势
- 中间件统一 ClusterIP,只在集群内可达;本机调试用 port-forward 到回环地址,不对局域网暴露任何数据库端口。
- 口令从第一天就是强随机值,脚本生成、存 Secret,演示环境也不例外。
- 内部回调接口带共享密钥,且 fail-closed:检测到密钥还是占位默认值就拒绝启动——宁可起不来,不带默认口令上线。
- 入口统一走 Ingress:TLS 终止、剥离伪造的身份头、内部路径对外直接拒绝。
七、三句话总结
- 单机验证 ≠ 单机架构:清单与抽象保持生产形态,规模只是参数;
- 资源策略三层缺一不可:常驻压最低、弹性按需拉起、配额兜底;
- 把不可再生的东西列出来重点保护:自建镜像、引擎元数据、HMS 库。
这套湖仓是「我的数据空间」的底座——一套可私有化部署的数据平台,支持 OEM 合作。产品介绍:datastudiohappy.cn/,交流合作 QQ:1559851993。