Previously we achieved to have our Kafka brokers connect to a ZooKeeper ensemble. Also we brought down some brokers checked the election leadership and produced/consumed some messages.
For now we want to make sure that we will be able to connect to those nodes. The problem with connecting to the ensemble we created previously is that it is located inside the container network. When a client interacts with one of the brokers and receives the full list of the brokers he will receive a list of IPs not accessible to it.
So the initial handshake of a client will be successful but then the client will try to interact withs some unreachable hosts.
In order to tackle this we will have a combination of workarounds.
The first one would be to bind the port of each Kafka broker to a different local ip.
kafka-1 will be mapped to 127.0.0.1:9092
kafka-2 will be mapped to 127.0.0.2:9092
kafka-3 will be mapped to 127.0.0.3:9092
So let’s create the aliases of those addresses
sudo ifconfig lo0 alias 127.0.0.2 sudo ifconfig lo0 alias 127.0.0.3
Now it’s possible to do the ip binding. Let’s also put those entries to our /etc/hosts. By doing this, we achieve our local network and our docker network to be in agreement on which broker they should access.
127.0.0.1 kafka-1 127.0.0.2 kafka-2 127.0.0.3 kafka-3
The next step is also to change the KAFKA_ADVERTISED_LISTENERS on each broker. We will adapt this to the DNS entry of each broker. By setting KAFKA_ADVERTISED_LISTENERS the clients from the outside can correctly connect to it, to an address reachable to them and not an address through the internal network. Further explanations can be found on this blog.
kafka-1: container_name: kafka-1 image: confluent/kafka ports: - "127.0.0.1:9092:9092" volumes: - type: bind source: ./server1.properties target: /etc/kafka/server.properties depends_on: - zookeeper-1 - zookeeper-2 - zookeeper-3 environment: KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://kafka-1:9092" kafka-2: container_name: kafka-2 image: confluent/kafka ports: - "127.0.0.2:9092:9092" volumes: - type: bind source: ./server2.properties target: /etc/kafka/server.properties depends_on: - zookeeper-1 - zookeeper-2 - zookeeper-3 environment: KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://kafka-2:9092" kafka-3: container_name: kafka-3 image: confluent/kafka ports: - "127.0.0.3:9092:9092" volumes: - type: bind source: ./server3.properties target: /etc/kafka/server.properties depends_on: - zookeeper-1 - zookeeper-2 - zookeeper-3 environment: KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://kafka-3:9092"
We see the port binding change as well as the KAFKA_ADVERTISED_LISTENERS. Now let’s wrap everything together in our docker-compose
version: "3.8" services: zookeeper-1: container_name: zookeeper-1 image: zookeeper ports: - "2181:2181" environment: ZOO_MY_ID: "1" ZOO_SERVERS: server.1=0.0.0.0:2888:3888;2181 server.2=zookeeper-2:2888:3888;2181 server.3=zookeeper-3:2888:3888;2181 zookeeper-2: container_name: zookeeper-2 image: zookeeper ports: - "2182:2181" environment: ZOO_MY_ID: "2" ZOO_SERVERS: server.1=zookeeper-1:2888:3888;2181 server.2=0.0.0.0:2888:3888;2181 server.3=zookeeper-3:2888:3888;2181 zookeeper-3: container_name: zookeeper-3 image: zookeeper ports: - "2183:2181" environment: ZOO_MY_ID: "3" ZOO_SERVERS: server.1=zookeeper-1:2888:3888;2181 server.2=0.0.0.0:2888:3888;2181 server.3=zookeeper-3:2888:3888;2181 kafka-1: container_name: kafka-1 image: confluent/kafka ports: - "127.0.0.1:9092:9092" volumes: - type: bind source: ./server1.properties target: /etc/kafka/server.properties depends_on: - zookeeper-1 - zookeeper-2 - zookeeper-3 environment: KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://kafka-1:9092" kafka-2: container_name: kafka-2 image: confluent/kafka ports: - "127.0.0.2:9092:9092" volumes: - type: bind source: ./server2.properties target: /etc/kafka/server.properties depends_on: - zookeeper-1 - zookeeper-2 - zookeeper-3 environment: KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://kafka-2:9092" kafka-3: container_name: kafka-3 image: confluent/kafka ports: - "127.0.0.3:9092:9092" volumes: - type: bind source: ./server3.properties target: /etc/kafka/server.properties depends_on: - zookeeper-1 - zookeeper-2 - zookeeper-3 environment: KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://kafka-3:9092"
You can find more on Compose on the Developers Essential Guide to Docker Compose.
Last but not least you can find the code on github.
One thought on “Kafka & Zookeeper for Development: Connecting Clients to the Cluster”