Skip to content
Learni
View all tutorials
Data Engineering

Comment déployer un cluster Apache Kafka en KRaft 2026

Introduction

Apache Kafka est la plateforme de streaming distribué de référence pour gérer des flux de données en temps réel à grande échelle. En 2026, le mode KRaft (Kafka Raft Metadata) a supplanté ZooKeeper, simplifiant les déploiements en éliminant un composant externe tout en améliorant la résilience et les performances. Ce tutoriel expert vous guide pour déployer un cluster haute disponibilité à 3 brokers via Docker Compose, créer des topics partitionnés, implémenter des producers et consumers en Python, et tuner pour la production.

Pourquoi c'est crucial ? Dans les architectures event-driven (microservices, IoT, analytics temps réel), Kafka gère des millions d'événements/seconde avec persistance garantie. Vous apprendrez les configs KRaft précises, les pièges de réplication, et des exemples fonctionnels copier-collables. À la fin, votre cluster sera prêt pour Kafka Streams ou Connect. Idéal pour data engineers seniors gérant des pipelines critiques.

Prérequis

  • Docker 25+ et Docker Compose 2.24+ installés et fonctionnels.
  • Python 3.11+ avec pip pour les clients producers/consumers.
  • 4 Go RAM minimum (8 Go recommandé pour tests charge).
  • Connaissances avancées en réseaux Docker, YAML, et concepts Kafka (topics, partitions, réplication).
  • Port 29092, 9092-9094 libres sur localhost.

Configuration Docker Compose pour cluster KRaft

docker-compose.yml
version: '3.8'
services:
  broker-1:
    image: apache/kafka:3.7.0
    container_name: kafka-broker-1
    ports:
      - "9092:9092"
    environment:
      KAFKA_NODE_ID: 1
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://broker-1:29092,PLAINTEXT_HOST://localhost:9092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_CONTROLLER_QUORUM_VOTERS: '1@broker-1:29093,2@broker-2:29093,3@broker-3:29093'
      KAFKA_PROCESS_ROLES: 'controller,broker'
      KAFKA_CONTROLLER_LISTENER_NAMES: 'CONTROLLER'
      KAFKA_LISTENERS: 'PLAINTEXT://broker-1:29092,CONTROLLER://broker-1:29093,PLAINTEXT_HOST://0.0.0.0:9092'
      KAFKA_LOG_DIRS: '/tmp/kraft-combined-logs'
      CLUSTER_ID: 'MkU3OEVBNTcwNTJENDM2Qk'
    volumes:
      - ./data1:/tmp/kraft-combined-logs
    networks:
      - kafka-net
  broker-2:
    image: apache/kafka:3.7.0
    container_name: kafka-broker-2
    ports:
      - "9093:9093"
    environment:
      KAFKA_NODE_ID: 2
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://broker-2:29092,PLAINTEXT_HOST://localhost:9093
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_CONTROLLER_QUORUM_VOTERS: '1@broker-1:29093,2@broker-2:29093,3@broker-3:29093'
      KAFKA_PROCESS_ROLES: 'broker'
      KAFKA_CONTROLLER_LISTENER_NAMES: 'CONTROLLER'
      KAFKA_LISTENERS: 'PLAINTEXT://broker-2:29092,CONTROLLER://broker-2:29093,PLAINTEXT_HOST://0.0.0.0:9093'
      KAFKA_LOG_DIRS: '/tmp/kraft-combined-logs'
      CLUSTER_ID: 'MkU3OEVBNTcwNTJENDM2Qk'
    volumes:
      - ./data2:/tmp/kraft-combined-logs
    networks:
      - kafka-net
    depends_on:
      - broker-1
  broker-3:
    image: apache/kafka:3.7.0
    container_name: kafka-broker-3
    ports:
      - "9094:9094"
    environment:
      KAFKA_NODE_ID: 3
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://broker-3:29092,PLAINTEXT_HOST://localhost:9094
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_CONTROLLER_QUORUM_VOTERS: '1@broker-1:29093,2@broker-2:29093,3@broker-3:29093'
      KAFKA_PROCESS_ROLES: 'broker'
      KAFKA_CONTROLLER_LISTENER_NAMES: 'CONTROLLER'
      KAFKA_LISTENERS: 'PLAINTEXT://broker-3:29092,CONTROLLER://broker-3:29093,PLAINTEXT_HOST://0.0.0.0:9094'
      KAFKA_LOG_DIRS: '/tmp/kraft-combined-logs'
      CLUSTER_ID: 'MkU3OEVBNTcwNTJENDM2Qk'
    volumes:
      - ./data3:/tmp/kraft-combined-logs
    networks:
      - kafka-net
    depends_on:
      - broker-1
networks:
  kafka-net:
    driver: bridge

Ce docker-compose.yml déploie un cluster à 3 brokers en mode KRaft combiné (broker + controller sur broker-1). Les variables d'env configurent les listeners internes (inter-broker), host (exposés localhost) et quorum Raft pour metadata haute disponibilité. Générez un CLUSTER_ID unique avec kafka-storage.sh random-uuid. Créez les dossiers data1/2/3 avant lancement pour persistance.

Lancement et vérification du cluster

Sauvegardez le code ci-dessus dans docker-compose.yml. Exécutez docker compose up -d pour démarrer. Vérifiez avec docker compose logs broker-1 : cherchez 'Started Kafka Server' et 'Registered broker'. Testez connectivité : docker exec -it kafka-broker-1 kafka-broker-api-versions --bootstrap-server localhost:9092. Le cluster est prêt quand tous brokers sont registered. Cette setup assure tolérance à 1 panne (quorum 3 nœuds).

Création d'un topic partitionné

create-topic.sh
#!/bin/bash
docker exec -it kafka-broker-1 \
  kafka-topics --bootstrap-server localhost:9092 \
  --create --topic expert-tutorial \
  --partitions 6 \
  --replication-factor 3 \
  --config cleanup.policy=delete \
  --config retention.ms=3600000

docker exec -it kafka-broker-1 \
  kafka-topics --bootstrap-server localhost:9092 \
  --describe --topic expert-tutorial

Ce script crée un topic 'expert-tutorial' avec 6 partitions et facteur de réplication 3 (HA). cleanup.policy=delete et retention.ms=1h pour tests courts. La commande describe confirme la réplication sur les 3 brokers. Exécutez-le après démarrage du cluster.

Test avec producers et consumers console

Avant les clients Python, validez avec outils Kafka. Producer : docker exec -it kafka-broker-1 kafka-console-producer --bootstrap-server localhost:9092 --topic expert-tutorial. Tapez des messages, Ctrl+C pour quitter. Consumer : docker exec -it kafka-broker-1 kafka-console-consumer --bootstrap-server localhost:9092 --topic expert-tutorial --from-beginning. Vous verrez les messages répliqués. Cela confirme la santé du cluster.

Producer Python asynchrone complet

producer.py
from kafka import KafkaProducer
import json
import time
import sys

# Installation préalable: pip install kafka-python
producer = KafkaProducer(
    bootstrap_servers=['localhost:9092', 'localhost:9093', 'localhost:9094'],
    value_serializer=lambda v: json.dumps(v).encode('utf-8'),
    acks='all',  # Durabilité: attendre réplication complète
    retries=3,
    max_in_flight_requests_per_connection=1  # Ordre garanti
)

for i in range(10):
    message = {'id': i, 'event': f"Expert Kafka event {i}", 'timestamp': time.time()}
    future = producer.send('expert-tutorial', value=message)
    result = future.get(timeout=10)
    print(f"Message {i} envoyé à partition {result.partition}")

producer.flush()
producer.close()
print("Production terminée.")

Ce producer asynchrone envoie 10 JSON messages avec sérialisation intégrée. bootstrap_servers liste tous brokers pour résilience. acks='all' + retries=3 + max_in_flight=1 garantit exactly-once et ordre. Copiez-collez après pip install kafka-python ; exécutez python producer.py.

Consumer Python avec group et offset management

consumer.py
from kafka import KafkaConsumer
import json

consumer = KafkaConsumer(
    'expert-tutorial',
    bootstrap_servers=['localhost:9092', 'localhost:9093', 'localhost:9094'],
    group_id='expert-group',
    value_deserializer=lambda m: json.loads(m.decode('utf-8')),
    auto_offset_commit=True,
    enable_auto_commit=True,
    auto_offset_reset='earliest',
    fetch_min_bytes=1,
    max_poll_records=100
)

print("Démarrage consumer...")
for message in consumer:
    print(f"Reçu: {message.value} de partition {message.partition} offset {message.offset}")
    if message.value['id'] == 9:  # Arrêt après dernier message test
        break

consumer.close()
print("Consumption terminée.")

Ce consumer utilise un group_id pour load balancing sur partitions. Désérialisation JSON, commit auto des offsets. auto_offset_reset='earliest' lit depuis début pour tests. Lancez dans un terminal séparé après producer ; scalez avec plusieurs consumers pour parallélisme.

Monitoring des métriques cluster

monitor.sh
#!/bin/bash
# Vérifier brokers
DOCKER exec -it kafka-broker-1 kafka-broker-api-versions --bootstrap-server localhost:9092

# Topics et partitions
docker exec -it kafka-broker-1 kafka-topics --bootstrap-server localhost:9092 --list

# Consumer groups
docker exec -it kafka-broker-1 kafka-consumer-groups --bootstrap-server localhost:9092 --list

# Logs récents broker-1
tail -f data1/kraft-combined-logs/meta.properties
docker compose logs --tail=20 broker-1

Ce script monitore brokers, topics, groups et logs. Utilisez-le pour debugger : vérifiez lag offsets, under-replicated partitions. kafka-broker-api-versions confirme protocoles supportés. Intégrez à cron ou Prometheus pour prod.

Bonnes pratiques

  • Tuning partitions : Visez 10k messages/s par partition ; utilisez min.insync.replicas=2 pour durabilité sans downtime.
  • Sécurité : Activez SASL/SCRAM ou mTLS dès prod ; mappez KAFKA_AUTHORIZE... pour ACL.
  • Scaling : Ajoutez brokers dynamiquement avec kafka-storage.sh format ; monitorer CPU/IO avec JMX Exporter.
  • Idempotence : Toujours enable.idempotence=true sur producers pour éviter duplicates.
  • KRaft tuning : controller.socket.timeout.ms=30000 pour grands clusters ; backup metadata via snapshots.

Erreurs courantes à éviter

  • CLUSTER_ID mismatch : Tous brokers doivent partager le même UUID ; régénérez-le si erreur 'InconsistentClusterId'.
  • Listeners mal configurés : Distinguez advertised_listeners (clients) vs listeners internes ; testez avec nc -zv localhost 9092.
  • Pas de volumes persistants : Sans ./dataX, metadata/logs perdus au redémarrage → corruption KRaft.
  • Consumer lag explosion : Augmentez session.timeout.ms=30s et max.poll.interval.ms=5min pour GC pauses.

Pour aller plus loin