I setup a single node Kafka Docker container on my local machine like it is described in the Confluent documentation (steps 2-3).
In addition, I also exposed Zookeeper's port 2181 and Kafka's port 9092 so that I'll be able to connect to them from a client running on local machine:
$ docker run -d \
-p 2181:2181 \
--net=confluent \
--name=zookeeper \
-e ZOOKEEPER_CLIENT_PORT=2181 \
confluentinc/cp-zookeeper:4.1.0
$ docker run -d \
--net=confluent \
--name=kafka \
-p 9092:9092 \
-e KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 \
-e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092 \
-e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 \
confluentinc/cp-kafka:4.1.0
Problem: When I try to connect to Kafka from the host machine, the connection fails because it can't resolve address: kafka:9092
.
Here is my Java code:
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("client.id", "KafkaExampleProducer");
props.put("key.serializer", LongSerializer.class.getName());
props.put("value.serializer", StringSerializer.class.getName());
KafkaProducer<Long, String> producer = new KafkaProducer<>(props);
ProducerRecord<Long, String> record = new ProducerRecord<>("foo", 1L, "Test 1");
producer.send(record).get();
producer.flush();
The exception:
java.io.IOException: Can't resolve address: kafka:9092
at org.apache.kafka.common.network.Selector.doConnect(Selector.java:235) ~[kafka-clients-2.0.0.jar:na]
at org.apache.kafka.common.network.Selector.connect(Selector.java:214) ~[kafka-clients-2.0.0.jar:na]
at org.apache.kafka.clients.NetworkClient.initiateConnect(NetworkClient.java:864) [kafka-clients-2.0.0.jar:na]
at org.apache.kafka.clients.NetworkClient.ready(NetworkClient.java:265) [kafka-clients-2.0.0.jar:na]
at org.apache.kafka.clients.producer.internals.Sender.sendProducerData(Sender.java:266) [kafka-clients-2.0.0.jar:na]
at org.apache.kafka.clients.producer.internals.Sender.run(Sender.java:238) [kafka-clients-2.0.0.jar:na]
at org.apache.kafka.clients.producer.internals.Sender.run(Sender.java:176) [kafka-clients-2.0.0.jar:na]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_144]
Caused by: java.nio.channels.UnresolvedAddressException: null
at sun.nio.ch.Net.checkAddress(Net.java:101) ~[na:1.8.0_144]
at sun.nio.ch.SocketChannelImpl.connect(SocketChannelImpl.java:622) ~[na:1.8.0_144]
at org.apache.kafka.common.network.Selector.doConnect(Selector.java:233) ~[kafka-clients-2.0.0.jar:na]
... 7 common frames omitted
Question: How to connect to Kafka running in Docker? My code is running from host machine, not Docker.
Note: I know that I could theoretically play around with DNS setup and /etc/hosts
but it is a workaround - it shouldn't be like that.
There is also similar question here, however it is based on ches/kafka
image. I use confluentinc
based image which is not the same.
tl;dr - At the end of the day, it's all the same Apache Kafka running in a container. You're just dependent on how it is configured. And which variables make it so.
The following uses
confluentinc
docker images, notwurstmeister/kafka
, although there is a similar configuration, I have not tried it. If using that image, read their Connectivity wiki.
Nothing against the
wurstmeister
image, but it's community maintained, not built in an automated CI/CD release... Bitnami ones are similarly minimalistic and run in multiple cloud providers. Forbitnami
Kafka images, refer their README
debezium/kafka
docs on it are mentioned here. Note: advertised host and port settings are deprecated. Advertised listeners covers both
spotify/kafka
is deprecated and outdated.fast-data-dev
is great for an all in one solution, but it is bloated
For supplemental reading, a fully-functional
docker-compose
, and network diagrams, see this blog by @rmoff
The Confluent quickstart (Docker) document assumes all produce and consume requests will be within the Docker network.
You could fix the problem by running your Kafka client code within its own container, but otherwise you'll need to add some more environment variables for exposing the container externally, while still having it work within the Docker network.
First add a protocol mapping of PLAINTEXT_HOST:PLAINTEXT
that will map the listener protocol to a Kafka protocol
Key: KAFKA_LISTENER_SECURITY_PROTOCOL_MAP
Value: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
Then setup two advertised listeners on different ports. (kafka:9092
here refers to the docker container name). Notice the protocols match the right side values of the mappings above
Key: KAFKA_ADVERTISED_LISTENERS
Value: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092
When running the container, add -p 29092:29092
for the host port mapping
tl;dr (with the above settings)
When running any Kafka Client outside the Docker network (including CLI tools you might have installed locally), use localhost:29092
for bootstrap servers and localhost:2181
for Zookeeper
If trying to connect from an external server, you'll need to advertise the external hostname/ip of the host as well/in place of localhost
When running an app in the Docker network, use kafka:9092
for bootstrap servers and zookeeper:2181
for Zookeeper, just like any other Docker service communication
See the example Compose file for the full Confluent stack
For anyone interested in Kubernetes deployments: https://operatorhub.io/?keyword=Kafka