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
pippour 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
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: bridgeCe 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é
#!/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-tutorialCe 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
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
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
#!/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-1Ce 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=2pour 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=truesur producers pour éviter duplicates. - KRaft tuning :
controller.socket.timeout.ms=30000pour 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=30setmax.poll.interval.ms=5minpour GC pauses.
Pour aller plus loin
- Implémentez Kafka Streams pour processing stateful.
- Intégrez Kafka Connect pour sources/sinks (ex: PostgreSQL).
- Sécurité avancée : Doc officielle KRaft Security.
- Découvrez nos formations Learni sur Data Streaming pour certifs Confluent/Kafka expert.