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_NAMEKAFKA_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 服务,因此我可以使用 : 连接到 Kafka,但只能从 kubernetes 集群中的机器 n/w 并且在 n/ 外部的机器上同样不起作用w 虽然我可以从外部机器访问/ping这些kube节点。 互联网上的一些资源说人们已经使用 ADVERTISED_HOST_NAME 在 AWS/Cloud 上使其在外部工作,这可能是因为公共 IP...外部负载均衡器 dns

以上是关于Kubernetes 集群中的 Kafka - 如何从 Kubernetes 集群外部发布/使用消息的主要内容,如果未能解决你的问题,请参考以下文章

如何在kubernetes上构建kafka集群后公开kafka以进行外部访问?

远程访问运行在 kubernetes 中的 Kafka

Kubernetes 集群上的 Kafka 与 Istio

Kafka集群部署(Docker容器的方式)

Knative Kafka通道调度程序无法在Kubernetes集群之外访问Kafka

从本地 Docker For Mac 中部署的服务访问本地 Kafka(包括 Kubernetes 扩展)