StatefulSet是Neo4j集群唯一可行选择,因其提供固定DNS名(如neo4j-0.neo4j.default.svc.cluster.local)、独立PVC、有序启停及稳定网络标识,而Deployment会导致Pod名/IP变动,引发数据不一致或脑裂。

生产环境别用 Deployment,必须用 StatefulSet。 Neo4j 是有状态服务,节点名、存储卷绑定、启动顺序、集群发现都依赖稳定网络标识和持久化路径,Deployment 重启后 Pod 名和 IP 都会变,直接导致数据不一致或集群脑裂。
为什么 StatefulSet 是唯一可行选择
Neo4j 在 Kubernetes 中要形成高可用集群(尤其是企业版 Causal Cluster),每个节点必须拥有:固定的 DNS 名(neo4j-0.neo4j.default.svc.cluster.local)、独立且不可替换的 PVC、按序启动/关闭、以及能被其他节点稳定寻址的 endpoint。Deployment 无法提供这些。
常见错误现象包括:
- Pod 重建后无法加入集群,日志反复报
Unable to join cluster: no leader found - 多个 Pod 挂载同一 PVC,导致
DatabaseLockedException - Bolt 连接被拒绝,因为客户端连的是旧 Pod IP,而 Service 不转发到已销毁的 endpoint
StatefulSet 的 serviceName 字段会为每个 Pod 创建固定 DNS 记录,配合 headless Service(clusterIP: None)才能让节点互相识别。
必须显式配置的三个关键环境变量
仅靠镜像默认值无法启动企业版集群,以下三个变量缺一不可:
-
NEO4J_ACCEPT_LICENSE_AGREEMENT=yes:不设则容器立即退出,日志只输出一行License not accepted -
NEO4J_dbms_mode=CORE或READ_REPLICA:决定节点角色;单节点可省略,但集群中必须明确指定 -
NEO4J_causal__clustering_expected__system__id=your-cluster-id:所有 CORE 节点必须一致,否则拒绝组成集群
注意:dbms_mode 和 causal_clustering_expected_system_id 中的双下划线是 Neo4j 5.x+ 环境变量命名规范,写成单下划线或驼峰都会被忽略。
PVC 绑定失败的典型原因和修复方式
StatefulSet 创建后卡在 Pending,kubectl describe pod neo4j-0 显示 Waiting for volume to be created,大概率是 PVC 模板没生效或 StorageClass 不匹配。
针对 Kubernetes 仪表板和 Web UI 的浏览器自动化。适用于与 Kubernetes Dashboard、Grafana、ArgoCD UI 或其他 Web 界面交互。需要设置 MCP_BROWSER_ENABLED=true。
检查点:
- 确认
volumeClaimTemplates名称与volumeMounts.mountPath中的name一致(如都叫neo4j-data) - 若使用本地存储(
hostPath或local类型 PV),必须设置volumeBindingMode: WaitForFirstConsumer,否则 PVC 会因找不到可用 PV 一直 Pending - 云厂商环境(如 AWS EBS、Azure Disk)需确保 StorageClass 存在且支持
ReadWriteOnce,不要硬写ReadWriteMany—— Neo4j 数据目录不支持多写
一个易忽略的细节:volumeClaimTemplates 下的 accessModes 必须是数组格式 ["ReadWriteOnce"],写成字符串 "ReadWriteOnce" 会导致 YAML 解析失败,但 kubectl apply 不报错,只会静默跳过 PVC 创建。
暴露 Bolt 端口时 Service 类型不能选 LoadBalancer
对外提供 bolt:// 连接时,Service 类型必须是 ClusterIP + Ingress(HTTP)或 NodePort(Bolt),绝不能用 LoadBalancer 直接暴露 7687 端口。
原因:
- 云厂商 LoadBalancer 默认只支持 TCP/UDP 层转发,无法做 TLS 终止或连接池管理,Bolt 协议握手阶段容易超时
- 客户端 SDK(如
neo4j-driver)内置的路由逻辑依赖集群拓扑信息,直连 LoadBalancer 会绕过 Neo4j 自身的读写分离机制 - 安全上,Bolt over TLS(
bolt+s://)需要证书由 Neo4j 容器内统一管理,外部 LB 无法透传证书链
正确做法:用 NodePort 对内网服务开放 7687,或通过 ClusterIP + 应用层代理(如 Envoy)做 TLS 终止和负载均衡。
真正麻烦的不是写 YAML,而是每个节点的 NEO4J_causal__clustering_initial__hosts 必须动态注入真实 Pod IP —— StatefulSet 启动顺序和 DNS 解析时机稍有偏差,集群就起不来。这需要 InitContainer 预检或用 Downward API 注入,不是简单 copy-paste 就能跑通的。

















