Hazelcast实例重启后直接访问K8s Pod,如何强制走LoadBalancer外部IP?
我在Minikube中部署了一个包含2个成员的Hazelcast集群,并配置了LoadBalancer服务来访问这些成员。部署在Minikube外部的Spring Boot应用通过以下代码初始化Hazelcast实例:
public Config getHazelcastConfig() { Config config = new Config("default"); config.getNetworkConfig().setPort(5701); config.getNetworkConfig().setPortCount(1); config.getNetworkConfig().setPortAutoIncrement(false); config.getNetworkConfig().getJoin().getMulticastConfig().setEnabled(false); config.getNetworkConfig() .getJoin() .getTcpIpConfig() .addMember("external-ip:port") .setEnabled(true); return config; } @Bean public HazelcastInstance hazelcastInstance() { Config config = getHazelcastConfig(); return Hazelcast.newHazelcastInstance(config); }
首次重建后启动应用时,能成功将Minikube中的成员加入集群,最终形成3个成员的集群,符合预期。但重启应用后,它会尝试直接使用Kubernetes Pod的私有IP地址访问成员,相关日志如下:
2023-07-02 20:39:16.831 INFO 32243 --- [.IO.thread-in-0] c.h.i.server.tcp.TcpServerConnection : [10.31.0.28]:5701 [dev] [4.2.1] Initialized new cluster connection between /192.168.105.1:50190 and /10.108.94.145:5701 2023-07-02 20:39:16.898 INFO 32243 --- [cached.thread-3] c.h.i.server.tcp.TcpServerConnector : [10.31.0.28]:5701 [dev] [4.2.1] Connecting to /10.244.0.2:5701, timeout: 10000, bind-any: true 2023-07-02 20:39:26.902 INFO 32243 --- [cached.thread-3] c.h.i.server.tcp.TcpServerConnector : [10.31.0.28]:5701 [dev] [4.2.1] Could not connect to: /10.244.0.2:5701. Reason: IOException[null to address /10.244.0.2:5701] 2023-07-02 20:39:26.903 INFO 32243 --- [cached.thread-3] c.h.internal.cluster.impl.TcpIpJoiner : [10.31.0.28]:5701 [dev] [4.2.1] [10.244.0.2]:5701 is added to the blacklist. 2023-07-02 20:39:36.939 INFO 32243 --- [cached.thread-3] c.h.internal.cluster.impl.TcpIpJoiner : [10.31.0.28]:5701 [dev] [4.2.1] [10.244.0.2]:5701 is added to the blacklist.
其中IP 10.244.0.2对应某个Kubernetes Pod(集群成员),但我的应用应仅通过LoadBalancer的外部IP访问成员。我不清楚为何它会尝试直接访问Pod。
请问如何强制我的Hazelcast实例始终通过LoadBalancer的外部IP访问成员?
注:我未使用ClientConfig,因为我希望将Kubernetes中部署的成员与Spring Boot应用启动的成员一起加入集群。我已参考官方文档搭建Minikube环境。
问题的核心原因是:Hazelcast集群成员会互相交换自身的内部地址信息,外部Spring Boot应用首次加入集群后会记录Minikube中Pod的私有IP,重启后会优先尝试连接这些已记录的地址,而非仅依赖配置的LoadBalancer地址。
可以从以下两个层面配置解决:
1. 让Minikube中的Hazelcast成员对外暴露LoadBalancer地址
在Kubernetes部署Hazelcast时,需要修改成员配置,让它们向集群报告外部可访问的LoadBalancer地址,而非Pod私有IP。
方式一:直接配置Hazelcast参数
通过XML或Java配置设置public-address:
<network> <public-address>LOAD_BALANCER_IP:LOAD_BALANCER_PORT</public-address> <!-- 其他网络配置 --> </network>
方式二:通过环境变量传递(适用于使用Kubernetes插件部署的场景)
在Hazelcast Deployment的YAML中添加环境变量:
env: - name: HZ_NETWORK_PUBLICADDRESS value: "LOAD_BALANCER_IP:LOAD_BALANCER_PORT"
这样Minikube中的Hazelcast成员向集群其他节点报告自身地址时,会发送LoadBalancer的地址,而非私有Pod IP。
2. 限制外部Spring Boot应用仅使用配置的成员地址
在Spring Boot应用的Hazelcast配置中,禁用成员列表自动刷新,强制实例始终使用初始化时配置的LoadBalancer地址:
public Config getHazelcastConfig() { Config config = new Config("default"); // 保留原有配置... // 禁用成员列表自动刷新 config.getNetworkConfig().getJoin().getTcpIpConfig() .setMemberListRefreshIntervalSeconds(0); config.getProperties().setProperty("hazelcast.cluster.member.list.refresh.interval", "0"); // 可选:启用成员认证,仅信任初始配置的节点 config.getProperties().setProperty("hazelcast.security.member.authentication.required", "true"); return config; }
setMemberListRefreshIntervalSeconds(0)会阻止实例自动从集群获取新的成员地址,确保它始终只使用你配置的LoadBalancer地址进行连接。
补充说明
- 确保LoadBalancer的端口已正确映射到Hazelcast成员的5701端口,且外部应用可正常访问该端口。
- 如果Minikube的LoadBalancer IP是动态分配的,可在部署脚本中自动获取IP并注入到Hazelcast的
public-address配置中,避免手动维护的麻烦。
内容的提问来源于stack exchange,提问作者Sreyas

