使用kubernetes-kafka作为 minikube 的起点。
这使用了 StatefulSet 和 headless service用于集群内的服务发现。
目标是向外部公开各个 Kafka Brokers,其内部地址如下:
kafka-0.broker.kafka.svc.cluster.local:9092
kafka-1.broker.kafka.svc.cluster.local:9092
kafka-2.broker.kafka.svc.cluster.local:9092
限制是该外部服务能够专门针对代理。
解决这个问题的正确(或一种可能)方法是什么?是否可以根据 kafka-x.broker.kafka.svc.cluster.local:9092
公开外部服务?
最佳答案
我们在 1.7 中通过将 headless 服务更改为 Type=NodePort
并设置 externalTrafficPolicy=Local
解决了这个问题。这会绕过服务的内部负载平衡,并且只有当 Kafka Pod 位于该节点上时,发往该节点端口上特定节点的流量才会起作用。
apiVersion: v1
kind: Service
metadata:
name: broker
spec:
externalTrafficPolicy: Local
ports:
- nodePort: 30000
port: 30000
protocol: TCP
targetPort: 9092
selector:
app: broker
type: NodePort
例如,我们有两个节点nodeA和nodeB,nodeB正在运行一个kafka pod。 nodeA:30000 将无法连接,但 nodeB:30000 将连接到在 nodeB 上运行的 kafka pod。
https://kubernetes.io/docs/tutorials/services/source-ip/#source-ip-for-services-with-typenodeport
请注意,这在 1.5 和 1.6 中也作为 Beta 注释提供,可以在此处找到有关功能可用性的更多信息:https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip
另请注意,虽然这将 kafka pod 绑定(bind)到特定的外部网络身份,但它并不能保证您的存储卷将绑定(bind)到该网络身份。如果您在 StatefulSet 中使用 VolumeClaimTemplates,那么您的卷将与 pod 绑定(bind),而 kafka 希望卷与网络身份绑定(bind)。
例如,如果 kafka-0 pod 重新启动并且 kafka-0 在 NodeC 而不是 NodeA 上出现,则 kafka-0 的 PVC(如果使用 VolumeClaimTemplates)具有用于 NodeA 的数据,并且在 kafka-0 上运行的代理将启动认为是nodeA而不是nodeC而拒绝请求。
为了解决这个问题,我们期待本地持久卷,但现在我们有一个用于 kafka StatefulSet 的 PVC,并且数据存储在该 PVC 上的 $NODENAME
下,以将卷数据绑定(bind)到特定节点。
https://github.com/kubernetes/features/issues/121 https://kubernetes.io/docs/concepts/storage/volumes/#local
关于apache-kafka - 如何在 Kubernetes 中向外部公开 StatefulSet 的 headless Kafka 服务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46456239/