Docker Compose로 간단하게 kafka 구성하기

김슭삵·2025년 5월 26일
post-thumbnail

들어가며

현대의 대규모 분산 시스템에서 실시간 데이터 처리와 메시지 스트리밍은 필수 요소가 되었습니다. 이번 글에서는 Docker Compose의 개념부터 시작해서 Apache Kafka와 Zookeeper를 활용한 강력한 메시지 스트리밍 환경을 구축하는 방법을 단계별로 알아보겠습니다.

Docker Compose란?

Docker Compose는 여러 개의 Docker 컨테이너로 구성된 애플리케이션을 정의하고 실행할 수 있게 해주는 도구입니다. 단일 명령어로 복잡한 멀티 컨테이너 애플리케이션을 쉽게 관리할 수 있습니다.

Docker Compose의 핵심 개념

YAML 기반 설정
docker-compose.yml 파일에 모든 서비스 구성을 선언적으로 정의합니다. 코드로 인프라를 관리하는 IaC(Infrastructure as Code) 방식입니다.

서비스 오케스트레이션
여러 컨테이너 간의 의존성과 실행 순서를 자동으로 관리합니다. 데이터베이스가 먼저 실행되고 애플리케이션이 나중에 실행되는 등의 순서를 보장할 수 있습니다.

네트워크 격리
관련된 컨테이너들을 동일한 네트워크에 배치하여 서로 통신할 수 있게 하면서, 외부와는 격리된 환경을 제공합니다.

볼륨 관리
데이터의 영속성을 보장하기 위해 컨테이너와 호스트 간의 볼륨 매핑을 쉽게 설정할 수 있습니다.

Docker vs Docker Compose

Docker 단독 사용

# 각각 따로 실행해야 함
docker run -d --name mysql-db mysql:8.0
docker run -d --name web-app --link mysql-db myapp:latest
docker run -d --name nginx-proxy --link web-app nginx:latest

Docker Compose 사용

# 한 번에 모든 서비스 실행
docker-compose up -d

Docker Compose의 장점

간편한 환경 구성
복잡한 개발 환경을 새로운 개발자가 단 한 번의 명령어로 구축할 수 있습니다.

일관된 환경
모든 팀원이 동일한 환경에서 개발할 수 있어 "내 컴퓨터에서는 잘 되는데" 문제를 해결합니다.

쉬운 확장성
서비스를 추가하거나 설정을 변경할 때 YAML 파일만 수정하면 됩니다.

테스트 환경 구축
CI/CD 파이프라인에서 테스트용 환경을 빠르게 생성하고 제거할 수 있습니다.

Apache Kafka란?

Apache Kafka는 LinkedIn에서 개발한 분산 스트리밍 플랫폼으로, 대용량의 실시간 데이터를 안정적으로 처리할 수 있는 메시지 브로커입니다.

Kafka의 핵심 개념

토픽 (Topic)
메시지가 저장되는 논리적인 채널입니다. 예를 들어 "주문 처리", "사용자 활동", "결제 정보" 등의 주제별로 토픽을 만들어 관리합니다.

프로듀서 (Producer)
토픽에 메시지를 발행하는 애플리케이션입니다. 웹 서버, IoT 디바이스, 로그 수집기 등이 프로듀서 역할을 할 수 있습니다.

컨슈머 (Consumer)
토픽에서 메시지를 구독하고 처리하는 애플리케이션입니다. 데이터 분석 시스템, 알림 서비스, 데이터베이스 동기화 등에 사용됩니다.

파티션 (Partition)
토픽을 여러 파티션으로 나누어 병렬 처리와 확장성을 제공합니다. 각 파티션은 순서가 보장된 메시지 큐입니다.

브로커 (Broker)
Kafka 서버 인스턴스로, 메시지를 저장하고 클라이언트 요청을 처리합니다.

Kafka의 주요 특징

높은 처리량 (High Throughput)
초당 수백만 개의 메시지를 처리할 수 있어 대규모 실시간 데이터 처리에 적합합니다.

내구성 (Durability)
메시지를 디스크에 저장하여 시스템 장애 시에도 데이터 손실을 방지합니다.

확장성 (Scalability)
브로커를 추가하여 수평적으로 확장할 수 있으며, 파티션을 통해 병렬 처리가 가능합니다.

장애 허용성 (Fault Tolerance)
복제(Replication) 기능을 통해 일부 브로커가 장애를 일으켜도 서비스가 지속됩니다.

Kafka 사용 사례

실시간 분석
웹사이트 클릭 스트림, 사용자 행동 데이터를 실시간으로 분석하여 개인화 서비스 제공

로그 수집
여러 애플리케이션의 로그를 중앙으로 수집하여 모니터링과 디버깅에 활용

이벤트 소싱
시스템의 모든 변경사항을 이벤트로 기록하여 상태 재구성과 감사 추적 가능

마이크로서비스 통신
서비스 간 비동기 통신을 통해 느슨한 결합과 높은 확장성 달성

Apache Zookeeper란?

Apache Zookeeper는 분산 시스템을 위한 중앙 집중식 서비스로, 설정 관리, 네이밍, 동기화, 그룹 서비스를 제공합니다. Kafka에서는 클러스터 메타데이터 관리와 리더 선출에 사용됩니다.

Zookeeper의 주요 역할

메타데이터 관리
Kafka 브로커 정보, 토픽 설정, 파티션 정보 등을 저장하고 관리합니다.

리더 선출
여러 브로커 중에서 파티션의 리더를 선출하고 관리합니다.

설정 동기화
클러스터 내 모든 브로커가 동일한 설정을 유지하도록 보장합니다.

상태 모니터링
브로커의 생존 상태를 모니터링하고 장애 감지 시 재구성을 수행합니다.

Zookeeper의 특징

일관성 보장
모든 클라이언트가 동일한 데이터 뷰를 보도록 강력한 일관성을 제공합니다.

고가용성
홀수 개의 서버로 구성된 앙상블을 통해 장애 허용성을 제공합니다.

순서 보장
클라이언트의 모든 요청이 순서대로 처리됩니다.

원자성
모든 업데이트가 성공하거나 실패하며, 부분적인 업데이트는 발생하지 않습니다.

Kafka + Zookeeper 환경 구축하기

이제 Docker Compose를 사용하여 실제 Kafka와 Zookeeper 환경을 구축해보겠습니다.

1단계: Docker Compose 설치

먼저 Docker Compose를 설치해야 합니다.

# Docker Compose 설치
sudo curl -L "https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

# 설치 확인
docker-compose --version

$(uname -s)$(uname -m)은 현재 시스템의 OS와 아키텍처를 자동으로 감지하여 적절한 바이너리를 다운로드합니다.

2단계: 프로젝트 디렉토리 생성

Kafka 관련 파일들을 관리할 디렉토리를 생성합니다.

mkdir -p ~/kafka
cd ~/kafka

3단계: Docker Compose 파일 생성

docker-compose.yml 파일을 생성하고 다음 내용을 작성합니다.

vi docker-compose.yml
version: '3'
services:
  zookeeper:
    image: confluentinc/cp-zookeeper:7.3.2
    container_name: <container_name>
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000
    ports:
      - "2181:2181"
    volumes:
      - ./zookeeper-data:/var/lib/zookeeper/data
    restart: always
    networks:
      - kafka-net

  kafka:
    image: confluentinc/cp-kafka:7.3.2
    container_name: <kafka_container_name>
    depends_on:
      - zookeeper
    ports:
      - "9092:9092"
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: <zookeeper_container_name>:2181
      KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:29092,PLAINTEXT_HOST://0.0.0.0:9092
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://<kafka_container_name>:29092,PLAINTEXT_HOST://localhost:9092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_HEAP_OPTS: "-Xmx1G -Xms1G"
    volumes:
      - ./kafka-data:/var/lib/kafka/data
    restart: always
    networks:
      - kafka-net

  kafka-ui:
    image: provectuslabs/kafka-ui:latest
    container_name: <kafka_ui_container_name>
    depends_on:
      - kafka
      - zookeeper
    ports:
      - "8084:8080"
    environment:
      KAFKA_CLUSTERS_0_NAME: <kafka_cluster_name>
      KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: <kafka_container_name>:29092
      KAFKA_CLUSTERS_0_ZOOKEEPER: <zookeeper_container_name>:2181
    restart: always
    networks:
      - kafka-net

networks:
  kafka-net:
    driver: bridge

Docker Compose 파일 상세 분석

Zookeeper 서비스

  • image: Confluent에서 제공하는 공식 Zookeeper 이미지 사용
  • ports: 2181 포트를 호스트에 노출하여 외부 접근 허용
  • environment: 클라이언트 포트와 틱 타임 설정
  • volumes: 데이터 영속성을 위한 볼륨 매핑

Kafka 서비스

  • depends_on: Zookeeper가 먼저 실행되도록 의존성 설정
  • KAFKA_LISTENERS: Kafka가 리스닝할 주소 설정
  • KAFKA_ADVERTISED_LISTENERS: 클라이언트가 접속할 주소 설정
  • KAFKA_HEAP_OPTS: JVM 힙 메모리 설정 (1GB)

Kafka UI 서비스

  • Web 기반 관리 도구: 토픽, 컨슈머, 메시지를 시각적으로 관리
  • 포트 8084: 웹 브라우저에서 접근 가능

네트워크 설정

  • kafka-net: 모든 서비스가 동일한 네트워크에서 통신

4단계: 데이터 디렉토리 생성

데이터 영속성을 위한 디렉토리를 생성하고 권한을 설정합니다.

mkdir -p ~/kafka/zookeeper-data
mkdir -p ~/kafka/kafka-data
chmod -R 777 ~/kafka/zookeeper-data
chmod -R 777 ~/kafka/kafka-data

권한을 777로 설정하는 이유는 컨테이너 내부의 사용자가 데이터를 쓸 수 있도록 하기 위함입니다.

5단계: Docker Compose 실행

이제 모든 서비스를 한 번에 실행합니다.

cd ~/kafka
docker-compose up -d

-d 옵션은 백그라운드에서 실행하도록 하는 detached 모드입니다.

실행 과정:
1. 네트워크 생성: kafka-net 브리지 네트워크 생성
2. Zookeeper 시작: 메타데이터 관리 서비스 시작
3. Kafka 시작: Zookeeper 연결 후 브로커 시작
4. Kafka UI 시작: 관리 도구 시작

6단계: 서비스 상태 확인

모든 서비스가 정상적으로 실행되었는지 확인합니다.

docker-compose ps

정상적으로 실행되면 다음과 같이 출력됩니다:

NAME                    	 STATE    PORTS
<kafka_container_name>       Up       0.0.0.0:9092->9092/tcp
<kafka_ui_container_name>    Up       0.0.0.0:8084->8080/tcp
<zookeeper_container_name>   Up       0.0.0.0:2181->2181/tcp

7단계: 방화벽 설정

외부에서 접근할 수 있도록 필요한 포트를 개방합니다.

# Zookeeper 포트
sudo ufw allow 2181/tcp

# Kafka 포트
sudo ufw allow 9092/tcp

# Kafka UI 포트 
sudo ufw allow 8084/tcp

각 포트의 용도:

  • 2181: Zookeeper 클라이언트 접속 포트
  • 9092: Kafka 브로커 접속 포트
  • 8084: Kafka UI 웹 인터페이스 포트

Kafka 환경 테스트

Kafka UI 접속

웹 브라우저에서 http://[EC2-IP]:8084로 접속하면 Kafka UI에 접근할 수 있습니다. 여기서 토픽 생성, 메시지 발송, 컨슈머 모니터링 등을 시각적으로 수행할 수 있습니다.

명령어를 통한 테스트

# Kafka 컨테이너 접속
docker exec -it awoofinance-kafka bash

# 토픽 생성
kafka-topics --create --topic test-topic --bootstrap-server localhost:9092 --partitions 1 --replication-factor 1

# 토픽 목록 확인
kafka-topics --list --bootstrap-server localhost:9092

# 메시지 발송 (프로듀서)
kafka-console-producer --topic test-topic --bootstrap-server localhost:9092

# 메시지 수신 (컨슈머) - 새 터미널에서
kafka-console-consumer --topic test-topic --from-beginning --bootstrap-server localhost:9092

운영 및 모니터링

로그 확인

# 모든 서비스 로그 확인
docker-compose logs

# 특정 서비스 로그 확인
docker-compose logs kafka

# 실시간 로그 모니터링
docker-compose logs -f

서비스 관리

# 서비스 중지
docker-compose stop

# 서비스 재시작
docker-compose restart

# 서비스 완전 제거 (데이터 보존)
docker-compose down

# 서비스와 볼륨까지 완전 제거
docker-compose down -v

성능 튜닝

메모리 설정

KAFKA_HEAP_OPTS: "-Xmx2G -Xms2G"  # 더 많은 메모리 할당

파티션 설정

# 더 많은 파티션으로 병렬 처리 향상
kafka-topics --create --topic high-throughput-topic --bootstrap-server localhost:9092 --partitions 10 --replication-factor 1

보안 고려사항

네트워크 보안

# 외부 접근 제한 (내부 통신만 허용)
ports: []  # 포트 노출 제거

인증 설정

프로덕션 환경에서는 SASL/SSL을 통한 인증과 암호화를 설정해야 합니다.

데이터 암호화

중요한 데이터의 경우 메시지 레벨에서의 암호화를 고려해야 합니다.

마치며

Docker Compose를 활용한 Kafka와 Zookeeper 환경 구축을 통해 강력한 메시지 스트리밍 플랫폼을 성공적으로 구축했습니다. 이제 실시간 데이터 처리, 마이크로서비스 간 통신, 이벤트 기반 아키텍처 구현 등 다양한 용도로 활용할 수 있습니다.

profile
비전공자의 개발 적응기

0개의 댓글