Пример docker-compose для запуска Kafka
Опубликовано:
Используемые термины: Kafka, Docker.
В нашем примере рассмотрим сценарий развертывания одноузлового кластера кафки через compose файл. Кроме основного сценария расскажем про выбор образа, режим KRaft, проверку кластера тестовым сообщением и переход к нескольким узлам.
Пример команд будет приведет с использованием Linux.
Создание файла docker-compose и запуск контейнеров
Выполнение тестовых запросов
Варианты образов для docker kafka
Увеличение узлов для создания кластера
Решение возможных проблем
Описание файла docker-compose
Создаем рабочий каталог и переходим в него:
mkdir /opt/kafka && cd /opt/kafka
Создаем файл docker-compose:
vi docker-compose.yml
services:
kafka1:
image: apache/kafka:${KAFKA_VER}
container_name: kafka1
hostname: kafka1
restart: unless-stopped
environment:
TZ: ${TIMEZONE}
KAFKA_NODE_ID: 1
KAFKA_PROCESS_ROLES: broker,controller
KAFKA_LISTENERS: INTERNAL://0.0.0.0:9092,EXTERNAL://0.0.0.0:9094,CONTROLLER://0.0.0.0:9093
KAFKA_ADVERTISED_LISTENERS: INTERNAL://kafka1:9092,EXTERNAL://${KAFKA_HOSTNAME}:9094
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT,CONTROLLER:PLAINTEXT
KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL
KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka1:9093
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
KAFKA_NUM_PARTITIONS: 3
volumes:
- ./kafka/data:/var/lib/kafka/data
ports:
- 9092:9092
- 9093:9093
- 9094:9094
healthcheck:
test: ["CMD-SHELL", "nc -z 127.0.0.1 9092 || exit 2"]
start_period: 10s
interval: 30s
timeout: 5s
retries: 5
* подробнее рассмотрим системные переменные, которые определяют поведение работы кафки:
- Идентификация и роли
- KAFKA_NODE_ID — Уникальный числовой идентификатор брокера в кластере.
- KAFKA_PROCESS_ROLES — Совмещение ролей. Узел работает и как хранилище данных (broker), и как управляющий элемент (controller).
- Сетевые подключения (Слушатели)
- KAFKA_LISTENERS — Интерфейсы и порты, которые слушает Kafka внутри контейнера или сервера. 0.0.0.0 означает прием подключений на всех сетевых интерфейсах.
- KAFKA_ADVERTISED_LISTENERS — Адреса, которые Kafka передаёт клиентам.
INTERNALиспользуется для клиентов внутри Docker-сети,EXTERNAL— для внешних подключений. - KAFKA_CONTROLLER_LISTENER_NAMES — Указывает, какой именно из настроенных слушателей используется для связи между контроллерами кластера.
- KAFKA_INTER_BROKER_LISTENER_NAME — слушатель, который используется для внутренних запросов (между контейнерами docker).
- KAFKA_LISTENER_SECURITY_PROTOCOL_MAP — Привязывает имена слушателей (
INTERNAL,EXTERNAL,CONTROLLER) к протоколу безопасности (PLAINTEXT).
- Кворум и согласованность KRaft
- KAFKA_CONTROLLER_QUORUM_VOTERS — Список всех голосующих узлов-контроллеров для выбора лидера. Формат: ID_узла@IP:порт. В данном случае узел голосует сам за себя на локальном интерфейсе.
- Репликация системных топиков
- KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR — Фактор репликации для служебного топика __consumer_offsets, где хранятся позиции чтения клиентов. Значение 1 подходит только для разработки или одного узла.
- KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR — Фактор репликации для топика состояния транзакций.
- KAFKA_TRANSACTION_STATE_LOG_MIN_ISR — Минимальное количество синхронных реплик (ISR), необходимое для подтверждения транзакции. При значении 1 транзакции будут работать даже на одиночном брокере.
- Производительность и дефолты
- KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS — Время ожидания (в миллисекундах) перед первой балансировкой группы потребителей. Значение 0 ускоряет старт и прогон тестов, так как группа собирается мгновенно.
- KAFKA_NUM_PARTITIONS — Количество разделов (партиций) по умолчанию для любого нового топика, если оно не было указано явно при его создании.
Создадим конфигурационный файл:
vi .env
TIMEZONE=Europe/Moscow
KAFKA_HOSTNAME=test.dmosk.ru
KAFKA_VER=4.3.1
* где:
- TIMEZONE — временная зона, в которой работает сервер кафки.
- KAFKA_HOSTNAME — имя сервера кафки. Должно разрешаться в DNS для возможности подключения к брокеру.
- KAFKA_VER — версия кафки. Актуальный тег можно найти на Docker Hub.
Одноузловой кластер настроен. Для запуска выполняем команду:
docker-compose up -d
И проверяем статус:
docker-compose ps
Проверка тестовым сообщением
Создадим топик и отправим в него тестовое сообщение — так проверим, что кластер работает:
docker exec -it kafka1 /opt/kafka/bin/kafka-topics.sh --create --topic test --bootstrap-server localhost:9092
* где test — имя топика, localhost:9092 — адрес брокера внутри контейнера.
Запустим продюсер и отправим сообщение:
docker exec -it kafka1 /opt/kafka/bin/kafka-console-producer.sh --topic test --bootstrap-server localhost:9092
В открывшейся строке вводим текст сообщения и нажимаем Enter, затем закрываем консоль сочетанием Ctrl+C.
В отдельном окне терминала запустим консумер и прочитаем сообщение:
docker exec -it kafka1 /opt/kafka/bin/kafka-console-consumer.sh --topic test --bootstrap-server localhost:9092 --from-beginning
Мы должны увидеть отправленное ранее сообщение в выводе консоли.
Кластер принимает и отдает сообщения.
В примерах ниже используется адрес localhost:9092 — это внутренний listener INTERNAL. Если вы подключаетесь к Kafka извне (не из контейнера), используйте внешний адрес, указанный в KAFKA_HOSTNAME, и порт 9094 (EXTERNAL).
Выбор образа Kafka и версии
В примере мы используем образ apache/kafka. Но есть и другие варианты:
- apache/kafka — официальный образ проекта. Поддерживает KRaft без ZooKeeper, переменные начинаются с KAFKA_.
- confluentinc/cp-kafka — образ от Confluent. Тоже работает в режиме KRaft, но часть переменных называется иначе, а в старых версиях нужен отдельный контроллер.
- bitnami/kafka — образ от Bitnami. Использует префикс KAFKA_CFG_ вместо KAFKA_, и добавляет свои готовые пресеты для одноузлового и многоузлового запуска.
* при смене образа сверяем набор переменных окружения с документацией — прямой перенос значений между образами не всегда работает.
Кафка в нашем примере работает без ZooKeeper — это режим KRaft. Роли broker и controller совмещены в одном узле через переменную KAFKA_PROCESS_ROLES. Кворум и выбор лидера контролирует сама Kafka через KAFKA_CONTROLLER_QUORUM_VOTERS. Раньше эту задачу решал отдельный компонент — ZooKeeper.
* в старых версиях Kafka (до перехода на KRaft) ZooKeeper еще требуется — уточняем версию образа перед настройкой.
Расширение до нескольких узлов
Пример с одним узлом подходит для разработки и тестов. Для продакшена обычно разворачивают три узла и больше. Каждому новому узлу задаем свой KAFKA_NODE_ID, и добавляем его в общий список KAFKA_CONTROLLER_QUORUM_VOTERS на всех узлах.
* при добавлении узлов также пересчитываем факторы репликации (KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR и подобные) — значение 1 подходит только для одного брокера.
Переход к кластеру из нескольких узлов делается по тому же принципу.
Решение проблем
Рассмотрим несколько часто встречаемых ошибок.
1. Ошибка подключения
Клиент подключается к брокеру и получает ошибку соединения.
Причина: часто из-за того, что KAFKA_ADVERTISED_LISTENERS указывает адрес, недоступный извне контейнера.
Решение: проверяем значение KAFKA_HOSTNAME в файле .env — оно должно быть адресом, по которому клиент реально достучится до брокера.
2. Кафка внутри контейнера на работает
Healthcheck контейнера показывает unhealthy, хотя в логах kafka1 нет ошибок.
Причина: иногда команда nc отсутствует внутри образа.
Решение: смотрим логи:
docker logs kafka1
... и при необходимости, меняем тест healthcheck на вызов kafka-broker-api-versions.sh.