You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker Compose部署Web应用连接Kafka失败问题排查

问题

我尝试用Docker Compose将应用容器化,启动ZooKeeper、Kafka和humanresources三个容器。我的docker-compose配置如下:

version: '3'
services:
  zookeeper:
    image: wurstmeister/zookeeper
    ports:
    - "2181:2181"
  kafka:
    image: wurstmeister/kafka
    ports:
    - "9092:9092"
    depends_on:
       - zookeeper
    healthcheck:
      test: nc -z localhost 9092 || exit -1
      start_period: 15s
      interval: 5s
      timeout: 10s
      retries: 10
    environment:
      KAFKA_ADVERTISED_HOST_NAME: 127.0.0.1
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_AUTO_CREATE_TOPICS_ENABLE: 'false' 
  humanresources:
      image: univer-anu4/humanresources:latest
      ports:
       - "8081:8081"
      depends_on:
        kafka:
          condition: service_healthy
      deploy:
        restart_policy:
          condition: on-failure
          delay: 10s
          max_attempts: 3
          window: 30s  

每次执行docker compose up时,都会出现如下错误:

compose-humanresources-1  | 2022-11-19 09:14:59.941  WARN 1 --- [| adminclient-1] org.apache.kafka.clients.NetworkClient   : [AdminClient clientId=adminclient-1] Connection to node -1 (localhost/127.0.0.1:9092) could not be established. Broker may not be available.

但如果从Docker Compose中移除humanresources服务,仅启动ZooKeeper和Kafka容器,然后在IntelliJ IDEA中启动应用却能正常运行。请问这是什么原因?

我的application.properties配置如下:

spring.h2.console.enabled=true

spring.datasource.url=jdbc:h2:mem:DB
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.kafka.template.default-topic=pad2
eureka.client.service-url.defaultZone = http://localhost:7080/eureka/
kafka.bootstrapAddress = localhost:9092
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update
spring.flyway.locations=classpath:db/migration
spring.flyway.enabled=true
spring.application.name=hr

eureka.instance.prefer-ip-address=true
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true
eureka.instance.lease-renewal-interval-in-seconds=30
spring.kafka.consumer.group-id=${random.uuid}

原因与解决方案

核心原因

  1. 容器网络隔离限制:Docker Compose的默认网络里,每个容器都是独立节点,localhost在humanresources容器中指向容器自身,而非宿主机或Kafka容器。本地IDEA启动应用时,localhost指向宿主机,此时Kafka端口已映射到宿主机9092,所以能正常连接。
  2. Kafka地址配置错误:当前Kafka的KAFKA_ADVERTISED_HOST_NAME设为127.0.0.1,会导致Kafka向客户端返回自身地址为127.0.0.1,容器内应用拿到地址后会尝试连接自身的9092端口,必然失败。

解决步骤

1. 修改Kafka的环境变量配置

调整docker-compose.yml中Kafka的环境变量,同时支持容器内部和宿主机的连接:

kafka:
  # 保留原有其他配置
  ports:
  - "9092:9092"
  - "9093:9093"
  environment:
    KAFKA_ADVERTISED_LISTENERS: INSIDE://kafka:9093,OUTSIDE://localhost:9092
    KAFKA_LISTENERS: INSIDE://0.0.0.0:9093,OUTSIDE://0.0.0.0:9092
    KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT
    KAFKA_INTER_BROKER_LISTENER_NAME: INSIDE
    KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
    KAFKA_AUTO_CREATE_TOPICS_ENABLE: 'false'
  • KAFKA_ADVERTISED_LISTENERS:对外宣告的监听地址,INSIDE供容器内部使用(用服务名kafka作为地址),OUTSIDE供宿主机使用。
  • KAFKA_LISTENERS:Kafka实际监听的端口,9093用于容器内部通信,9092映射到宿主机。

2. 更新应用的Kafka连接配置

修改application.properties中的Kafka地址,让容器内应用通过服务名连接Kafka:

kafka.bootstrapAddress = kafka:9093
spring.kafka.bootstrap-servers = ${kafka.bootstrapAddress}

3. 调整Kafka的健康检查规则

因为Kafka现在监听内部端口9093,健康检查需要对应修改:

kafka:
  # 保留原有其他配置
  healthcheck:
    test: nc -z localhost 9093 || exit -1
    start_period: 15s
    interval: 5s
    timeout: 10s
    retries: 10

4. 重新部署容器

执行以下命令重启服务:

docker compose down
docker compose up -d

修改完成后,容器内的humanresources应用会通过kafka:9093连接Kafka,宿主机本地应用依然可以用localhost:9092连接,两种场景都能正常运行。

内容的提问来源于stack exchange,提问作者Gumaniuc Alexandru

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 04:55:19