Single-Broker KRaft Cluster

A Single-Broker KRaft Cluster in Docker Compose

The image maps environment variables to properties (KAFKA_NUM_PARTITIONS becomes num.partitions), and setting any of them replaces its whole default configuration, so a Compose file must supply the full KRaft minimum. This combined node has three listeners: DOCKER for containers on the l3-booknest network, CONTROLLER for the quorum, and HOST for programs on the workstation, published on port 33092.

compose/single.yaml: one broker and controller for BookNestYAML
# single.yaml: one combined broker and controller in KRaft mode (Kafka 4.3.1)
name: l3-kafka
services:
  kafka:
    image: apache/kafka:4.3.1
    container_name: l3-kafka
    ports: ["33092:9094"]                    # host clients use localhost:33092
    environment:
      CLUSTER_ID: BlU5rkQ7TciwZo42azfLxA
      KAFKA_NODE_ID: 1
      KAFKA_PROCESS_ROLES: broker,controller
      KAFKA_CONTROLLER_QUORUM_VOTERS: 1@l3-kafka:9093
      KAFKA_LISTENERS: DOCKER://:9092,CONTROLLER://:9093,HOST://:9094
      KAFKA_ADVERTISED_LISTENERS: DOCKER://l3-kafka:9092,HOST://localhost:33092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: >-
        DOCKER:PLAINTEXT,CONTROLLER:PLAINTEXT,HOST:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: DOCKER
      KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
      KAFKA_LOG_DIRS: /var/lib/kafka/data
      KAFKA_NUM_PARTITIONS: 3
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1          # one broker cannot hold
      KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1  # three copies of the
      KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1             # internal topics
      KAFKA_SHARE_COORDINATOR_STATE_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_SHARE_COORDINATOR_STATE_TOPIC_MIN_ISR: 1
      KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
      KAFKA_HEAP_OPTS: "-Xms512m -Xmx512m"
    volumes: ["kafka-data:/var/lib/kafka/data"]
    healthcheck:
      test: /opt/kafka/bin/kafka-broker-api-versions.sh --bootstrap-server l3-kafka:9092
      interval: 5s
volumes: {kafka-data: {name: l3-kafka-data}}
networks: {default: {name: l3-booknest}}

docker compose -f compose/single.yaml up -d --wait returns once the healthcheck passes. Clients connect to a bootstrap address, learn each broker's advertised address and reconnect there, so localhost:33092 works only from the host and l3-kafka:9092 only inside Docker 514 : the usual cause of "connected, then timed out". One broker also means one replica for the internal offsets, transaction and share-group topics.