通过 AWS 上的 ELB 在 Kubernetes 上公开单个 Kafka 代理

Posted

技术标签:

【中文标题】通过 AWS 上的 ELB 在 Kubernetes 上公开单个 Kafka 代理【英文标题】:Expose individual Kafka brokers on Kubernetes through an ELB on AWS 【发布时间】:2018-07-10 01:18:23 【问题描述】:

我在 AWS 上运行 KOPS Kubernetes 集群,试图让 kubernetes-kafka 示例与弹性负载均衡器一起工作。这是两个经纪人的外部服务部分:

kind: Service
apiVersion: v1
metadata:
  name: outside-0
  namespace: kafka
spec:
  selector:
    app: kafka
    kafka-broker-id: "0"
  ports:
  - protocol: TCP
    targetPort: 9094
    port: 32400
    nodePort: 32400
  type: NodePort
---
kind: Service
apiVersion: v1
metadata:
  name: outside-1
  namespace: kafka
spec:
  selector:
    app: kafka
    kafka-broker-id: "1"
  ports:
  - protocol: TCP
    targetPort: 9094
    port: 32401
    nodePort: 32401
  type: NodePort

这是我尝试通过 ELB 公开这些代理(实际 FQDN 替换为 my.copmany.com)。

apiVersion: v1
kind: Service
metadata:
  name: kafka-0
  annotations:
    dns.alpha.kubernetes.io/external: kafka-0.kafka.my.company.com
spec:
  type: LoadBalancer
  ports:
  - port: 32400
    name: outside
    targetPort: 32400
  selector:
    app: outside-0
---
apiVersion: v1
kind: Service
metadata:
  name: kafka-1
  annotations:
    dns.alpha.kubernetes.io/external: kafka-1.kafka.my.company.com
spec:
  type: LoadBalancer
  ports:
  - port: 32401
    name: outside
    targetPort: 32401
  selector:
    app: outside-1

查看 AWS ELB 控制台显示 3 个实例中有 0 个可用于每个 Kafka ELB 代理,并使用 Kafka 命令行客户端超时生成到 kafka-1.kafka.my.company.com:9094outside-0 NodePort 服务如何通过kafka-0 LoadBalancer 服务暴露?还是有其他方法可以考虑?

【问题讨论】:

也许这有助于***.com/q/41868161/741970 @DmitryMinkovsky - 谢谢你的链接,两个最重要的答案都有一些很好的元素,第一个通过ec2-host:port 公开它,第二个使用elb:port。我的挑战是每个卡夫卡经纪人都需要拥有自己的“永久”网址,例如subdomain-on-company-domain:port,例如kafka-1.kafka.my.company.com:9094. 是的,我自己从来没有完全弄清楚。幸运的是,在我的情况下,我最终意识到我可以从内部发送数据,而不是向外部开放 Kafka。如果你明白这一点,请发布答案。 ELB DNS 对服务来说是永久的。如果您重新部署甚至删除部署,它不会改变。如果您删除该服务,它将被释放。如果您拥有自己的 DNS,例如 my.kafka.com,则可以将其别名为 ELB DNS 【参考方案1】:

Kakfa 非常注重需要直接访问作为主题领导者的服务器的客户端。为此,我做了以下工作:

1) 设置 configmap 以根据 pod 的序号值动态覆盖adverted.listeners 的值

POD_ID=$HOSTNAME##*-

kafka-server-start.sh server.properties \
      --override advertised.listeners=INSIDE://`hostname -f`:9092,OUTSIDE://kafka-$POD_ID.kafka.my.company.com:9094 \
      --override broker.id=$POD_ID \
      --override listeners=INSIDE://:9092,OUTSIDE://:9094

2) 为每个 Kafka pod 创建一个 LoadBalancer 服务。更改选择器以匹配您的 kafka-pod-id。

    apiVersion: v1
    kind: Service
    metadata:
      name: kafka-0
      annotations:
        dns.alpha.kubernetes.io/external: kafka-0.kafka.my.company.com
    spec:
      externalTrafficPolicy: Local
      type: LoadBalancer
      ports:
      - port: 9094
        name: outside
        targetPort: 9094
      selector:
        app: kafka
        kafka-pod-id: "0"
---     
apiVersion: v1
        kind: Service
        metadata:
          name: kafka-1
          annotations:
            dns.alpha.kubernetes.io/external: kafka-1.kafka.my.company.com
        spec:
          externalTrafficPolicy: Local
          type: LoadBalancer
          ports:
          - port: 9094
            name: outside
            targetPort: 9094
          selector:
            app: kafka
            kafka-pod-id: "1"

【讨论】:

【参考方案2】:

这些 Kubernetes 配置看起来正确。但是,如果 AWS 控制台显示“3 个实例中的 0 个可用”,这通常意味着您未通过 ELB 运行状况检查。如果没有可用于向其发送数据的健康后端实例,ELB 将丢弃任何流量,这将解释对 Kafka 的调用超时。

节点端口服务的简单 ELB 运行状况检查只是 SSH 以查看实例本身是否处于活动状态,因为该实例上的 kube-proxy 实际上会将流量转发到正确的实例。如果您只在 ELB 上运行一个侦听器,那么您实际上可以在运行状况检查中检查该端口。 (我经常为每个 ELB 运行一组 nodeport 侦听器,而不是为每个 nodeport 服务运行一个以节省资金。)

【讨论】:

【参考方案3】:

根据文档 (Kuebrnetes Service Types):

LoadBalancer:使用云提供商的外部公开服务 负载均衡器。 NodePort 和 ClusterIP 服务,其外部 负载均衡器将路由,自动创建。

您不应该为 NodePort 和 LoadBalancer 类型定义单独的服务,而只能指定 LoadBalancer 并指定 nodePort(请测试并尝试添加/删除一些选项,因为我没有可以测试的环境):

apiVersion: v1
kind: Service
metadata:
  name: kafka-0
spec:
  type: LoadBalancer
  ports:
  - port: 32400
    name: kafka
    nodePort: 32400
  selector:
    app: kafka
    kafka-broker-id: "0"
---
apiVersion: v1
kind: Service
metadata:
  name: kafka-1
spec:
  type: LoadBalancer
  ports:
  - port: 32401
    name: kafka
    nodePort: 32401
  selector:
    app: kafka
    kafka-broker-id: "1"
Kubernetes 集群应配置 AWS API 访问。 kubeletkube-apiserverkube-controller-manager/cloud-controller-manager 有云配置选项。

【讨论】:

【参考方案4】:

目标端口设置不正确,必须使用容器端口,会自动分配一个NodePort。配置如下:

apiVersion: v1
kind: Service
metadata:
  name: kafka-0
  annotations:
    dns.alpha.kubernetes.io/external: kafka-0.kafka.my.company.com
spec:
  type: LoadBalancer
  ports:
  - port: 9094
    name: outside
    targetPort: 9094
  selector:
    app: outside-0
---
apiVersion: v1
kind: Service
metadata:
  name: kafka-1
  annotations:
    dns.alpha.kubernetes.io/external: kafka-1.kafka.my.company.com
spec:
  type: LoadBalancer
  ports:
  - port: 9094
    name: outside
    targetPort: 9094
  selector:
    app: outside-1

外部端口可以是任何你想要的,例如你可以使用9094,与容器的端口相同,并且它可以是所有服务的相同端口,因为你使用不同的ELB。只要确保选择器设置正确,这应该可以正常工作。

【讨论】:

以上是关于通过 AWS 上的 ELB 在 Kubernetes 上公开单个 Kafka 代理的主要内容,如果未能解决你的问题,请参考以下文章

AWS Elastic Beanstalk VPC - 从 ELB 到实例的 HTTPS

使用用户定义的参数来控制 AWS ELB 实例的自动扩展

kubectl 等待 AWS EKS 上的服务公开 .status.loadBalancer.ingress 字段中报告的 Elastic Load Balancer (ELB) 地址

通过 ELB 访问 AWS EC2 实例

我应该为 elb 和 aws S3 设置两个不同的 Cloudfront 发行版吗?

使用 AWS(ELB、Kubernetes Nginx 和 ACM)配置 HSTS