无法从容器外部运行的Spring Boot应用程序连接到容器中运行的Kafka

时间:2018-10-31 18:00:48

标签: java docker spring-boot apache-kafka spring-kafka

我通过以下方式在本地运行kafka:

docker-compose.yml

  zookeeper:
    image: 'bitnami/zookeeper:latest'
    ports:
      - 2181:2181
    environment:
      - ALLOW_ANONYMOUS_LOGIN=yes
  kafka:
    image: 'bitnami/kafka:latest'
    ports:
      - 9092:9092
    environment:
      - KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
      - ALLOW_PLAINTEXT_LISTENER=yes
      - KAFKA_ADVERTISED_PORT=9092
      - KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092

我的Spring Boot应用程序运行于:

application.yml:

spring:
  application:
    name: testkafka
  kafka:
    bootstrap-servers: localhost:9092

server:
  port: 8080

当我运行它并尝试将其发送到有关kafka的主题时,我得到:

org.springframework.kafka.KafkaException: Reply timed out
    at org.springframework.kafka.requestreply.ReplyingKafkaTemplate.lambda$sendAndReceive$0(ReplyingKafkaTemplate.java:196) ~[spring-kafka-2.1.10.RELEASE.jar:2.1.10.RELEASE]
    at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) ~[na:na]
    at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264) ~[na:na]
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java) ~[na:na]
    at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) ~[na:na]
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
    at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]

如果我从一个docker容器内部运行spring boot(使用一个docker compose文件),那么它确实起作用:

同时运行两个文件:

version: "3.0"
services:
  service1:
    build: ./Service
    ports:
      - 8080:8080
      - 5005:5005
    links:
      - zookeeper
      - kafka
  zookeeper:
    image: 'bitnami/zookeeper:latest'
    ports:
      - 2181:2181
    environment:
      - ALLOW_ANONYMOUS_LOGIN=yes
  kafka:
    image: 'bitnami/kafka:latest'
    ports:
      - 9092:9092
    environment:
      - KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
      - ALLOW_PLAINTEXT_LISTENER=yes
      - KAFKA_ADVERTISED_PORT=9092
      - KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092

如何获取kafka容器以允许来自外部/ docker的连接?

编辑:尝试了以下更改:

kafka:
  image: 'bitnami/kafka:latest'
  ports:
    - 9092:9092
  environment:
    - KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
    - ALLOW_PLAINTEXT_LISTENER=yes
    - KAFKA_ADVERTISED_PORT=9092
    - KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092

和:

spring:
  application:
    name: testkafka
  kafka:
    bootstrap-servers: kafka:9092

server:
  port: 8080

这仍然超时

1 个答案:

答案 0 :(得分:3)

  

如果我从docker容器内部运行spring boot(使用一个docker compose文件),那么它确实起作用

实际上不应该。 Kafka并未作为应用程序的一部分运行,因此本节未针对Kafka容器。

kafka:
    bootstrap-servers: localhost:9092

它必须在Docker网络中为kafka:9092

在Docker网络的内部和外部,通过指定KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092表示您的客户端收到localhost:9092的Kafka引导程序连接,该连接仅在Docker网络外部有效,进行了端口转发,并且您的容器在localhost上运行,但是,如前所述,在Docker网络内部,localhost表示那个应用程序容器,而不是代理。

解决方案是通过该属性创建两个端口映射,如this blog post

所讨论的那样。

此外,Confluent provides a fully configured Docker Compose具有适用于Docker内部和外部的适当映射

ports:
  - "9092:9092"
  - "29092:29092"
environment:
  KAFKA_BROKER_ID: 1
  KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181'
  ALLOW_PLAINTEXT_LISTENER: "yes"
  KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
  KAFKA_LISTENERS=PLAINTEXT://:9092,PLAINTEXT_HOST://:29092
  KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092

对于Docker网络中的应用程序,使用kafka:9092,对于外部的应用程序,使用 localhost:29092