Architecting Event Streaming Infrastructures with Apache Kafka and Docker

Apache Kafka has established itself as the industry standard for the construction of real-time data pipelines and the deployment of streaming applications. At its core, Kafka is a distributed event streaming platform designed to facilitate the reading, writing, storing, and processing of events—alternatively referred to as records or messages—across a cluster of multiple machines. These events encompass a vast array of real-world data points, such as payment transactions, geolocation updates transmitted from mobile devices, shipping orders, and sensor measurements originating from medical equipment or IoT devices. To manage these streams, Kafka organizes events into topics; conceptually, a topic functions similarly to a folder within a filesystem, where the events act as the individual files stored within that folder. Because of this architecture, the creation of a topic is a mandatory prerequisite before any events can be written to the system.

The integration of Kafka within Docker containers fundamentally transforms the development lifecycle by simplifying the processes of development, testing, and deployment. By containerizing the broker, developers can abstract the underlying infrastructure, ensuring that the environment remains consistent from a local laptop to a staging server. Whether utilizing the official Apache images or third-party distributions like Bitnami, Docker provides the necessary isolation and orchestration capabilities to deploy Kafka without the friction of manual installation and complex dependency management on the host operating system.

Fundamental Deployment Methodologies

There are multiple pathways to initializing a Kafka environment, ranging from raw binary installations to high-level container orchestration.

Native Binary Installation

For users requiring a non-containerized setup or those performing low-level debugging, Kafka can be run using local scripts. This process requires a host environment with Java 17 or higher installed. The sequence of operations is as follows:

  1. Download and extract the latest release:
    tar -xzf kafka_2.13-4.2.0.tgz
  2. Navigate to the extracted directory:
    cd kafka_2.13-4.2.0
  3. Generate a unique cluster identifier:
    KAFKA_CLUSTER_ID="$(bin/kafka-storage.sh random-uuid)"
  4. Format the log directories using the generated ID:
    bin/kafka-storage.sh format --standalone -t $KAFKA_CLUSTER_ID -c config/server.properties
  5. Launch the server:
    bin/kafka-server-start.sh config/server.properties

Single-Container Rapid Deployment

For the fastest path to a running broker, Docker images provided by Apache allow for immediate execution. Depending on the specific requirements for the runtime environment, users can choose between the standard image or the native image.

To pull and run the standard Apache Kafka image:
docker pull apache/kafka:4.2.0
docker run -p 9092:9092 apache/kafka:4.2.0

To pull and run the native Apache Kafka image:
docker pull apache/kafka-native:4.2.0
docker run -p 9092:9092 apache/kafka-native:4.2.0

Deep Dive into Docker Compose Configurations

Docker Compose allows for the definition of complex multi-container environments. Depending on the use case—whether it is a simple development sandbox or a production-like cluster—the configuration varies significantly.

Development-Centric Single Broker Setup

A development setup focuses on ease of use and minimal resource consumption. In such environments, replication factors are typically set to 1, as there is no need for high availability across multiple nodes.

The following configuration demonstrates a streamlined setup using the latest Apache image:

yaml services: broker: image: apache/kafka:latest hostname: broker container_name: broker ports: - 9092:9092 environment: KAFKA_BROKER_ID: 1 KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT,CONTROLLER:PLAINTEXT KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://broker:29092,PLAINTEXT_HOST://localhost:9092 KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0 KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1 KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1 KAFKA_PROCESS_ROLES: broker,controller KAFKA_NODE_ID: 1 KAFKA_CONTROLLER_QUORUM_VOTERS: 1@broker:29093 KAFKA_LISTENERS: PLAINTEXT://broker:29092,CONTROLLER://broker:29093,PLAINTEXT_HOST://0.0.0.0:9092 KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER KAFKA_LOG_DIRS: /tmp/kraft-combined-logs CLUSTER_ID: MkU3OEVBNTcwNTJENDM2Qk

In this configuration, the KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR and KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR are set to 1. This is a critical technical requirement for single-node clusters because Kafka cannot replicate data to other brokers that do not exist; attempting to use a replication factor of 3 on a single broker would lead to a failure in topic creation.

Bitnami Distribution Configuration

Bitnami provides an alternative set of images with different environment variable naming conventions (using the KAFKA_CFG_ prefix).

For a basic development setup:

yaml version: "3" services: kafka: image: bitnami/kafka:latest ports: - 9092:9092 environment: - KAFKA_CFG_NODE_ID=0 - KAFKA_CFG_PROCESS_ROLES=controller,broker - KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093 - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT - KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER

To enable the automatic creation of topics, which is useful for rapid prototyping, the following variable can be added:
KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE=true

Advanced Networking and Listener Management

One of the most complex aspects of running Kafka in Docker is managing the listeners. Kafka requires a clear distinction between how it listens for traffic and how it tells clients to connect to it.

Internal vs. External Client Access

To support both internal Docker network communication and external host-machine access, multiple listeners must be configured. This is achieved by mapping the KAFKA_CFG_LISTENERS and KAFKA_CFG_ADVERTISED_LISTENERS.

Configuration for hybrid access:

yaml environment: - KAFKA_CFG_NODE_ID=0 - KAFKA_CFG_PROCESS_ROLES=controller,broker - KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:9094 - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092,EXTERNAL://localhost:9094 - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,PLAINTEXT:PLAINTEXT - KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER ports: - 9092:9092 - 9094:9094

The PLAINTEXT listener is used for internal communication between containers, while the EXTERNAL listener allows a developer on the host machine to connect via localhost:9094. This prevents the "connection refused" errors that occur when a client receives an advertised listener address that is only reachable inside the Docker network.

High Availability and Multi-Broker Clusters

For production-like environments, a single broker is a single point of failure. High availability is achieved through a multi-broker cluster, which requires more rigorous configuration of roles and quorum/voting mechanisms.

The KRaft Mode and Role Distribution

In modern Kafka deployments, the dependency on Zookeeper has been replaced by KRaft. Roles are defined by KAFKA_PROCESS_ROLES, which can be:
- broker: Handles data storage and client requests.
- controller: Manages the cluster metadata and quorum.
- broker,controller: A combined mode where the node performs both functions.

Multi-Broker Architectural Configuration

A three-broker cluster requires coordinated voting to maintain consistency. This is defined by the KAFKA_CONTROLLER_QUORUM_VOTERS variable, which maps node IDs to their controller addresses.

Example Multi-Broker Setup:

Parameter Value for Broker 1 Value for Broker 2 Value for Broker 3
KAFKANODEID 1 2 3
KAFKAPROCESSROLES broker,controller broker,controller broker,controller
KAFKAADVERTISEDLISTENERS PLAINTEXT://kafka-1:9092 PLAINTEXT://kafka-2:9092 PLAINTEXT://kafka-3:9092
Port Mapping 9092:9092 9093:9092 9094:9092

Full Multi-Broker YAML Fragment:

yaml version: '3.8' services: kafka-1: image: apache/kafka:3.7.0 container_name: kafka-1 ports: - "9092:9092" environment: KAFKA_NODE_ID: 1 KAFKA_PROCESS_ROLES: broker,controller KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093 KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka-1:9092 KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka-1:9093,2@kafka-2:9093,3@kafka-3:9093 KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 3 KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 3 KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 2 KAFKA_NUM_PARTITIONS: 3 KAFKA_DEFAULT_REPLICATION_FACTOR: 3 KAFKA_MIN_INSYNC_REPLICAS: 2 volumes: - kafka-1-data:/var/lib/kafka/data networks: - kafka-network

In this high-availability configuration:
- KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 3 ensures that the internal offset topic is mirrored across all three brokers.
- KAFKA_MIN_INSYNC_REPLICAS: 2 requires at least two replicas to acknowledge a write, ensuring data durability even if one broker fails.
- KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 2 maintains the integrity of transactional logs.

Operational Maintenance and Verification

Once the containers are deployed, it is necessary to verify the health of the cluster and manage the topics.

Launching the Environment

To start the containers in detached mode, execute:
docker-compose up -d

Verifying Cluster State

To check if Kafka is running and to list the existing topics, you can execute a command directly inside the running container:

docker exec -it kafka /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --list

Advanced Orchestration with Health Checks

In complex environments where other services (like Kafka UI or a consumer application) depend on the broker, the depends_on property with a service_healthy condition should be used. This ensures that the application does not attempt to connect to the broker before it has fully initialized its log directories and joined the quorum.

Example:
yaml kafka-ui: depends_on: kafka: condition: service_healthy

Technical Summary of Configurations

The following table provides a comparative analysis of the different deployment modes discussed.

Feature Single-Node (Dev) Multi-Broker (Prod-like) Bitnami Setup
Image apache/kafka:latest apache/kafka:3.7.0 bitnami/kafka:latest
Replication Factor 1 3 Configurable
Min ISR 1 2 Configurable
Quorum Voters Single node 3-node list Configurable
Use Case Local prototyping High Availability testing Enterprise/Customized

Conclusion

The deployment of Apache Kafka via Docker provides a powerful abstraction that allows engineers to transition from a simple single-node development environment to a sophisticated multi-broker cluster with minimal friction. While the single-node setup is ideal for initial development—where replication factors are set to 1 and minimal resources are used—the transition to a multi-broker architecture is essential for simulating production environments. This requires a deep understanding of KRaft roles, where nodes can act as brokers, controllers, or both, and the implementation of a quorum via KAFKA_CONTROLLER_QUORUM_VOTERS.

Furthermore, the mastery of listeners is paramount. By distinguishing between internal and external advertised listeners, developers can ensure that their host-machine applications can communicate with the containerized brokers without network resolution errors. For those moving beyond Docker Compose toward full-scale production, the use of dedicated Kubernetes operators like Strimzi is recommended. Such operators provide the necessary automation for upgrades, monitoring, and security configurations that exceed the capabilities of standard Compose files. Ultimately, the choice between the official Apache images and the Bitnami distribution depends on the preferred environment variable naming conventions and the specific need for automated topic creation.

Sources

  1. OneUptime Blog
  2. Apache Kafka Quickstart
  3. Confluent Tutorials - Kafka on Docker
  4. Docker Hub - Bitnami Kafka
  5. Docker Hub - Apache Kafka

Related Posts