Keywords: Kafka | Docker | AdminClient | Timeout | Configuration
Abstract: This article addresses the timeout issue encountered when using Kafka AdminClient in Docker environments, focusing on misconfigurations of listeners and advertised.listeners. By analyzing the root cause and providing a step-by-step solution based on best practices, it helps users correctly configure Kafka network settings to ensure connectivity from the host to Docker container services.
Problem Description
When running Kafka with Docker Compose, many developers face a TimeoutException: Timed out waiting for a node assignment error while attempting to create topics using Scala's AdminClient API. In contrast, the command-line tool kafka-topics successfully creates topics, highlighting the impact of configuration differences on client connectivity.
Cause Analysis
The root cause of this issue lies in the configuration of Kafka's listeners and advertised.listeners. In Docker environments, Kafka runs inside containers, while clients typically operate on the host machine. The advertised.listeners parameter specifies the addresses that clients should connect to. In common Docker Compose setups, such as setting KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092, the PLAINTEXT_HOST://localhost:9092 part instructs clients to connect to localhost:9092 on the host. However, due to Docker's network isolation, if the Kafka broker does not properly advertise this address to clients, AdminClient times out when attempting to connect.
AdminClient initializes via the BOOTSTRAP_SERVERS_CONFIG setting (e.g., set to "localhost:9092"), but if Kafka's listeners are not correctly listening or advertising that address, the connection fails. This differs from command-line tools that operate directly through ZooKeeper, which does not rely on broker network advertising mechanisms.
Solution
Based on best practices, correctly configuring KAFKA_ADVERTISED_LISTENERS is key. Here is an example of corrected environment variables in Docker Compose to ensure host accessibility:
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT://localhost:9092
Alternatively, use the host's actual IP address instead of localhost, depending on the network setup. Also, ensure consistency in KAFKA_LISTENER_SECURITY_PROTOCOL_MAP and KAFKA_INTER_BROKER_LISTENER_NAME configurations to avoid protocol mismatches.
In the Scala code, rewrite the AdminClient configuration to match these settings:
val props = new Properties()
props.setProperty(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092")
val adminClient: AdminClient = AdminClient.create(props)
val newTopic = new NewTopic("test", 1, 1.toShort)
val topicsF = adminClient.createTopics(List(newTopic).asJavaCollection)
try {
val result = topicsF.all().get()
println("Topic created successfully")
} catch {
case e: Exception => println("Error: " + e.getMessage)
}
This code initializes AdminClient with bootstrap servers addresses that align with the configured listeners. If Kafka runs in Docker, ensure listeners are set to PLAINTEXT://0.0.0.0:9092 to listen on all network interfaces, allowing host connections.
Additional References
Other approaches include directly modifying Kafka's server.properties file, such as enabling the listeners=PLAINTEXT://localhost:9092 line. This can be done via Docker Compose environment variables or volume mounts, but it is less flexible and maintainable than configuring through environment variables.
Conclusion
Timeout issues when using Kafka AdminClient in Docker environments often stem from improper network configurations. By carefully adjusting listeners and advertised.listeners, developers can ensure reliable client connectivity to Kafka services. The solutions provided in this article, based on real-world cases, help avoid common configuration pitfalls and improve development and testing efficiency.