DevOps

[Kafka] Docker Compose를 이용하여 Kafka 환경 구성하기

감자b 2025. 3. 8. 16:55
 

[Kafka] Apache Kafka, Zookeeper 개념

Apache Kafka는 대용량의 데이터를 빠르게 처리하고 실시간 스트리밍을 지원하는 pub/sub 모델의 분산 메시지 브로커로 주로 로그 처리, 이벤트 기반 아키텍처, 데이터 스트리밍 등에 활용된다.Kafka는

hbb-devlog.tistory.com

 

이번에는 Docker-Compose를 이용하여 간단하게 Kafka 환경을 구성해보도록 하겠다.

 

docker-compose-local.yml 파일 작성

version: "3.8"
services:
  zookeeper:
    image: confluentinc/cp-zookeeper:latest
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181 
      ZOOKEEPER_TICK_TIME: 2000
    ports:
      - "22181:2181"

  kafka1:
    image: confluentinc/cp-kafka:latest
    depends_on:
      - zookeeper
    ports:
      - "19092:19092"
      - "19094:19094"
    environment:
      KAFKA_BROKER_ID: 1 
      KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181' 
      KAFKA_LISTENERS: PLAINTEXT://kafka1:19092,PLAINTEXT_HOST://kafka1:19094
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka1:19092,PLAINTEXT_HOST://localhost:19094
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT

  kafka2:
    image: confluentinc/cp-kafka:latest
    depends_on:
      - zookeeper
    ports:
      - "29092:29092"
      - "29094:29094"
    environment:
      KAFKA_BROKER_ID: 2
      KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181'
      KAFKA_LISTENERS: PLAINTEXT://kafka2:29092,PLAINTEXT_HOST://kafka2:29094
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka2:29092,PLAINTEXT_HOST://localhost:29094
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT

  kafka3:
    image: confluentinc/cp-kafka:latest
    depends_on:
      - zookeeper
    ports:
      - "39092:39092"
      - "39094:39094"
    environment:
      KAFKA_BROKER_ID: 3
      KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181'
      KAFKA_LISTENERS: PLAINTEXT://kafka3:39092,PLAINTEXT_HOST://kafka3:39094
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka3:39092,PLAINTEXT_HOST://localhost:39094
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT

 

Zookeeper 환경 변수 설정

  • ZOOKEEPER_CLIENT_PORT: 2181 - 컨테이너 내부에서 주키퍼를 2181 포트로 실행
  • ZOOKEEPER_TICK_TIME: 2000 - ZooKeeper 시간의 기본 단위(밀리초)로 ZooKeeper의 모든 시간 관련 설정은 이 값을 기준으로 계산

Kafka 환경 변수 설정

  • KAFKA_BROKER_ID :  카프카 브로커 ID 설정. 현재 브로커가 여러 대이므로 설정해주어야 한다.
  • KAFKA_ZOOKEEPER_CONNECT : kafka가 zookeeper에 커넥션하기 위한 대상
  • KAFKA_LISTENERS : 리스너와 Kafka가 수신을 위해 바인딩하는 호스트/IP 및 Kafka 포트의 쉼표로 구분된 목록
    • PLAINTEXT://kafka1:19092: 내부 통신용 리스너 (다른 브로커와 통신)
    • PLAINTEXT_HOST://kafka1:19094: 외부 클라이언트용 리스너
    • 여기서 kafka1은 컨테이너의 호스트명
    • 기본값은 0.0.0.0이며, 이는 모든 인터페이스에서 수신을 의미.
  • KAFKA_ADVERTISED_LISTENERS: PLAINTEXT : 클라이언트가 Kafka 브로커와 통신하기 위한 외부에서 접근할 수 있는 주소 설정으로 클라이언트에게 전달되는 메타데이터
    • PLAINTEXT://kafka:19092: Kafka 브로커 내부에서 통신할 때 사용할 주소
    • PLAINTEXT_HOST://localhost:19094: 외부에서 접속할 때 사용할 주소  
  • KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: 리스너 이름 별로 사용할 보안 프로토콜을 설정 ({listener 이름}:{보안 프로토콜} 형식)
    • 외부, 내부 모두 보안 없이 평문(PLAINTEXT)으로 통신
  • KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
    • Kafka 브로커들 간에 내부 통신할 리스너의 이름으로 여기서 PLAINTEXT://로 시작하는 해당 주소는 내부에서만 사용

 

여기서 각 브로커는 2가지 방식으로 접근이 가능하다.

1. 내부 클라이언트 접근 (다른 Kafka 브로커나 Docker 네트워크 내 애플리케이션):

  • Docker 내부 네트워크를 통해 kafka1:19092로 접근
  • KAFKA_LISTENERS에 따라 Kafka 브로커는 이 주소에서 연결을 수신
  • 브로커는 KAFKA_ADVERTISED_LISTENERS에 따라 내부 클라이언트에게 kafka1:19092를 연결 주소로 알려줌
  • 내부 클라이언트는 이 주소로 통신을 계속함

2. 외부 클라이언트 접근 (호스트 시스템이나 외부 네트워크의 애플리케이션):

  • 호스트 시스템의 localhost:19094로 접근
  • Docker의 포트 매핑 (19094:19094)을 통해 이 연결은 컨테이너의 19094 포트로 전달
  • KAFKA_LISTENERS에 따라 Kafka 브로커는 kafka1:19094에서 이 연결을 수신
  • 브로커는 KAFKA_ADVERTISED_LISTENERS에 따라 외부 클라이언트에게 localhost:19094를 연결 주소로 알려줌
  • 외부 클라이언트는 해당 주소로 통신을 계속함


Docker에서 Kafka 브로커에 접근

1. docker-compose 실행

docker-compose -f docker-compose-local.yml up -d

 

 

2. 토픽 생성

docker-compose -f docker-compose-local.yml exec kafka1 kafka-topics --create --topic my-topic --bootstrap-server kafka1:19092 --replication-factor 3 --partitions 2

성공 시 응답 Created topic my-topic.

 

 

3. 토픽 목록 확인

docker-compose -f docker-compose-local.yml exec kafka1 kafka-topics --bootstrap-server kafka1:19092 --list

 

 

4. 토픽 정보 확인

docker-compose -f docker-compose-local.yml exec kafka1 kafka-topics --describe --topic my-topic --bootstrap-server kafka1:19092
결과
Topic: my-topic TopicId: ... PartitionCount: 2       ReplicationFactor: 3    Configs: 
        Topic: my-topic Partition: 0    Leader: 2       Replicas: 2,1,3 Isr: 2,1,3      Elr: N/A        LastKnownElr: N/A
        Topic: my-topic Partition: 1    Leader: 3       Replicas: 3,2,1 Isr: 3,2,1      Elr: N/A        LastKnownElr: N/A

 

 

5. 메시지 생산

docker-compose -f docker-compose-local.yml exec kafka1 kafka-console-producer --broker-list kafka1:19092 --topic my-topic

명령어를 입력하면 메시지를 입력할 수 있는 bash가 열리는데 여기에 입력한 메시지가 생산된다.

 

6. 메시지 소비

docker-compose -f docker-compose-local.yml exec kafka1 kafka-console-consumer --bootstrap-server kafka1:19092 --topic my-topic

위에서 생산된 메시지는 위 명령어를 통해 수신받을 수 있다.

 

7. 컨트롤러 브로커 조회

docker-compose -f docker-compose-local.yml exec zookeeper zookeeper-shell zookeeper:2181 get /controller

 

8. 컨테이너 종료

docker-compose -f docker-compose-local.yml down

 

 

지금까지 카프카 브로커 3대, Zookeeper 1대로 간단하게 카프카 클러스터를 구성해보았다.

그리고 도커 내부에서 토픽을 생성, 메시지 송수신하는 작업을 간단하게 살펴보았는데 다음에는 외부에서 접근(Spring Boot Application)에서 접근해서 카프카를 사용하는 방법에 대해서 알아보도록 하겠다.


참고

 

Quick Start for Confluent Platform | Confluent Documentation

In Confluent Platform, real-time streaming events are stored in a Kafka topic, which is an append-only log, and the fundamental unit of organization for Kafka. To learn more about Kafka basics, see Kafka Introduction. The topics are named pageviews and use

docs.confluent.io

 

 

Kafka Listeners – Explained | Confluent

You need to set advertised listeners (or KAFKA_ADVERTISED_LISTENERS if you’re using Docker images) to the external address (host/IP) so that clients can correctly connect to it. Otherwise, they’ll try to connect to the internal host address—and if th

www.confluent.io