
들어가며
현대의 대규모 분산 시스템에서 실시간 데이터 처리와 메시지 스트리밍은 필수 요소가 되었습니다. 이번 글에서는 Docker Compose의 개념부터 시작해서 Apache Kafka와 Zookeeper를 활용한 강력한 메시지 스트리밍 환경을 구축하는 방법을 단계별로 알아보겠습니다.
Docker Compose는 여러 개의 Docker 컨테이너로 구성된 애플리케이션을 정의하고 실행할 수 있게 해주는 도구입니다. 단일 명령어로 복잡한 멀티 컨테이너 애플리케이션을 쉽게 관리할 수 있습니다.
YAML 기반 설정
docker-compose.yml 파일에 모든 서비스 구성을 선언적으로 정의합니다. 코드로 인프라를 관리하는 IaC(Infrastructure as Code) 방식입니다.
서비스 오케스트레이션
여러 컨테이너 간의 의존성과 실행 순서를 자동으로 관리합니다. 데이터베이스가 먼저 실행되고 애플리케이션이 나중에 실행되는 등의 순서를 보장할 수 있습니다.
네트워크 격리
관련된 컨테이너들을 동일한 네트워크에 배치하여 서로 통신할 수 있게 하면서, 외부와는 격리된 환경을 제공합니다.
볼륨 관리
데이터의 영속성을 보장하기 위해 컨테이너와 호스트 간의 볼륨 매핑을 쉽게 설정할 수 있습니다.
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
간편한 환경 구성
복잡한 개발 환경을 새로운 개발자가 단 한 번의 명령어로 구축할 수 있습니다.
일관된 환경
모든 팀원이 동일한 환경에서 개발할 수 있어 "내 컴퓨터에서는 잘 되는데" 문제를 해결합니다.
쉬운 확장성
서비스를 추가하거나 설정을 변경할 때 YAML 파일만 수정하면 됩니다.
테스트 환경 구축
CI/CD 파이프라인에서 테스트용 환경을 빠르게 생성하고 제거할 수 있습니다.
Apache Kafka는 LinkedIn에서 개발한 분산 스트리밍 플랫폼으로, 대용량의 실시간 데이터를 안정적으로 처리할 수 있는 메시지 브로커입니다.
토픽 (Topic)
메시지가 저장되는 논리적인 채널입니다. 예를 들어 "주문 처리", "사용자 활동", "결제 정보" 등의 주제별로 토픽을 만들어 관리합니다.
프로듀서 (Producer)
토픽에 메시지를 발행하는 애플리케이션입니다. 웹 서버, IoT 디바이스, 로그 수집기 등이 프로듀서 역할을 할 수 있습니다.
컨슈머 (Consumer)
토픽에서 메시지를 구독하고 처리하는 애플리케이션입니다. 데이터 분석 시스템, 알림 서비스, 데이터베이스 동기화 등에 사용됩니다.
파티션 (Partition)
토픽을 여러 파티션으로 나누어 병렬 처리와 확장성을 제공합니다. 각 파티션은 순서가 보장된 메시지 큐입니다.
브로커 (Broker)
Kafka 서버 인스턴스로, 메시지를 저장하고 클라이언트 요청을 처리합니다.
높은 처리량 (High Throughput)
초당 수백만 개의 메시지를 처리할 수 있어 대규모 실시간 데이터 처리에 적합합니다.
내구성 (Durability)
메시지를 디스크에 저장하여 시스템 장애 시에도 데이터 손실을 방지합니다.
확장성 (Scalability)
브로커를 추가하여 수평적으로 확장할 수 있으며, 파티션을 통해 병렬 처리가 가능합니다.
장애 허용성 (Fault Tolerance)
복제(Replication) 기능을 통해 일부 브로커가 장애를 일으켜도 서비스가 지속됩니다.
실시간 분석
웹사이트 클릭 스트림, 사용자 행동 데이터를 실시간으로 분석하여 개인화 서비스 제공
로그 수집
여러 애플리케이션의 로그를 중앙으로 수집하여 모니터링과 디버깅에 활용
이벤트 소싱
시스템의 모든 변경사항을 이벤트로 기록하여 상태 재구성과 감사 추적 가능
마이크로서비스 통신
서비스 간 비동기 통신을 통해 느슨한 결합과 높은 확장성 달성
Apache Zookeeper는 분산 시스템을 위한 중앙 집중식 서비스로, 설정 관리, 네이밍, 동기화, 그룹 서비스를 제공합니다. Kafka에서는 클러스터 메타데이터 관리와 리더 선출에 사용됩니다.
메타데이터 관리
Kafka 브로커 정보, 토픽 설정, 파티션 정보 등을 저장하고 관리합니다.
리더 선출
여러 브로커 중에서 파티션의 리더를 선출하고 관리합니다.
설정 동기화
클러스터 내 모든 브로커가 동일한 설정을 유지하도록 보장합니다.
상태 모니터링
브로커의 생존 상태를 모니터링하고 장애 감지 시 재구성을 수행합니다.
일관성 보장
모든 클라이언트가 동일한 데이터 뷰를 보도록 강력한 일관성을 제공합니다.
고가용성
홀수 개의 서버로 구성된 앙상블을 통해 장애 허용성을 제공합니다.
순서 보장
클라이언트의 모든 요청이 순서대로 처리됩니다.
원자성
모든 업데이트가 성공하거나 실패하며, 부분적인 업데이트는 발생하지 않습니다.
이제 Docker Compose를 사용하여 실제 Kafka와 Zookeeper 환경을 구축해보겠습니다.
먼저 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와 아키텍처를 자동으로 감지하여 적절한 바이너리를 다운로드합니다.
Kafka 관련 파일들을 관리할 디렉토리를 생성합니다.
mkdir -p ~/kafka
cd ~/kafka
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
Zookeeper 서비스
Kafka 서비스
Kafka UI 서비스
네트워크 설정
데이터 영속성을 위한 디렉토리를 생성하고 권한을 설정합니다.
mkdir -p ~/kafka/zookeeper-data
mkdir -p ~/kafka/kafka-data
chmod -R 777 ~/kafka/zookeeper-data
chmod -R 777 ~/kafka/kafka-data
권한을 777로 설정하는 이유는 컨테이너 내부의 사용자가 데이터를 쓸 수 있도록 하기 위함입니다.
이제 모든 서비스를 한 번에 실행합니다.
cd ~/kafka
docker-compose up -d
-d 옵션은 백그라운드에서 실행하도록 하는 detached 모드입니다.
실행 과정:
1. 네트워크 생성: kafka-net 브리지 네트워크 생성
2. Zookeeper 시작: 메타데이터 관리 서비스 시작
3. Kafka 시작: Zookeeper 연결 후 브로커 시작
4. Kafka UI 시작: 관리 도구 시작
모든 서비스가 정상적으로 실행되었는지 확인합니다.
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
외부에서 접근할 수 있도록 필요한 포트를 개방합니다.
# Zookeeper 포트
sudo ufw allow 2181/tcp
# Kafka 포트
sudo ufw allow 9092/tcp
# Kafka UI 포트
sudo ufw allow 8084/tcp
각 포트의 용도:
웹 브라우저에서 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 환경 구축을 통해 강력한 메시지 스트리밍 플랫폼을 성공적으로 구축했습니다. 이제 실시간 데이터 처리, 마이크로서비스 간 통신, 이벤트 기반 아키텍처 구현 등 다양한 용도로 활용할 수 있습니다.