Kubernetes 集群中的 Kafka - 如何从 Kubernetes 集群外部发布/使用消息
Posted
技术标签:
【中文标题】Kubernetes 集群中的 Kafka - 如何从 Kubernetes 集群外部发布/使用消息【英文标题】:Kafka in Kubernetes Cluster- How to publish/consume messages from outside of Kubernetes Cluster 【发布时间】:2017-06-11 14:40:29 【问题描述】:-
我已经在 Kubernetes 集群中部署并运行了 Kafka。我正在使用来自 docker hub 的这张图片 - https://hub.docker.com/r/cloudtrackinc/kubernetes-kafka/
我的 kubernetes 集群中有 3 个 kube 节点。我有 3 个 Kafka 和 3 个 zookeeper 应用程序正在运行,并且我有 zoo1、zoo2、zoo3 和 kafka-1、kafka-2 和 kafka-3 与它们对应运行。我能够从 kubernetes 集群内部发布/使用,但我无法从 kubernetes 集群外部发布/使用,即从不属于 kubernetes 集群的外部机器发布/使用。
我能够从外部机器访问 kube-nodes - 基本上我可以使用名称/IP ping 它们。
我没有使用任何外部负载平衡器,但我有一个可以解析我的外部计算机和 kube 节点的 DNS。
在这种情况下,使用 NodePort 或 ExternalIP 公开 Kafka 服务不起作用。
在 Kafka RC YML 中设置
KAFKA_ADVERTISED_HOST_NAME
或 KAFKA_ADVERTISED_LISTENERS
最终在 server.properties
中设置 ADVERTISED_HOST_NAME
/ADVERTISED_LISTENERS
属性都无助于从 kubernetes 集群外部访问 kafka。
请建议我如何从 kubernetes 集群外部发布/使用。非常感谢!
【问题讨论】:
【参考方案1】:与其重新发明***并自己构建它,不如使用https://strimzi.io添加外部侦听器的解决方案
来自文档 - https://strimzi.io/docs/operators/latest/deploying.html#setup-external-clients-str
外部监听器通过指定外部类型来暴露 Kafka:
route
使用 OpenShift 路由和默认 HAProxy 路由器
loadbalancer
使用负载均衡器服务
nodeport
使用 Kubernetes 节点上的端口
ingress
使用 Kubernetes Ingress 和 nginx Ingress Controller for Kubernetes
然后这将添加您可以从 pod(用于节点端口)或负载均衡器/服务入口查询的适当资源
还可以选择安装“Kafka Bridge”,其运行方式与 Confluent 的 Kafka REST 代理非常相似。
【讨论】:
【参考方案2】:我能够通过进行以下更改来解决我的问题 -
在 YML 中使用 NodeSelector 让 kafka pod 在 kube 集群的特定节点上运行。
将 KAFKA_ADVERTISED_HOST_NAME
设置为 Kube 主机名,此 Kafka POD 已配置为在其中运行(如步骤 1 中所配置)
使用 NodePort 暴露 Kafka 服务,并将 POD 端口设置为与暴露的 NodePort 相同,如下所示 -
spec:
ports:
- name: broker-2
port: **30031**
targetPort: 9092
nodePort: **30031**
protocol: TCP
selector:
app: kafka-2
broker_id: "2"
type: NodePort
现在,您可以使用 host:exposedPort 从 kube 集群外部访问 Kafka 代理
【讨论】:
【参考方案3】:我在从 AWS 上的 k8s 集群外部访问 kafka 时遇到了同样的问题。我设法通过使用从版本 0.10.2 开始支持多个接口的 kafka 侦听器功能来解决这个问题。
这是我配置 kafka 容器的方式。
ports:
- containerPort: 9092
- containerPort: 9093
env:
- name: KAFKA_ZOOKEEPER_CONNECT
value: "zookeeper:2181"
- name: KAFKA_LISTENER_SECURITY_PROTOCOL_MAP
value: "INTERNAL_PLAINTEXT:PLAINTEXT,EXTERNAL_PLAINTEXT:PLAINTEXT"
- name: KAFKA_ADVERTISED_LISTENERS
value: "INTERNAL_PLAINTEXT://kafka-internal-service:9092,EXTERNAL_PLAINTEXT://123.us-east-2.elb.amazonaws.com:9093"
- name: KAFKA_LISTENERS
value: "INTERNAL_PLAINTEXT://0.0.0.0:9092,EXTERNAL_PLAINTEXT://0.0.0.0:9093"
- name: KAFKA_INTER_BROKER_LISTENER_NAME
value: "INTERNAL_PLAINTEXT"
除此之外,我还配置了两个服务。一种用于内部(无头)通信,另一种用于外部(LoadBalancer)通信。
希望这会节省人们的时间。
【讨论】:
嗨,我想按照你的解决方案,因为我有同样的问题和类似的设置。你能再解释一下吗,我不明白你是怎么做到的。【参考方案4】:我通过使用 Confluent 的 Kafka REST 代理映像解决了这个问题。
https://hub.docker.com/r/confluentinc/cp-kafka-rest/
REST 代理的文档在这里:
http://docs.confluent.io/3.1.2/kafka-rest/docs/index.html
步骤 A:使用最新的 Kafka 版本构建 Kafka 代理 docker 映像
我使用了基于您使用的同一映像的自定义构建的 Kafka 代理映像。您基本上只需要更新 cloudtrackinc 的映像以使用 Kafka 版本 0.10.1.0,否则它将无法正常工作。只需从 cloudertrackinc 的镜像更新 Dockerfile 以使用最新的 wurstmeister kafka 镜像并重建 docker 镜像。
- FROM wurstmeister/kafka:0.10.1.0
我将每个 Kafka 代理的 ADVERTISED_HOST_NAME 设置为 POD 的 IP,这样每个代理都会获得一个唯一的 URL。
- name: ADVERTISED_HOST_NAME
valueFrom:
fieldRef:
fieldPath: status.podIP
步骤 B:设置 cp-kafka-rest 代理以使用您的 Kafka 代理集群
Kafka Rest Proxy 必须与您的 Kafka 代理集群在同一个集群中运行。
您至少需要为 cp-kafka-rest 映像提供两个环境变量才能运行。 KAFKA_REST_HOST_NAME 和 KAFKA_REST_ZOOKEEPER_CONNECT。您可以设置 KAFKA_REST_HOST_NAME 使用 POD 的 IP。
- name: KAFKA_REST_HOST_NAME
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: KAFKA_REST_ZOOKEEPER_CONNECT
value: "zookeeper-svc-1:2181,zookeeper-svc-2:2181,zookeeper-svc-3:2181"
步骤 C:将 Kafka REST 代理公开为服务
spec:
type: NodePort or LoadBalancer
ports:
- name: kafka-rest-port
port: 8082
protocol: TCP
您可以使用 NodePort 或 LoadBalancer 来利用单个或多个 Kafka REST Proxy pod。
使用 Kafka REST 代理的优缺点
优点:
-
您可以轻松扩展 Kafka 代理集群
您不必在集群外公开 Kakfa 代理
您可以将负载均衡器与代理一起使用。
您可以使用任何类型的客户端访问 Kafka 集群(即 curl)。重量很轻。
缺点:
-
Kakfa 集群顶部的另一个组件/层。
消费者是在代理 pod 中创建的。这需要由您的 REST 客户端跟踪。
性能不理想:REST 而不是原生 Kafka 协议。虽然如果您部署多个代理,这可能会有所帮助。我不会将此设置用于大流量。对于少量消息流量,这可能没问题。
所以,如果你能忍受上述问题,那就试试 Kafka Rest Proxy。
【讨论】:
谢谢@yuqing mai。我还能够使我的初始配置工作。请看我对这个问题的回答。【参考方案5】:目前这似乎是不可能的,kafka 的网络架构在这个话题上相当糟糕。新的消费者使用一个代理列表,它返回 zookeeper 的主机,但不幸的是,它位于不同的网络中,因此无法从本地客户端访问它。 kafka 的不足之处在于,无法指定代理和 zookeeper 服务器。这可以防止客户端从外部访问系统。
我们暂时使用busybox解决了这个问题,我们在其中安装了与kafka交互的工具。在我们的例子中plunger
【讨论】:
谢谢@Dag 是的,在 kubernetes 中运行的 Kafka 集群在不同的 n/w 中。但是由于集群机器和外部机器都可以由内部 DNS 服务器解析,是否有一种方法或解决方法可以从外部机器发布/使用消息?此外,由于我已经使用 NodePort 公开了 kafka 服务,因此我可以使用以上是关于Kubernetes 集群中的 Kafka - 如何从 Kubernetes 集群外部发布/使用消息的主要内容,如果未能解决你的问题,请参考以下文章
如何在kubernetes上构建kafka集群后公开kafka以进行外部访问?