Docker를 통해 Kafka를 실행해 보자
📌 서론
이전에도 kafka 세팅에 대해 포스팅을 한 적이 있지만 가장 최근에 새롭게 세팅을 하면서 알게 된 점들을 정리해 봤다.
특히 port를 설정할 때 내부, 외부로 구성하는 점이 굉장히 중요했다. 이 부분은 실수로 잘못 설정하면 외부에서는 아예 접근조차 불가능했다.
세팅은 loacl에서 진행했으며 docker-compose를 사용해서 m2 max 맥북에서 실행했다.
만약 SpringBoot에 연결하는 방법이 궁금하다면 이 글을 확인하자 (SpringBoot3.x.x)
1. 전체 구성 이해하기
지금부터 설명할 Docker Compose 파일은 다음과 같은 주요 구성 요소로 이루어져 있다.
- 네트워크 설정 (networks): Kafka 서비스들이 서로 통신할 수 있도록 독립적인 Docker 네트워크 kafka_network를 설정한다.
- 볼륨 설정 (volumes): Kafka 데이터 저장을 위해 각 브로커별로 로컬 드라이버를 사용하는 Docker 볼륨 (Kafka00, Kafka01, Kafka02)을 설정한다.
- Kafka 브로커 서비스들 (Kafka00Service, Kafka01Service, Kafka02Service): 세 개의 Kafka 브로커가 클러스터를 형성하며, 각 브로커는 KRaft 모드를 사용하여 컨트롤러와 브로커 역할을 동시에 수행한다.
- Kafka UI 서비스 (KafkaWebUiService): Kafka 클러스터의 상태를 모니터링하고 관리하기 위한 웹 기반 UI다.
Kafka 클러스터 실행을 위한 docker-compose.yml의 전체 코드는 다음과 같다.
- vim 에디터로 docker-compose.yml 파일을 만든 후 아래의 코드를 붙여 넣고 사용하면 된다.
version: '3.8'
networks:
kafka_network:
volumes:
Kafka00:
driver: local
Kafka01:
driver: local
Kafka02:
driver: local
services:
Kafka00Service:
image: bitnami/kafka:3.7.0
restart: unless-stopped
container_name: Kafka00Container
ports:
- '9092:9092' # 내부 네트워크 통신을 위한 PLAINTEXT 리스너
- '10000:10000' # 외부 접근을 위한 EXTERNAL 리스너
environment:
# KRaft 설정
- KAFKA_ENABLE_KRAFT=yes # KRaft 모드 활성화
- KAFKA_CFG_BROKER_ID=0
- KAFKA_CFG_NODE_ID=0
- KAFKA_KRAFT_CLUSTER_ID=HsDBs9l6UUmQq7Y5E6bNlw # 고유 클러스터 ID, 모든 브로커에 동일하게 설정
- KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@Kafka00Service:9093,1@Kafka01Service:9093,2@Kafka02Service:9093
- KAFKA_CFG_PROCESS_ROLES=controller,broker
# 리스너 설정
- KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE=true
- ALLOW_PLAINTEXT_LISTENER=yes
- KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:10000
- KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://Kafka00Service:9092,EXTERNAL://localhost:10000
- KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT
- KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
# 클러스터 설정
- KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR=2
- KAFKA_CFG_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=2
- KAFKA_CFG_TRANSACTION_STATE_LOG_MIN_ISR=2
networks:
- kafka_network
volumes:
- Kafka00:/bitnami/kafka
Kafka01Service:
image: bitnami/kafka:3.7.0
restart: unless-stopped
container_name: Kafka01Container
ports:
- '9093:9092' # 내부 네트워크 통신을 위한 PLAINTEXT 리스너
- '10001:10000' # 외부 접근을 위한 EXTERNAL 리스너
environment:
# KRaft 설정
- KAFKA_ENABLE_KRAFT=yes # KRaft 모드 활성화
- KAFKA_CFG_BROKER_ID=1
- KAFKA_CFG_NODE_ID=1
- KAFKA_KRAFT_CLUSTER_ID=HsDBs9l6UUmQq7Y5E6bNlw # 고유 클러스터 ID, 모든 브로커에 동일하게 설정
- KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@Kafka00Service:9093,1@Kafka01Service:9093,2@Kafka02Service:9093
- KAFKA_CFG_PROCESS_ROLES=controller,broker
# 리스너 설정
- KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE=true
- ALLOW_PLAINTEXT_LISTENER=yes
- KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:10000
- KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://Kafka01Service:9092,EXTERNAL://localhost:10001
- KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT
- KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
# 클러스터 설정
- KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR=2
- KAFKA_CFG_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=2
- KAFKA_CFG_TRANSACTION_STATE_LOG_MIN_ISR=2
networks:
- kafka_network
volumes:
- Kafka01:/bitnami/kafka
Kafka02Service:
image: bitnami/kafka:3.7.0
restart: unless-stopped
container_name: Kafka02Container
ports:
- '9094:9092' # 내부 네트워크 통신을 위한 PLAINTEXT 리스너
- '10002:10000' # 외부 접근을 위한 EXTERNAL 리스너
environment:
# KRaft 설정
- KAFKA_ENABLE_KRAFT=yes # KRaft 모드 활성화
- KAFKA_CFG_BROKER_ID=2
- KAFKA_CFG_NODE_ID=2
- KAFKA_KRAFT_CLUSTER_ID=HsDBs9l6UUmQq7Y5E6bNlw # 고유 클러스터 ID, 모든 브로커에 동일하게 설정
- KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@Kafka00Service:9093,1@Kafka01Service:9093,2@Kafka02Service:9093
- KAFKA_CFG_PROCESS_ROLES=controller,broker
# 리스너 설정
- KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE=true
- ALLOW_PLAINTEXT_LISTENER=yes
- KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:10000
- KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://Kafka02Service:9092,EXTERNAL://localhost:10002
- KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT
- KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
# 클러스터 설정
- KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR=2
- KAFKA_CFG_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=2
- KAFKA_CFG_TRANSACTION_STATE_LOG_MIN_ISR=2
networks:
- kafka_network
volumes:
- Kafka02:/bitnami/kafka
KafkaWebUiService:
image: provectuslabs/kafka-ui:latest
restart: unless-stopped
container_name: KafkaWebUiContainer
ports:
- '8085:8080' # 호스트의 8085 포트를 컨테이너의 8080 포트에 바인딩
environment:
- KAFKA_CLUSTERS_0_NAME=Local-Kraft-Cluster
- KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS=Kafka00Service:9092,Kafka01Service:9092,Kafka02Service:9092
- DYNAMIC_CONFIG_ENABLED=true
- KAFKA_CLUSTERS_0_AUDIT_TOPICAUDITENABLED=true
- KAFKA_CLUSTERS_0_AUDIT_CONSOLEAUDITENABLED=true
depends_on:
- Kafka00Service
- Kafka01Service
- Kafka02Service
networks:
- kafka_network
실행방법
- docker-compose.yml 파일을 생성했다면 그 폴더 경로에서 아래의 명령어를 통해 실행해 주면 된다.
docker-compose up -d
docker-compose up
- Docker Compose 파일(docker-compose.yml)에 정의된 모든 서비스(여기서는 Kafka 브로커, Kafka UI 등)를 시작한다.
-d (detached mode)
- 이 옵션을 사용하면 Docker Compose가 백그라운드에서 컨테이너를 실행한다. 따라서 터미널이 실행된 상태로 유지되며, 컨테이너의 로그를 보지 않고 다른 작업을 계속할 수 있다.
2. kafka 실행을 위한 docker-compose 각 구성요소별 분석
네트워크 설정
networks:
kafka_network:
- 모든 Kafka 서비스가 동일한 네트워크 (kafka_network) 내에서 실행되도록 설정했다. 이는 Docker 네트워크를 통해 브로커 간 통신이 가능하게 한다. Docker 네트워크를 사용함으로써 서비스 간의 통신을 격리하고, 필요한 경우 외부 접근을 제한할 수 있다.
볼륨 설정
- 각 Kafka 브로커는 별도의 Docker 볼륨 (Kafka00, Kafka01, Kafka02)을 사용하여 데이터 저장소를 유지한다. driver: local은 호스트 시스템(kafka를 실행 중인 컴퓨터)의 로컬 스토리지를 사용한다는 의미다. 이렇게 설정해서 Kafka의 로그 및 데이터 파일이 Docker 컨테이너가 재시작될 때도 유지되도록 한다.
volumes:
Kafka00:
driver: local
Kafka01:
driver: local
Kafka02:
driver: local
volumes
- Docker에서는 컨테이너가 데이터를 영구적으로 저장할 수 있는 공간을 제공하기 위해 볼륨(volume)을 사용한다. 볼륨은 컨테이너의 파일 시스템과 호스트의 파일 시스템 사이의 독립적인 저장소를 의미한다.
driver: local
- 이 설정은 Docker가 기본적으로 제공하는 로컬 드라이버를 사용하여 볼륨을 생성하고 관리하도록 한다. local 드라이버는 호스트 머신의 파일 시스템을 사용하여 데이터를 저장하므로, 별도의 파일 시스템 경로를 지정하지 않으면 Docker가 자동으로 호스트의 특정 디렉터리를 할당하여 데이터를 저장하게 된다.
local 드라이버의 동작 방식
- driver: local을 사용하면 Docker가 기본적으로 설정된 디렉터리에 볼륨 데이터를 저장한다. 이는 호스트 머신의 로컬 파일 시스템에 위치하며, Docker가 컨테이너의 데이터를 영구적으로 저장하기 위해 사용된다.
- 예를 들어, 위의 설정에서는 Kafka00, Kafka01, Kafka02라는 세 개의 볼륨이 정의되어 있다. 이 볼륨들은 각각의 Kafka 서비스 컨테이너의 데이터를 호스트의 로컬 파일 시스템에 저장하게 된다.
확인하는 방법 (로컬)
- 명령어를 통해 docker에 접속해서 volume을 확인하는 방법도 있지만 docker desktop을 사용중이라면 훨씬 더 간단하게 volume을 확인할 수 있다. 하단과 같이 volumes 메뉴에 접속하면 로컬에 Kafka_00 ~ 03까지 volume이 만들어진 것을 확인할 수 있다.
Kafka 브로커 서비스 (Kafka00Service)
Kafka00Service:
image: bitnami/kafka:3.7.0
restart: unless-stopped
container_name: Kafka00Container
ports:
- '9092:9092' # 내부 네트워크 통신을 위한 PLAINTEXT 리스너
- '10000:10000' # 외부 접근을 위한 EXTERNAL 리스너
environment:
- KAFKA_ENABLE_KRAFT=yes # KRaft 모드 활성화
- KAFKA_CFG_BROKER_ID=0
- KAFKA_CFG_NODE_ID=0
- KAFKA_KRAFT_CLUSTER_ID=HsDBs9l6UUmQq7Y5E6bNlw # 고유 클러스터 ID, 모든 브로커에 동일하게 설정
- KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@Kafka00Service:9093,1@Kafka01Service:9093,2@Kafka02Service:9093
- KAFKA_CFG_PROCESS_ROLES=controller,broker
- KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE=true
- ALLOW_PLAINTEXT_LISTENER=yes
- KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:10000
- KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://Kafka00Service:9092,EXTERNAL://localhost:10000
- KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT
- KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
- KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR=2
- KAFKA_CFG_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=2
- KAFKA_CFG_TRANSACTION_STATE_LOG_MIN_ISR=2
networks:
- kafka_network
volumes:
- Kafka00:/bitnami/kafka
이미지 설정
- bitnami/kafka:3.7.0 이미지를 사용하여 Kafka 브로커를 실행한다.
재시작 정책
- unless-stopped로 설정되어 컨테이너가 중지되지 않는 한 항상 재시작한다.
컨테이너 이름
- Kafka00Container로 설정되어 있으며, Docker에서 컨테이너를 명확히 식별하는 데 사용된다.
포트 설정
- 9092:9092: 내부 네트워크 통신을 위한 PLAINTEXT 리스너. Kafka 클라이언트가 브로커와 통신할 때 사용된다.
- 10000:10000: 외부 접근을 위한 EXTERNAL 리스너. 외부에서 Kafka 브로커에 접근할 때 사용된다. (ex: SpringBoot)
환경 변수 설정
- KAFKA_ENABLE_KRAFT=yes: KRaft 모드를 활성화한다. KRaft 모드는 ZooKeeper 없이 Kafka 클러스터를 운영할 수 있도록 하는 방법이다.
- KAFKA_CFG_BROKER_ID와 KAFKA_CFG_NODE_ID: 각각의 브로커와 노드에 대한 ID를 설정한다. (각 브로커별로 다르게 설정한다.)
- KAFKA_KRAFT_CLUSTER_ID: 고유한 클러스터 ID를 설정하여 클러스터 내 모든 브로커에 동일하게 적용한다. 이 ID는 KRaft(Kafka Raft) 모드에서 클러스터를 구성하는 모든 브로커(여러 kafka 브로커)가 동일한 클러스터에 속해 있음을 나타내기 위함이다. 그래서 클러스터에 속한 모든 브로커에 동일한 KAFKA_KRAFT_CLUSTER_ID를 설정한다.
- KAFKA_CFG_CONTROLLER_QUORUM_VOTERS: 클러스터 내의 컨트롤러들에 대한 정보를 정의한다. 각 컨트롤러는 다른 서비스의 컨트롤러와 통신하여 클러스터를 관리한다.
- KAFKA_CFG_LISTENERS와 KAFKA_CFG_ADVERTISED_LISTENERS: 리스너를 설정하여 Kafka 클라이언트가 브로커에 연결할 수 있는 방법을 지정한다.
- KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR, KAFKA_CFG_TRANSACTION_STATE_LOG_REPLICATION_FACTOR, KAFKA_CFG_TRANSACTION_STATE_LOG_MIN_ISR: 클러스터 내 토픽 및 로그 복제 설정을 정의하여 가용성을 보장한다.
네트워크
- kafka_network에 연결된다.
볼륨
- Kafka 데이터를 저장할 볼륨 Kafka00을 마운트 한다.
Kafka 브로커 서비스 (Kafka01Service 및 Kafka02Service)
- Kafka01Service와 Kafka02Service는 Kafka00Service와 유사한 설정을 가지고 있다.(사실상 몇 개 빼고는 완전히 동일하다.) 주요 차이점은 각각의 브로커 ID 및 노드 ID와 관련된 환경 변수 설정과 포트 매핑이다.
Kafka01Service:
image: bitnami/kafka:3.7.0
restart: unless-stopped
container_name: Kafka01Container
ports:
- '9093:9092' # 내부 네트워크 통신을 위한 PLAINTEXT 리스너
- '10001:10000' # 외부 접근을 위한 EXTERNAL 리스너
environment:
# KRaft 설정
- KAFKA_ENABLE_KRAFT=yes # KRaft 모드 활성화
- KAFKA_CFG_BROKER_ID=1
- KAFKA_CFG_NODE_ID=1
- KAFKA_KRAFT_CLUSTER_ID=HsDBs9l6UUmQq7Y5E6bNlw # 고유 클러스터 ID, 모든 브로커에 동일하게 설정
- KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@Kafka00Service:9093,1@Kafka01Service:9093,2@Kafka02Service:9093
- KAFKA_CFG_PROCESS_ROLES=controller,broker
# 리스너 설정
- KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE=true
- ALLOW_PLAINTEXT_LISTENER=yes
- KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:10000
- KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://Kafka01Service:9092,EXTERNAL://localhost:10001
- KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT
- KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
# 클러스터 설정
- KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR=2
- KAFKA_CFG_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=2
- KAFKA_CFG_TRANSACTION_STATE_LOG_MIN_ISR=2
networks:
- kafka_network
volumes:
- Kafka01:/bitnami/kafka
- Kafka01Service는 BROKER_ID=1, NODE_ID=1로 설정되며, 포트 매핑이 '9093:9092'와 '10001:10000'으로 지정된다.
Kafka02Service:
image: bitnami/kafka:3.7.0
restart: unless-stopped
container_name: Kafka02Container
ports:
- '9094:9092' # 내부 네트워크 통신을 위한 PLAINTEXT 리스너
- '10002:10000' # 외부 접근을 위한 EXTERNAL 리스너
environment:
# KRaft 설정
- KAFKA_ENABLE_KRAFT=yes # KRaft 모드 활성화
- KAFKA_CFG_BROKER_ID=2
- KAFKA_CFG_NODE_ID=2
- KAFKA_KRAFT_CLUSTER_ID=HsDBs9l6UUmQq7Y5E6bNlw # 고유 클러스터 ID, 모든 브로커에 동일하게 설정
- KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@Kafka00Service:9093,1@Kafka01Service:9093,2@Kafka02Service:9093
- KAFKA_CFG_PROCESS_ROLES=controller,broker
# 리스너 설정
- KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE=true
- ALLOW_PLAINTEXT_LISTENER=yes
- KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:10000
- KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://Kafka02Service:9092,EXTERNAL://localhost:10002
- KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT
- KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
# 클러스터 설정
- KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR=2
- KAFKA_CFG_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=2
- KAFKA_CFG_TRANSACTION_STATE_LOG_MIN_ISR=2
networks:
- kafka_network
volumes:
- Kafka02:/bitnami/kafka
- Kafka02Service는 BROKER_ID=2, NODE_ID=2로 설정되며, 포트 매핑이 '9094:9092'와 '10002:10000'으로 지정된다.
KafkaWebUiService 설정 설명 (kafka 관리 웹 UI)
KafkaWebUiService:
image: provectuslabs/kafka-ui:latest
restart: unless-stopped
container_name: KafkaWebUiContainer
ports:
- '8085:8080' # 호스트의 8085 포트를 컨테이너의 8080 포트에 바인딩
environment:
- KAFKA_CLUSTERS_0_NAME=Local-Kraft-Cluster
- KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS=Kafka00Service:9092,Kafka01Service:9092,Kafka02Service:9092
- DYNAMIC_CONFIG_ENABLED=true
- KAFKA_CLUSTERS_0_AUDIT_TOPICAUDITENABLED=true
- KAFKA_CLUSTERS_0_AUDIT_CONSOLEAUDITENABLED=true
depends_on:
- Kafka00Service
- Kafka01Service
- Kafka02Service
networks:
- kafka_network
이미지 설정
- 이 설정은 provectuslabs/kafka-ui 이미지를 사용하여 Kafka UI 컨테이너를 생성한다. latest 태그는 가장 최신 버전의 Kafka UI 이미지를 사용함을 의미한다. Kafka UI는 Kafka 클러스터를 모니터링하고 관리할 수 있는 웹 기반 사용자 인터페이스를 제공한다.
재시작 정책
- Docker 컨테이너의 재시작 정책을 설정한다. unless-stopped로 설정된 경우, 컨테이너는 명시적으로 중지되지 않는 한 항상 재시작된다. 이 설정은 Kafka UI가 항상 실행 중 이도록 보장한다.
컨테이너 이름
- 생성된 Docker 컨테이너의 이름을 KafkaWebUiContainer로 설정한다. 이 이름을 사용하면 Docker 명령어로 쉽게 컨테이너를 관리할 수 있다.
ports 설정 ('8085:8080')
- 호스트의 포트 8085를 컨테이너의 포트 8080에 매핑한다. 이는 호스트 머신에서 http://localhost:8085로 접속하면 컨테이너 내의 Kafka UI 웹 애플리케이션을 사용할 수 있도록 한다.
환경 변수 설정
- KAFKA_CLUSTERS_0_NAME=Local-Kraft-Cluster:
- Kafka UI에서 표시할 Kafka 클러스터의 이름을 설정한다. 여기서는 Local-Kraft-Cluster라는 이름으로 클러스터가 표시된다.
- Kafka UI에서 표시할 Kafka 클러스터의 이름을 설정한다. 여기서는 Local-Kraft-Cluster라는 이름으로 클러스터가 표시된다.
- KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS= Kafka00Service:9092,Kafka01Service:9092,Kafka02Service:9092
- Kafka 클러스터에 연결하기 위한 초기 브로커 주소 목록을 설정한다. 이 목록을 통해 Kafka UI는 클러스터의 메타데이터를 가져오고, 클러스터 상태를 모니터링할 수 있다. Kafka00Service:9092, Kafka01Service:9092, Kafka02Service:9092는 각각 Docker Compose에 정의된 Kafka 브로커 서비스다.
- Kafka 클러스터에 연결하기 위한 초기 브로커 주소 목록을 설정한다. 이 목록을 통해 Kafka UI는 클러스터의 메타데이터를 가져오고, 클러스터 상태를 모니터링할 수 있다. Kafka00Service:9092, Kafka01Service:9092, Kafka02Service:9092는 각각 Docker Compose에 정의된 Kafka 브로커 서비스다.
- DYNAMIC_CONFIG_ENABLED=true
- Kafka UI에서 동적 설정 변경을 허용할지 여부를 결정한다. true로 설정되면 Kafka 클러스터의 설정을 UI를 통해 변경할 수 있다.
- Kafka UI에서 동적 설정 변경을 허용할지 여부를 결정한다. true로 설정되면 Kafka 클러스터의 설정을 UI를 통해 변경할 수 있다.
- KAFKA_CLUSTERS_0_AUDIT_TOPICAUDITENABLED=true
- Kafka UI에서 토픽 관련 활동(예: 토픽 생성, 삭제 등)을 감사할 수 있도록 설정한다. true로 설정하면 토픽의 생성, 삭제, 변경과 같은 활동이 감사 로그에 기록된다.
- Kafka UI에서 토픽 관련 활동(예: 토픽 생성, 삭제 등)을 감사할 수 있도록 설정한다. true로 설정하면 토픽의 생성, 삭제, 변경과 같은 활동이 감사 로그에 기록된다.
- KAFKA_CLUSTERS_0_AUDIT_CONSOLEAUDITENABLED=true
- Kafka UI에서 콘솔에서 수행되는 활동을 감사할 수 있도록 설정한다. true로 설정하면 콘솔에서 수행된 활동들이 감사 로그에 기록된다.
- Kafka UI에서 콘솔에서 수행되는 활동을 감사할 수 있도록 설정한다. true로 설정하면 콘솔에서 수행된 활동들이 감사 로그에 기록된다.
depends_on 설정
- depends_on 옵션은 KafkaWebUiService가 Kafka00Service, Kafka01Service, Kafka02Service가 실행된 후에 시작되도록 설정한다. 이 옵션은 Kafka UI가 Kafka 클러스터에 연결할 수 있도록 클러스터의 모든 브로커 서비스가 준비된 후에 실행되도록 보장한다.
networks 설정
- Kafka UI 컨테이너가 kafka_network라는 Docker 네트워크에 연결되도록 한다. 이는 Kafka 브로커와 같은 네트워크를 공유하게 하여, 브로커와의 통신을 가능하게 한다.
3. Kafka 내부 포트의 역할과 필요성 (설정하는 이유)
내부 포트
- 내부 포트(9092, 9093, 9094)는 Kafka 브로커 간 통신을 위해 사용되며, 메타데이터 동기화와 데이터 복제를 담당한다. 보안과 성능을 최적화하기 위해 클러스터 내부에서만 사용된다.
내부 포트가 필요한 이유 1 (브로커 간의 내부 통신)
브로커 간 메타데이터 동기화
- Kafka 클러스터는 여러 브로커로 구성되며, 각 브로커는 클러스터의 상태와 메타데이터(토픽, 파티션, 리더 브로커 정보 등)를 유지해야 한다. 이를 위해 브로커들은 주기적으로 서로 통신하며 메타데이터를 동기화한다. 이 동기화 작업은 내부 네트워크에서 안전하고 빠르게 이루어져야 하며, 이는 9092와 9093 같은 내부 포트를 통해 수행된다.
파티션 리더와 팔로워 간의 데이터 복제
- Kafka는 고가용성과 내구성을 위해 파티션 리더가 데이터를 수신하면 팔로워 브로커에게 데이터를 복제한다. 이 복제 과정도 내부 네트워크에서 발생하며, 내부 포트를 통해 브로커 간 통신이 이루어진다.
내부 포트가 필요한 이유 2 (보안과 성능)
보안
- 내부 포트를 사용하면 Kafka 클러스터 내의 통신이 외부로부터 격리된다. 이는 클러스터 내에서만 사용되는 민감한 데이터를 보호하는 데 도움이 된다. PLAINTEXT 리스너를 내부 네트워크 통신에만 사용함으로써 클러스터 외부에서의 무단 접근을 방지할 수 있다.
성능 최적화
- 내부 통신을 전용 포트를 통해 수행함으로써 네트워크 성능을 최적화할 수 있다. 내부 통신은 일반적으로 고속 로컬 네트워크에서 이루어지기 때문에 외부 통신과 분리하여 더 높은 성능과 신뢰성을 보장할 수 있다.
4. Kafka 외부 포트의 역할과 필요성 (설정하는 이유)
외부 포트
- 외부 포트(10000, 10001, 10002)는 외부 애플리케이션이 Kafka 브로커에 연결하여 데이터를 송수신할 수 있도록 하는 역할을 한다. 외부 클라이언트 접근과 멀티테넌시를 지원하며, 이를 통해 애플리케이션의 데이터 수집 및 분산 처리 요구를 충족시킨다.
내부 포트가 필요한 이유 1 (클라이언트 접근)
외부 클라이언트 연결
- Kafka 클러스터는 다양한 외부 애플리케이션(예: Spring Boot 애플리케이션, 데이터 처리 파이프라인, 분석 도구 등)에서 데이터를 수집하고 분산 처리하기 위해 사용된다. 외부 포트(10000, 10001, 10002)는 이러한 애플리케이션들이 Kafka 브로커에 연결하여 데이터를 송수신할 수 있도록 허용한다.
Bootstrap 서버로 사용
- 외부 애플리케이션은 Kafka 클러스터와의 초기 연결을 설정하기 위해 bootstrap-servers를 사용한다. 예를 들어, Spring 애플리케이션의 application.yml에서 bootstrap-servers 설정을 통해 Kafka 브로커에 연결을 설정할 수 있다.
spring:
# 카프카 설정
kafka:
consumer:
bootstrap-servers: localhost:10000,localhost:10001,localhost:10002
group-id: member-group
producer:
bootstrap-servers: localhost:10000,localhost:10001,localhost:10002
- 여기서 bootstrap-servers는 클라이언트가 Kafka 클러스터에 처음 연결할 때 사용하는 초기 브로커 주소 목록이다. 클라이언트는 이 주소를 통해 클러스터의 메타데이터를 가져오고, 다른 브로커들과의 연결을 설정할 수 있다.
내부 포트가 필요한 이유 2 (멀티테넌시와 접근 제어)
멀티테넌시 지원
- Kafka 클러스터는 여러 애플리케이션 및 팀이 동시에 사용할 수 있도록 설계되었다. 외부 포트를 사용하여 애플리케이션 별로 접근을 제어할 수 있으며, 필요에 따라 각 애플리케이션이 접근할 수 있는 브로커를 분리하여 멀티테넌시를 지원한다.
접근 제어 및 네트워크 분리
- 외부 포트를 사용하는 설정은 클러스터 관리자가 외부 클라이언트와의 네트워크 트래픽을 제어하고 격리하는 데 도움이 된다. 외부 포트는 클러스터 내부 통신과는 다른 네트워크 인터페이스에서 동작할 수 있어, 보다 세밀한 네트워크 보안 정책을 적용할 수 있다.
5. KRaft 모드의 주요 특징과 장점 (설정하는 이유)
KRaft 모드란 무엇인가?
- KRaft 모드(Kafka Raft 모드)는 ZooKeeper 없이 Kafka 클러스터를 운영할 수 있도록 하는 Kafka의 새로운 운영 모드다. KAFKA_ENABLE_KRAFT=yes로 설정되면 KRaft 모드가 활성화되어 Kafka 브로커들이 스스로 클러스터를 관리하고 메타데이터를 유지할 수 있다.
- 이 모드에서는 Kafka 브로커가 클러스터의 구성과 상태를 관리하는 컨트롤러(controller) 역할을 수행하며, 데이터의 저장과 전송을 담당하는 브로커(broker) 역할도 동시에 수행할 수 있다.
KRaft 모드의 주요 특징
- ZooKeeper의 필요성 제거
- KRaft 모드는 Kafka 브로커가 자체적으로 클러스터를 관리할 수 있도록 설계되었으며, 이를 통해 Kafka 클러스터 운영에서 ZooKeeper를 사용하지 않아도 된다. 이는 클러스터 구성과 운영을 더 간단하게 만들고, 운영 비용을 줄일 수 있다.
- KRaft 모드는 Kafka 브로커가 자체적으로 클러스터를 관리할 수 있도록 설계되었으며, 이를 통해 Kafka 클러스터 운영에서 ZooKeeper를 사용하지 않아도 된다. 이는 클러스터 구성과 운영을 더 간단하게 만들고, 운영 비용을 줄일 수 있다.
- 메타데이터 관리의 통합
- KRaft 모드에서는 클러스터의 모든 메타데이터(토픽, 파티션, 리더 정보 등)를 Kafka 브로커 자체에서 관리한다. 이를 통해 클러스터의 메타데이터 관리가 통합되고, ZooKeeper와의 중복성을 제거하여 성능과 안정성을 향상시킨다.
- KRaft 모드에서는 클러스터의 모든 메타데이터(토픽, 파티션, 리더 정보 등)를 Kafka 브로커 자체에서 관리한다. 이를 통해 클러스터의 메타데이터 관리가 통합되고, ZooKeeper와의 중복성을 제거하여 성능과 안정성을 향상시킨다.
- 컨트롤러 쿼럼을 통한 고가용성
- KAFKA_CFG_CONTROLLER_QUORUM_VOTERS 환경 변수는 KRaft 모드에서 각 브로커가 컨트롤러 쿼럼에 참여하도록 설정한다. 이 변수는 클러스터의 메타데이터 변경 작업(예: 리더 선출, 파티션 이동 등)을 처리하는 브로커들 사이에서 투표를 통해 합의를 이룰 수 있게 한다.
- 예를 들어, KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@Kafka00Service:9093,1@Kafka01Service:9093,2@Kafka02Service:9093와 같이 설정하면, 각 브로커가 컨트롤러 쿼럼의 구성원으로서 중요한 결정에 참여한다. 이는 클러스터의 메타데이터가 일관되게 유지되도록 보장한다.
- KAFKA_CFG_CONTROLLER_QUORUM_VOTERS 환경 변수는 KRaft 모드에서 각 브로커가 컨트롤러 쿼럼에 참여하도록 설정한다. 이 변수는 클러스터의 메타데이터 변경 작업(예: 리더 선출, 파티션 이동 등)을 처리하는 브로커들 사이에서 투표를 통해 합의를 이룰 수 있게 한다.
컨트롤러 쿼럼의 역할
- 컨트롤러 쿼럼은 Kafka 클러스터에서 고가용성을 보장하는 핵심 메커니즘이다. KRaft 모드에서는 여러 브로커가 컨트롤러 역할을 수행할 수 있으며, 이들은 다음과 같은 역할을 한다.
- 클러스터 상태 관리
- 컨트롤러 쿼럼은 클러스터의 현재 상태와 메타데이터를 유지하고 관리한다. 이들은 새로운 브로커의 추가, 파티션 리더의 변경, 파티션의 이동 등을 처리한다.
- 컨트롤러 쿼럼은 클러스터의 현재 상태와 메타데이터를 유지하고 관리한다. 이들은 새로운 브로커의 추가, 파티션 리더의 변경, 파티션의 이동 등을 처리한다.
- 안정성 및 장애 조치
- 컨트롤러 쿼럼을 구성하는 여러 브로커는 Kafka 클러스터의 장애 상황에서도 정상 작동을 보장한다. 예를 들어, 하나의 브로커가 장애를 겪더라도 다른 컨트롤러 브로커들이 클러스터의 상태를 유지하고 메타데이터 관리를 계속 수행할 수 있다.
- 이와 같은 메커니즘은 클러스터가 높은 가용성과 내구성을 유지할 수 있도록 지원하며, 중요한 메타데이터와 클러스터 상태가 손실되지 않도록 보장한다.
- 컨트롤러 쿼럼을 구성하는 여러 브로커는 Kafka 클러스터의 장애 상황에서도 정상 작동을 보장한다. 예를 들어, 하나의 브로커가 장애를 겪더라도 다른 컨트롤러 브로커들이 클러스터의 상태를 유지하고 메타데이터 관리를 계속 수행할 수 있다.
- 복구와 리더 선출
- 클러스터에서 장애가 발생했을 때, 컨트롤러 쿼럼은 리더 선출 과정을 통해 빠르게 복구할 수 있다. 이 과정을 통해 클러스터의 운영이 최소한의 다운타임으로 유지된다.
요약하자면 KRaft 모드는 Kafka 클러스터에서 ZooKeeper의 필요성을 제거하고, 브로커들이 클러스터의 메타데이터와 상태를 직접 관리하도록 한다. KRaft 모드는 컨트롤러 쿼럼을 통해 고가용성과 안정성을 보장하며, 클러스터의 중요한 메타데이터 관리 작업을 효율적으로 처리한다. 이를 통해 Kafka 클러스터의 운영이 더욱 간편해지고, 안정성이 향상된다.
6. Kafka UI를 통한 클러스터 상태 확인
Kafka UI 사용하기
- 명령어로 Kafka의 실행 여부를 검증하는 것도 가능하지만 Docker Compose 파일에서 설정한 Kafka UI 컨테이너(KafkaWebUiService)를 통해 웹 인터페이스에서 Kafka 클러스터의 상태를 모니터링할 수 있다.
- Kafka UI 접속: 웹 브라우저에서 http://localhost:8085로 접속한다.
- Kafka 브로커 및 토픽 상태 확인: UI에서 클러스터 상태, 브로커 리스트, 토픽 목록 등을 확인할 수 있다. 브로커가 정상적으로 작동 중이라면 클러스터와 브로커 정보가 정확하게 표시된다.
대시보드 확인
브로커 정보 확인
토픽 정보 확인
명령어로 Kafka 상태 확인하기
docker exec -it Kafka00Container kafka-topics.sh --bootstrap-server localhost:9092 --describe --topic __consumer_offsets
- 이 명령어는 __consumer_offsets 토픽에 대한 메타데이터를 보여준다. 해당 정보에는 파티션 리더, ISR(In-Sync Replica) 등이 포함된다. 이 정보가 올바르게 표시되면 클러스터의 메타데이터가 정상적으로 동기화되고 있음을 의미한다.
- 정상적인 상황이라면 아래와 같이 표시된다. (터미널에서 명령어를 입력)
다음 포스팅에서는 Kafka를 스프링에서 어떻게 사용하는지 다뤄볼 예정이다.
'유용한 개발지식 > Apache Kafka' 카테고리의 다른 글
Kafka에서 Locale.ROOT 사용의 중요성 (3) | 2024.12.06 |
---|---|
[kafka] Spring실행 시 consumer 연결문제 해결 (8) | 2024.02.18 |
[kafka] 스프링부트와 kafka를 이용한 slack 예외알림 구현 (1) | 2024.02.18 |
[Kafka] 슬랙 webhook 설정하기 (kafka에서 호출) (0) | 2024.02.18 |
[Kafka] SpringBoot3.x.x에서 Kafka 연동하기 (2) | 2024.02.18 |