이 프로젝트는 Amazon EKS(Elastic Kubernetes Service) 클러스터에 실시간 데이터 스트리밍 파이프라인을 배포하기 위한 Kubernetes 매니페스트 파일들을 포함합니다.
시스템은 다음과 같은 컴포넌트로 구성됩니다:
Web Application Server (WAS)
|
v
Kafka Cluster (Strimzi) ──> Kafka Connect
| |
v v
Spark Streaming Application Monitoring Stack
(Prometheus, Grafana, Kafka Exporter)
- Web Application Server: 사용자 활동 로그를 생성하고 Kafka로 전송
- Kafka Cluster: 메시지 브로커로 실시간 데이터 스트리밍 허브 역할
- Spark Application: Kafka에서 데이터를 소비하여 실시간 처리
- Amazon EKS 클러스터 (eksctl로 생성)
- kubectl 설치 및 클러스터 접근 권한
- Strimzi Kafka Operator 설치
- Spark Operator 설치
시스템은 다음 네임스페이스로 구성됩니다:
kafka: Kafka 클러스터 및 관련 리소스 (Kafka Connect 포함)was: Web Application Serverlogging-system: Log Generatordefault: Spark Application 및 관련 리소스spark-operator: Spark Operatormonitoring: 모니터링 스택 (Prometheus, Grafana, Kafka Exporter)
- File:
kafka-strimzi.yaml,kafka-nodepool.yaml - Namespace:
kafka - Cluster Name:
streaming-cluster - Brokers: 3개
- Version: Kafka 3.7.0
- Storage: Persistent Volume (10Gi per broker)
- Files:
topic.yaml,topic-user-activity-logs.yaml - Topics:
streaming-topic(3 파티션, 3 리플리케이션)user-activity-logs(WAS와 Spark가 사용, 3 파티션, 3 리플리케이션)
- Retention: 600000ms (10 minutes)
- Bootstrap Service:
streaming-cluster-kafka-bootstrap.kafka.svc.cluster.local:9092 - Type: ClusterIP
- Port: 9092
- File:
was-deployment.yaml - Namespace:
was - Replicas: 2
- Image:
ji0513ji/log-generator:1.1.2 - Port: 8080
- Liveness Probe:
/mainendpoint, 60초 초기 지연 - Readiness Probe:
/mainendpoint, 30초 초기 지연
- Internal Service:
was-service(ClusterIP, port 80) - External Service:
was-service-external(NodePort, port 30080)
KAFKA_BOOTSTRAP_SERVERS:streaming-cluster-kafka-bootstrap.kafka.svc.cluster.local:9092SPRING_KAFKA_BOOTSTRAP_SERVERS:streaming-cluster-kafka-bootstrap.kafka.svc.cluster.local:9092- 사용 토픽:
user-activity-logs
- File:
spark-direct.yaml - Namespace:
default - Pod Name:
spark-streaming - Image:
doyoomii/spark-k8s:latest - Main Application:
user_activity_streaming.py(ConfigMap에서 마운트) - Kafka 토픽:
user-activity-logs - MinIO 연결:
http://minio.storage.svc.cluster.local:9000 - S3A 라이브러리:
org.apache.hadoop:hadoop-aws:3.3.4,org.apache.hadoop:hadoop-common:3.3.4
- File:
spark-app.yaml - Namespace:
default - Type: Python
- Mode: cluster
- Spark Version: 3.3.1
- Image:
doyoomii/spark-k8s:latest - Main Application:
user_activity_streaming.py
- Cores: 1
- Memory: 1g
- Service Account:
spark
- Cores: 1
- Memory: 2g
- Instances: 2
KAFKA_BOOTSTRAP_SERVERS:streaming-cluster-kafka-bootstrap.kafka.svc.cluster.local:9092
- ServiceAccount:
spark-serviceaccount.yaml - ConfigMap:
spark-code-configmap.yaml(Spark 스트리밍 코드 포함)
- File:
log-generator.yaml - Namespace:
logging-system - Replicas: 1
- Image:
ji0513ji/log-generator:1.1.1
KAFKA_BOOTSTRAP_SERVERS:streaming-cluster-kafka-bootstrap.kafka.svc.cluster.local:9092
- File:
prometheus-deployment.yaml,prometheus-configmap.yaml - Namespace:
monitoring - Port: 9090
- Storage: EmptyDir (프로덕션에서는 PersistentVolume 사용 권장)
- Scrape Targets: Kafka Exporter, Prometheus itself
- File:
grafana-deployment.yaml - Namespace:
monitoring - Port: 3000 (Internal), 30300 (NodePort)
- Default Credentials: admin/admin
- Data Source: Prometheus (자동 설정 필요)
- File:
kafka-exporter-deployment.yaml - Namespace:
monitoring - Port: 9308
- Purpose: Kafka 메트릭을 Prometheus 형식으로 노출
- File:
kafka-connect.yaml - Namespace:
kafka - Replicas: 2
- Version: 4.0.0
- Purpose: Kafka와 외부 시스템 간 데이터 연결 (예: HDFS Sink Connector)
- File:
minio-deployment.yaml - Namespace:
storage - Replicas: 1
- Image:
minio/minio:latest - Ports: 9000 (API), 9001 (Console)
- Services:
minio(ClusterIP)minio-external(NodePort 30900, 30901)
- Credentials: admin/password1234
- Bucket: mybucket (생성 필요)
# eksctl을 사용한 클러스터 생성 (cluster.yaml 참조)
eksctl create cluster -f cluster.yamlkubectl create namespace kafka
kubectl apply -f 'https://strimzi.io/install/latest?namespace=kafka' -n kafkakubectl apply -f kafka-strimzi.yaml
kubectl apply -f kafka-nodepool.yaml
kubectl apply -f topic.yaml
kubectl apply -f topic-user-activity-logs.yamlhelm repo add spark-operator https://googlecloudplatform.github.io/spark-on-k8s-operator
helm install spark-operator spark-operator/spark-operator --namespace spark-operator --create-namespacekubectl apply -f spark-serviceaccount.yaml
kubectl apply -f spark-code-configmap.yamlkubectl create namespace was
kubectl apply -f was-deployment.yaml
kubectl apply -f was-service-external.yamlkubectl create namespace logging-system
kubectl apply -f log-generator.yaml방법 1: Pod 방식 (권장)
kubectl apply -f spark-direct.yaml방법 2: SparkApplication 방식
kubectl apply -f spark-app.yamlkubectl create namespace storage
kubectl apply -f minio-deployment.yaml
# MinIO 버킷 생성 (Pod 내부에서 실행)
kubectl exec -it $(kubectl get pods -n storage -l app=minio -o jsonpath='{.items[0].metadata.name}') -n storage -- \
sh -c "mc alias set myminio http://localhost:9000 admin password1234 && mc mb myminio/mybucket --ignore-existing"# monitoring 네임스페이스 생성
kubectl create namespace monitoring
# Prometheus ConfigMap 배포
kubectl apply -f prometheus-configmap.yaml
# Prometheus 배포
kubectl apply -f prometheus-deployment.yaml
# Kafka Exporter 배포
kubectl apply -f kafka-exporter-deployment.yaml
# Grafana 배포
kubectl apply -f grafana-deployment.yamlkubectl apply -f kafka-connect.yamlkubectl get pods --all-namespaceskubectl get kafka -n kafka
kubectl get kafkatopic -n kafka
kubectl get pods -n kafkakubectl get pods -n was
kubectl get svc -n waskubectl get sparkapplication -n default
kubectl get pods -n default | grep spark- Internal:
streaming-cluster-kafka-bootstrap.kafka.svc.cluster.local:9092 - Topics:
streaming-topicuser-activity-logs(WAS와 Spark가 사용)
- Internal:
was-service.was.svc.cluster.local:80 - External:
<NodeIP>:30080
- Prometheus:
prometheus.monitoring.svc.cluster.local:9090 - Grafana:
grafana.monitoring.svc.cluster.local:3000(Internal) - Grafana External:
<NodeIP>:30300(NodePort) - Kafka Exporter:
kafka-exporter.monitoring.svc.cluster.local:9308
- REST API:
streaming-connect-cluster-connect-api.kafka.svc.cluster.local:8083
- MinIO API:
minio.storage.svc.cluster.local:9000(Internal) - MinIO API External:
<NodeIP>:30900(NodePort) - MinIO Console:
minio.storage.svc.cluster.local:9001(Internal) - MinIO Console External:
<NodeIP>:30901(NodePort)
- Replication Factor: 3 (모든 토픽)
- Min In-Sync Replicas: 2
- Listener Type: Internal (TLS 비활성화)
- Port: 9092
- Health Check Endpoint:
/main - Resource Limits: 1Gi memory, 1000m CPU
- Replica Count: 2
- Deployment Mode: Pod 방식 (spark-direct.yaml) 또는 SparkApplication 방식
- Kafka Consumer:
user-activity-logs토픽 구독 - MinIO Storage: S3A 프로토콜 사용, 버킷
mybucket - S3A Libraries: hadoop-aws, hadoop-common 포함
S3A 라이브러리 누락 오류
Spark가 MinIO에 연결할 때 S3A 라이브러리가 필요합니다. spark-direct.yaml에 다음 패키지가 포함되어 있습니다:
org.apache.hadoop:hadoop-aws:3.3.4org.apache.hadoop:hadoop-common:3.3.4
MinIO 버킷 생성 확인
Spark가 데이터를 저장하기 전에 MinIO에 mybucket 버킷이 생성되어 있어야 합니다.
모든 서비스는 다음 주소로 Kafka에 연결해야 합니다:
streaming-cluster-kafka-bootstrap.kafka.svc.cluster.local:9092
잘못된 주소 사용 시 연결이 실패할 수 있습니다.
WAS는 was 네임스페이스에 배포되며, Kafka는 kafka 네임스페이스에 배포됩니다. 네임스페이스가 올바르게 설정되었는지 확인하세요.
K8s/
├── cluster.yaml # EKS 클러스터 설정
├── kafka-strimzi.yaml # Kafka 클러스터 정의
├── kafka-nodepool.yaml # Kafka Node Pool 설정
├── kafka-connect.yaml # Kafka Connect 클러스터 정의
├── topic.yaml # Kafka Topic 정의
├── was-deployment.yaml # WAS Deployment 및 Service
├── was-service-external.yaml # WAS 외부 접근 Service
├── spark-app.yaml # Spark Application 정의
├── spark-serviceaccount.yaml # Spark ServiceAccount
├── spark-code-configmap.yaml # Spark 스트리밍 코드
├── log-generator.yaml # Log Generator Deployment
├── minio-deployment.yaml # MinIO Deployment 및 Service
├── prometheus-configmap.yaml # Prometheus 설정
├── prometheus-deployment.yaml # Prometheus Deployment 및 Service
├── grafana-deployment.yaml # Grafana Deployment 및 Service
├── kafka-exporter-deployment.yaml # Kafka Exporter Deployment 및 Service
├── topic-user-activity-logs.yaml # user-activity-logs 토픽 정의
└── zookeeper.yaml # Zookeeper 설정 (선택적)
- WAS → Kafka:
streaming-cluster-kafka-bootstrap.kafka.svc.cluster.local:9092(토픽:user-activity-logs) - Spark → Kafka:
streaming-cluster-kafka-bootstrap.kafka.svc.cluster.local:9092(토픽:user-activity-logs) - Spark → MinIO:
http://minio.storage.svc.cluster.local:9000(버킷:mybucket) - Log Generator → Kafka:
streaming-cluster-kafka-bootstrap.kafka.svc.cluster.local:9092
- WAS: NodePort 30080을 통해 클러스터 외부에서 접근 가능
- Grafana: NodePort 30300을 통해 클러스터 외부에서 접근 가능
- MinIO API: NodePort 30900을 통해 클러스터 외부에서 접근 가능
- MinIO Console: NodePort 30901을 통해 클러스터 외부에서 접근 가능
- Kafka: 3개 노드 (각 10Gi 스토리지)
- WAS: 2개 Pod (각 1Gi memory, 1000m CPU)
- Spark: Driver 1개, Executor 2개 (각 2g memory)
- Instance Type: m6i.large 이상
- Node Count: 최소 3개
- Storage: 각 노드당 50Gi 이상
- Kafka는 현재 내부 통신만 허용 (TLS 비활성화)
- WAS는 NodePort를 통해 외부 접근 가능 (프로덕션 환경에서는 Ingress 사용 권장)
- Spark ServiceAccount는 최소 권한으로 설정
# WAS 로그
kubectl logs -n was -l app=was --tail=100
# Spark Application 로그 (Pod 방식)
kubectl logs spark-streaming -n default
# Spark Application 로그 (SparkApplication 방식)
kubectl logs -n default spark-kafka-consumer-driver
# Kafka 브로커 로그
kubectl logs -n kafka streaming-cluster-broker-pool-0
# Prometheus 로그
kubectl logs -n monitoring -l app=prometheus
# Grafana 로그
kubectl logs -n monitoring -l app=grafana
# Kafka Exporter 로그
kubectl logs -n monitoring -l app=kafka-exporter# Pod 방식
kubectl get pod spark-streaming -n default
kubectl describe pod spark-streaming -n default
# SparkApplication 방식
kubectl get sparkapplication spark-kafka-consumer -n default
kubectl describe sparkapplication spark-kafka-consumer -n default# Prometheus UI 접근 (포트 포워딩)
kubectl port-forward -n monitoring svc/prometheus 9090:9090
# 브라우저에서 http://localhost:9090 접근-
Grafana UI 접근 (포트 포워딩 또는 NodePort)
kubectl port-forward -n monitoring svc/grafana 3000:3000
또는 NodePort를 통해:
<NodeIP>:30300 -
로그인 (기본: admin/admin)
-
Prometheus 데이터 소스 추가
- URL:
http://prometheus.monitoring.svc.cluster.local:9090 - 또는 외부 접근 시:
http://<NodeIP>:<Prometheus-NodePort>
- URL:
-
Kafka 메트릭 대시보드 임포트
- Grafana 대시보드 ID: 721 (Kafka Exporter 대시보드)
- 매니페스트 파일 수정
kubectl apply -f <file>명령으로 변경사항 적용- Deployment의 경우 자동으로 롤링 업데이트 수행
- SparkApplication의 경우 삭제 후 재생성 필요
- Kafka Topic 데이터는 Persistent Volume에 저장됨
- 중요한 데이터의 경우 정기적인 백업 권장
- ConfigMap 및 Secret은 별도로 백업 필요
K8s 담당자와 다른 팀원들(카프카, 로그, 스파크 팀) 간의 협업을 위한 상세 가이드는 COLLABORATION_GUIDE.md 파일을 참고하세요.
-
카프카 팀 요청
- 토픽 생성/삭제
- 브로커 개수 조절
- 파티션/리플리케이션 팩터 조절
- Kafka Connect 커넥터 추가
-
로그/WAS 팀 요청
- WAS Pod 개수 조절
- 리소스 조절 (CPU, Memory)
- 로그 확인
- 이미지 업데이트
-
스파크 팀 요청
- Spark Pod 개수 조절
- 리소스 조절
- 코드 업데이트
- 토픽 변경
-
모니터링 팀 요청
- Prometheus 설정 변경
- Grafana 대시보드 추가
- 모니터링 리소스 조절
# Pod 개수 조절
kubectl scale deployment <deployment-name> --replicas=<개수> -n <namespace>
# 리소스 사용량 확인
kubectl top pods -n <namespace>
# 로그 확인
kubectl logs <pod-name> -n <namespace> --tail=100자세한 내용은 COLLABORATION_GUIDE.md를 참고하세요.
이 프로젝트는 내부 사용을 위한 것입니다.