Azure容器实例中Docker Compose多容器(Zookeeper+Kafka+Python脚本)无法连接Kafka的问题求助
你遇到的核心问题是Azure容器实例(ACI)容器组的网络模型和本地Docker Compose的Bridge网络存在本质差异,导致容器名称解析失效。
为什么本地正常但Azure不行?
本地Docker Compose使用bridge网络时,每个容器拥有独立IP,Docker内置DNS会将服务名(比如kafka)解析为对应容器的IP,因此生产者能通过kafka:9092正常连接。
但Azure容器组内的所有容器共享同一个网络命名空间(相当于共用一个IP和端口栈),容器之间无法通过服务名/容器名称进行DNS解析,必须通过localhost+目标端口来互相访问。
具体修复步骤
1. 调整Kafka的监听与广告配置
修改docker-compose.yml中Kafka服务的环境变量,适配ACI的网络模型:
kafka: image: confluentinc/cp-kafka:latest container_name: kafka depends_on: - zookeeper ports: - 29092:29092 environment: KAFKA_BROKER_ID: 1 KAFKA_ZOOKEEPER_CONNECT: localhost:2181 # 同一网络栈下用localhost访问Zookeeper KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092,PLAINTEXT_HOST://<你的容器组公网IP或DNS>:29092 KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092,PLAINTEXT_HOST://0.0.0.0:29092 # 显式监听所有接口 KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
注:
<你的容器组公网IP或DNS>替换为ACI容器组的实际公网访问地址,如果不需要外部访问Kafka,也可以移除PLAINTEXT_HOST部分。
2. 修改Python生产者的连接地址
让生产者通过环境变量动态获取Kafka地址,同时适配本地和Azure环境:
import os from time import sleep import json from confluent_kafka import Producer def acked(err, msg): if err is not None: print("Failed to deliver message: {0}: {1}".format(msg.value(), err.str())) else: print("Message produced: {0}".format(msg.value())) def send_status(producer,counter): msg = {'counter':counter} json_dump = json.dumps(msg) producer.produce("counter", json_dump.encode('utf-8'), callback=acked) producer.poll() # 从环境变量取地址,本地默认用kafka:9092,Azure用localhost:9092 kafka_servers = os.getenv('KAFKA_SERVERS', 'kafka:9092') producer = Producer({'bootstrap.servers': kafka_servers}) for j in range(9999): print("Iteration", j) send_status(producer, j) sleep(2)
3. 同步更新生产者容器的环境变量
在docker-compose.yml的kafka_producer服务中,将连接地址改为localhost:9092:
kafka_producer: build: ../kafka_producer image: annabotkafka.azurecr.io/kafka_producer:v1 container_name: kafka_producer depends_on: - kafka volumes: - .:/usr/src/kafka_producer environment: KAFKA_SERVERS: localhost:9092
4. 移除不必要的自定义网络(可选)
ACI容器组默认共享网络,无需自定义my-network,可以删除docker-compose.yml中的networks节点,简化配置。
验证与后续扩展
修改完成后,重新构建镜像并推送到Azure容器注册表(ACR),再通过az container create --file docker-compose.yml --resource-group <你的资源组>部署到ACI,生产者应该能正常连接Kafka并发送消息。
如果后续需要部署多个Python脚本容器,只需保证它们和Kafka/Zookeeper在同一个ACI容器组内,并且都用localhost+对应端口访问即可。
内容的提问来源于stack exchange,提问作者db533

