Docker / Kafka连接两个不同的容器

时间:2019-06-13 08:05:53

标签: docker apache-kafka docker-compose

我正在使用wurstmeister's docker-kafka项目在容器中运行kafka / zookeeper。我使用localhost作为KAFKA_ADVERTISED_HOST_NAME: localhost变量,对Docker组成了容器。

我编写了一个Java应用程序,该应用程序使用flink连接和使用此Kafka容器的主题之一。如果我导出一个可运行的jar并从我的机器上运行它,那么它绝对可以正常工作。当我创建以下图像以从另一个docker容器运行jar时,我收到一个异常(执行后约30秒)Exception in thread "main" org.apache.flink.runtime.client.JobExecutionException: org.apache.kafka.common.errors.TimeoutException: Timeout expired while fetching topic metadata,我认为这与我的Java程序无法与正在运行的Kafka服务器进行通信有关在另一个容器中。

这是我的Java应用程序的dockerfile:

# Dockerfile

FROM anapsix/alpine-java

MAINTAINER myself myself

COPY myApp.jar /home/myApp.jar

CMD ["java","-jar","/home/myApp.jar"]

这是wurstmeister的docker kafka的docker-compose.yml:

version: "3.5"

networks:
  myNetwork:
    name: myNetwork
    driver: bridge

services:
  zookeeper:
    image: wurstmeister/zookeeper
    ports:
      - "2181:2181"
    networks:
      - myNetwork
  kafka:
    build: .
    ports:
      - "9092:9092"
    environment:
      KAFKA_ADVERTISED_HOST_NAME: localhost
      KAFKA_ADVERTISED_PORT: "9092"
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true"
      ALLOW_PLAINTEXT_LISTENER: "yes"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - myNetwork
  auth_analytics:
      build: 
        context: .
        dockerfile: auth_dockerfile
      depends_on:
        - kafka
      networks:
        - myNetwork

我已经尝试了以上版本。最初,我没有设置任何我认为可能是问题的网络,但是创建网络的上述操作没有任何区别。我在Java应用程序中尝试将“ localhost:9092”作为引导服务器,并在网上阅读时尝试了“ myNetwork:9092”。

我也从wurstmeister阅读了FAQ的有关连通性的信息,但是我的设置没有出现任何问题。

我还尝试了不使用docker-compose运行我的Java应用程序映像(我运行了docker-compose以启动zookeeper / kafka,然后我做了一个docker构建,docker在我的Java应用程序的映像上运行。没什么。

我被困住了。我在做什么错了?

2 个答案:

答案 0 :(得分:2)

您需要正确设置KAFKA_ADVERTISED_LISTENERS。目前是localhost,这意味着代理将告知任何客户端连接,代理处于localhost上,并且当客户端尝试连接时,它将失败(除非Kafka代理实际上可以在localhost上使用,而不会在仅运行您的应用程序的Docker容器上使用)。

解决方案是定义侦听器,以便可以从任何需要它的代理和客户端位置对其进行寻址。我的首选方法是this,您可以通过一种方法进行容器内通信,而通过主机进行通信:

  KAFKA_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092
  KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
  KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
  KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092

您在Docker网络上的客户端使用kafka:29092进行连接;主机上的客户端在localhost:9092上连接(并确保您通过Docker将9092公开给主机)。

要了解更多信息,请参阅https://rmoff.net/2018/08/02/kafka-listeners-explained/

顺便说一句,我强烈建议您以适当的方式修复此问题;覆盖/etc/hosts文件是一种无法解决IMO实际问题的黑客。

答案 1 :(得分:1)

KAFKA_ADVERTISED_HOST_NAME: localhost

是您的客户端将收到的与Kafka的连接字符串。这意味着带有您的应用程序的容器将尝试到达localhost的Kafka,其中localhost是带有您的应用程序的容器的本地网络堆栈。

要解决该问题,您应该使用kafka主机作为您的KAFKA_ADVERTISED_HOST_NAME和引导服务器-这将允许您的容器在docker内部连接到kafka,但是当您尝试通过在PC上运行来连接到Kafka时会破坏配置java -jar ...

要解决该问题,请使用映射kafka-> localhost在PC上的主机文件中输入。