grasys blog

dockerでkafkaを動かしてみた

はじめに

grasysの新井です。

直近の案件でkafkaを触る機会があったので、dockerでどうやって動かすのかをまとめてみました。

対象読者

  • kafkaを初めて触る人
  • dockerでkafkaを動かしてみたい人

構成図

  • producer
    topicへデータを追加するクライアント。
  • consumer
    topicからデータを取得するクライアント。
  • broker
    実際にtopicに追加されたデータが格納されているノード。
  • topic
    データ保管先、受信先を表すカテゴリ名。
  • partition
    topicに対するメッセージを処理する単位。
  • controller
    kafkaクラスタを管理するノード。
    brokerとは違いユーザデータは持たない。

環境

  • mac
  • docker, docker compose
❯ docker -v
Docker version 28.1.1, build 4eba377

❯ docker compose version
Docker Compose version v2.35.1-desktop.1

事前準備

  • docker composeで使用するcompose.yamlを用意する
services:
  controller-1:
    image: apache/kafka:4.0.0-rc4
    container_name: controller-1
    environment:
      KAFKA_NODE_ID: 1
      KAFKA_PROCESS_ROLES: controller
      KAFKA_LISTENERS: CONTROLLER://:9093
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
      KAFKA_CONTROLLER_QUORUM_VOTERS: 1@controller-1:9093,2@controller-2:9093,3@controller-3:9093
      KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0

  controller-2:
    image: apache/kafka:4.0.0-rc4
    container_name: controller-2
    environment:
      KAFKA_NODE_ID: 2
      KAFKA_PROCESS_ROLES: controller
      KAFKA_LISTENERS: CONTROLLER://:9093
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
      KAFKA_CONTROLLER_QUORUM_VOTERS: 1@controller-1:9093,2@controller-2:9093,3@controller-3:9093
      KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0

  controller-3:
    image: apache/kafka:4.0.0-rc4
    container_name: controller-3
    environment:
      KAFKA_NODE_ID: 3
      KAFKA_PROCESS_ROLES: controller
      KAFKA_LISTENERS: CONTROLLER://:9093
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
      KAFKA_CONTROLLER_QUORUM_VOTERS: 1@controller-1:9093,2@controller-2:9093,3@controller-3:9093
      KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0

  broker-1:
    image: apache/kafka:4.0.0-rc4
    container_name: broker-1
    ports:
      - 29092:9092
    environment:
      KAFKA_NODE_ID: 4
      KAFKA_PROCESS_ROLES: broker
      KAFKA_LISTENERS: 'PLAINTEXT://:19092,PLAINTEXT_HOST://:9092'
      KAFKA_ADVERTISED_LISTENERS: 'PLAINTEXT://broker-1:19092,PLAINTEXT_HOST://localhost:29092'
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_CONTROLLER_QUORUM_VOTERS: 1@controller-1:9093,2@controller-2:9093,3@controller-3:9093
      KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
    depends_on:
      - controller-1
      - controller-2
      - controller-3

  broker-2:
    image: apache/kafka:4.0.0-rc4
    container_name: broker-2
    ports:
      - 39092:9092
    environment:
      KAFKA_NODE_ID: 5
      KAFKA_PROCESS_ROLES: broker
      KAFKA_LISTENERS: 'PLAINTEXT://:19092,PLAINTEXT_HOST://:9092'
      KAFKA_ADVERTISED_LISTENERS: 'PLAINTEXT://broker-2:19092,PLAINTEXT_HOST://localhost:39092'
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_CONTROLLER_QUORUM_VOTERS: 1@controller-1:9093,2@controller-2:9093,3@controller-3:9093
      KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
    depends_on:
      - controller-1
      - controller-2
      - controller-3

  broker-3:
    image: apache/kafka:4.0.0-rc4
    container_name: broker-3
    ports:
      - 49092:9092
    environment:
      KAFKA_NODE_ID: 6
      KAFKA_PROCESS_ROLES: broker
      KAFKA_LISTENERS: 'PLAINTEXT://:19092,PLAINTEXT_HOST://:9092'
      KAFKA_ADVERTISED_LISTENERS: 'PLAINTEXT://broker-3:19092,PLAINTEXT_HOST://localhost:49092'
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_CONTROLLER_QUORUM_VOTERS: 1@controller-1:9093,2@controller-2:9093,3@controller-3:9093
      KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
    depends_on:
      - controller-1
      - controller-2
      - controller-3

ハンズオン

1、コンテナを立ち上げる

$ docker compose up -d

broker: 3, controller: 3のコンテナが起動している

$ docker compose ps

2、topicを作成してみる

まずはtopicがないことをkcatで確認する

$ docker compose exec broker-1 /opt/kafka/bin/kafka-topics.sh \
  --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 \
  --list

topicを作成する

$ docker compose exec broker-1 /opt/kafka/bin/kafka-topics.sh \
  --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 \
  --create \
  --topic my-test-topic \
  --partitions 3 \
  --replication-factor 3

–partitions:
topic内に作成するpartition数を指定できる。(この場合3つのpartitionが作成される)

–replication-factor:
leader partition含めて、いくつのpartitionの複製を作成するか指定している。(この場合3つreplicaが作成される)

注意: replicaはbroker数より多く作成することはできない。
(今回の場合4以上は作成することができない。)

作成されたtopicを確認する

$ docker compose exec broker-1 /opt/kafka/bin/kafka-topics.sh \
  --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 \
  --list
my-test-topic

my-test-topicというトピックが作成できている。

$ docker compose exec broker-1 /opt/kafka/bin/kafka-topics.sh \
  --describe \
  --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 \
  --topic my-test-topic

Topic: my-test-topic	TopicId: dbdyZPl9Q4uV2YApDyhkmw	PartitionCount: 3	ReplicationFactor: 3	Configs:
	Topic: my-test-topic	Partition: 0	Leader: 6	Replicas: 6,4,5	Isr: 6,4,5	Elr: 	LastKnownElr:
	Topic: my-test-topic	Partition: 1	Leader: 4	Replicas: 4,5,6	Isr: 4,5,6	Elr: 	LastKnownElr:
	Topic: my-test-topic	Partition: 2	Leader: 5	Replicas: 5,6,4	Isr: 5,6,4	Elr: 	LastKnownElr:

partition:
実際に作成されたパーティションが表示されている。
0始まりでインクリメントされていく。

leader:
リーダーパーティションが表示されている。
producerからtopicへpublish(追加)されたデータは、このパーティションに追加され、follow replicaに複製される。
またこのパーティションからconsumerはデータをsubscribe(取得)する。

Replicas:
リーダーパーティションを含めた複製パーティションが表示されている。

Isr:
In-Sync-Replicaが表示されている。
leader partitionと同期が取られているfollow replicaがわかる。
(今回の場合、全てのfollow replicaで同期が取られている。)

Elr:
Excluded Replicas(除外されたレプリカ)が表示される。
一時的な同期遅延でISRから除外されたレプリカなど。

LastKnownElr:
最後に認識された除外されたレプリカが表示される。

3、kafkaコマンドでsubscribeできる状態にしてみる

kafkaコマンドでsubscribeする

$ docker compose exec broker-1 /opt/kafka/bin/kafka-console-consumer.sh \
  --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 \
  --topic my-test-topic

まだtopicにデータが追加されていないため、何も表示されない。

4、topicへデータを追加してみる

ターミナルの別windowでproducerを立ち上げる

$ docker compose exec broker-1 /opt/kafka/bin/kafka-console-producer.sh \
  --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 \
  --topic my-test-topic

topicへデータを追加してみる。

# producer
❯ docker compose exec broker-1 /opt/kafka/bin/kafka-console-producer.sh \
  --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 \
  --topic my-test-topic
>fdsafsa
>fdsafdsa
>fdsa
>fdsa
>fdsadfsaf
>dsa

# consumer
❯ docker compose exec broker-1 /opt/kafka/bin/kafka-console-consumer.sh \
  --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 \
  --topic my-test-topic
fdsafsa
fdsafdsa
fdsa
fdsa
fdsadfsaf

すると、topicからconsumerが追加されたデータを取得して表示されるのがわかる。

終わりに

今回はkafkaをdockerで動かす方法をまとめてみました。

これ以外にも、Commit Offsetの仕組みやkafka exporterやJMXでのメトリクス表示、上記以外のkafkaコマンド、apache pulsarやRabbitMQなどとの違い、kafka管理部分であるzoo keeperとkraftの違い、kafka uiなどのGUIベースでの表示/操作方法、kafka stream、strimziでのk8s上での運用方法などなどまだまだ気になることはたくさんあります!

今後はこのあたりも随時調べていければと思います。


採用情報
お問い合わせ