Kafka在Kubernetes多节点上

时间:2015-08-21 12:10:32

标签: docker apache-zookeeper apache-kafka google-cloud-platform kubernetes

所以我的目标是以分布式方式建立一个由几个kafka经纪人组成的集群。但我看不出让经纪人了解彼此的方法。

据我所知,每个代理在其配置中都需要一个单独的ID,如果我从kubernetes启动容器,我无法保证或配置?

他们还需要有相同的advertised_host吗?

我是否缺少任何需要更改的参数才能让节点相互发现?

使用脚本在Dockerfile的末尾进行这样的配置是否可行?和/或共享卷?

我正在尝试使用spotify / kafka-image进行此操作,该图像具有预先配置的zookeeper + kafka组合,在vanilla Kubernetes上。

4 个答案:

答案 0 :(得分:11)

我的解决方案是使用IP作为ID :修剪点数,您将获得一个唯一的ID,该ID也可以在容器外部提供给其他容器。

使用服务,您可以访问多个容器的IP(请参阅我的答案,如何执行此操作: what's the best way to let kubenetes pods communicate with each other?

因此,如果您使用IP作为唯一ID,也可以获取其ID。 唯一的问题是ID不是连续的或从0开始,但是zookeeper / kafka似乎并不介意。

编辑1:

后续问题涉及配置Zookeeper:

每个ZK节点都需要知道其他节点。 Kubernetes发现服务知道服务中的节点,因此我们的想法是使用ZK节点启动服务

需要在创建Zookeeper pod的ReplicationController(RC)之前启动此服务。

ZK容器的启动脚本需要:

  • 等待发现服务用其节点填充ZK服务(这需要几秒钟,现在我只是在我的启动脚本的开头添加一个睡眠10但更可靠的是你应该寻找服务其中至少有3个节点。)
  • 在发现服务中查找构成服务的容器: 这是通过查询API完成的。 每个容器中都有KUBERNETES_SERVICE_HOST环境变量。 然后,找到服务描述的端点是

URL="http(s)://$USERNAME:$PASSWORD@${KUBERNETES_SERVICE_HOST/api/v1/namespaces/${NAMESPACE}/endpoints/${SERVICE_NAME}"

除非您更改NAMESPACE default,否则SERVICE_NAME如果您命名为服务管理员,则curl -s $URL | grep '\"ip\"' | awk '{print $2}' | awk -F\" '{print $2}' 将成为zookeeper。

您可以获得构成服务的容器的描述,其ip位于“ip”字段中。 你可以这样做:

curl -s --insecure

获取服务中的IP列表。 然后,使用上面定义的ID

填充节点上的zoo.cfg

您可能需要 USERNAME PASSWORD 才能访问google容器引擎等服务上的端点。这些需要放在密码卷中(请参阅此处的文档:http://kubernetes.io/v1.0/docs/user-guide/secrets.html

您还需要在Google容器引擎上使用{{1}},除非您在向容器中添加CA证书时遇到麻烦

基本上将卷添加到容器中,并从文件中查找值。 (与文档所说的相反,当base64编码时,不要将\ n放在用户名或密码的末尾:它只会让你的生活在阅读时变得更复杂)

编辑2:

您需要在Kafka节点上做的另一件事是获取IP和主机名,并将它们放在/ etc / hosts文件中。 Kafka似乎需要通过主机名知道节点,默认情况下这些节点不在服务节点中设置

编辑3:

经过多次试验后,使用IP作为ID的想法可能不会那么好:这取决于您如何配置存储。 对于像zookeeper,kafka,mongo,hdfs这样的任何类型的分布式服务,您可能想要使用emptyDir类型的存储,因此它只是在该节点上(安装远程存储类型会破坏分发这些服务的目的!) emptyDir将与同一节点上的数据进行重新连接,因此使用NODE ID(节点IP)作为ID似乎更合乎逻辑,因为在同一节点上重新启动的pod将具有该数据。 这样可以避免数据的潜在损坏(如果新节点开始在同一个dir中写入,实际上不是空的,谁知道会发生什么),还有Kafka,如果代理ID更改,主题被分配了broker.id, zookeeper没有更新主题broker.id,主题看起来像是可用但是指向错误的broker.id并且它是一团糟。

到目前为止,我还没有找到如何获取节点IP,但我认为可以通过查找服务pod名称然后查找部署它们的节点来查找API。

编辑4

要获取节点IP,您可以从端点API获取pod hostname == name / API / V1 /命名空间/默认/端点/ 如上所述。 然后你可以从pod名称中获取节点IP / API / V1 /命名空间/默认/荚/

PS:这是受Kubernetes回购中的示例启发的(此处为rethinkdb示例:https://github.com/kubernetes/kubernetes/tree/master/examples/rethinkdb

答案 1 :(得分:2)

看看 https://github.com/CloudTrackInc/kubernetes-kafka 它允许在kubernetes中启动Kafka并支持缩放和自动扩展。

答案 2 :(得分:2)

这在我的搜索中突出显示,但包含非常过时的信息。要使用更现代的解决方案进行更新,您应该使用StatefulSet部署,这将生成具有整数计数器而不是名称中的哈希的窗格,例如。卡夫卡控制器-0。

这当然是主机名,所以从那里使用awk提取固定的,不变的代理ID是一件简单的事情:

hostname | awk -F'-' '{print $3}'

最近Kafka最常用的容器有一个代理ID命令。

答案 3 :(得分:1)

我使用docker-compose做到了这一点(Kubernetes的不同之处在于您将通过service.yaml传递ID并提供2项服务):

kafka1:
  build: kafka-0.8.1/
  ports:
  - 9092
  links:
  - zookeeper
  environment:
  - ID=1
kafka2:
  build: kafka-0.8.1/
  ports:
  - 9092
  links:
  - zookeeper
  environment:
  - ID=2

<强>配置:

broker.id=${ID}
port=9092
advertised.host.name=${HOST}
advertised.port=9092
num.network.threads=3
num.io.threads=8
socket.send.buffer.bytes=102400
socket.receive.buffer.bytes=102400
socket.request.max.bytes=104857600
log.dirs=/kafka/kafka-logs-${ID}
num.partitions=200
num.recovery.threads.per.data.dir=1
log.retention.hours=168
log.segment.bytes=1073741824
log.retention.check.interval.ms=300000
log.cleaner.enable=false
zookeeper.connect=${DOCKER_ZOOKEEPER_1_PORT_2181_TCP_ADDR}:${DOCKER_ZOOKEEPER_1_PORT_2181_TCP_PORT}
zookeeper.connection.timeout.ms=6000

<强> SH:

#!/bin/bash
echo "Running config"
export HOST=`grep $HOSTNAME /etc/hosts | awk '{print $1}'`
export ID=${ID:?}
perl -p -i -e 's/\$\{([^}]+)\}/defined $ENV{$1} ? $ENV{$1} : $&/eg' < /broker.template > $KAFKA_HOME/config/server.properties
echo "Done"
echo "starting kafka with:"
echo "$KAFKA_HOME/config/server.properties"
echo ""
cat $KAFKA_HOME/config/server.properties
$KAFKA_HOME/bin/kafka-server-start.sh $KAFKA_HOME/config/server.properties