Navisafe/Infrastructure

Kubernetes 환경 구성 (3) - NaviSafe 서비스 배포와 Kafka Topic 초기화

jjaehyeok 2026. 4. 20. 15:56

1. 문제 배경

  • 사전 준비 단계에서 이미지, 설정, 권한, 저장소를 분리했지만 실제 서비스는 아직 실행되지 않은 상태였다.
  • Kubernetes에서는 서비스를 단순히 실행하는 것이 아니라, 각 서비스의 역할과 성격에 맞게 리소스를 나눠서 배포해야 한다.

특히 이번 구조에서는 다음 기준이 중요했다.

  • 상태 저장 여부
  • 다른 서비스의 접근 필요 여부
  • 지속적으로 실행되어야 하는지 여부
  • 후속 처리 서비스가 의존하는 리소스가 먼저 준비되어 있는지 여부

이번 단계에서는 Kafka, Redis, MySQL와 같은 기반 서비스를 먼저 배포하고, 이후 Spark Streaming 서비스가 안정적으로 구독할 수 있도록 Kafka topic도 초기화 단계에서 함께 준비했다.


2. 목표

  • NaviSafe 주요 서비스를 Kubernetes 리소스로 분리하여 배포
  • 서비스 간 연결 구조 구성
  • Spark Streaming이 의존하는 Kafka topic 사전 생성
  • 이후 데이터 처리 흐름이 실행될 수 있는 기반 환경 준비

3. 배포 대상 서비스

이번 단계에서 배포한 주요 구성 요소는 다음과 같다.

  • Zookeeper / Kafka: 메시지 브로커 구성
  • Redis: 중간 버퍼 및 큐 관리
  • MySQL: 최종 데이터 저장
  • Kafka Topic: Spark가 구독할 입력 경로

이 구성 요소들은 이후 Spark Streaming과 Airflow가 정상적으로 동작하기 위해 먼저 준비되어 있어야 하는 기반 서비스에 해당한다.


4. 리소스 설계 기준

서비스를 배포할 때 다음 기준으로 리소스를 나눴다.

1) StatefulSet (상태 저장 서비스)

  • Kafka
  • Zookeeper
  • MySQL

이 리소스들은 데이터 유지가 필요하고, Pod의 이름이나 순서가 의미를 가지는 서비스다.
따라서 일반 Deployment보다 StatefulSet이 더 적절했다.

2) Deployment (stateless 서비스)

  • Redis

Redis는 현재 구조에서 단일 인스턴스로 운용했고, Pod가 재생성되더라도 동일한 방식으로 다시 실행되면 되는 형태였기 때문에 Deployment로 구성했다.

3) Service (네트워크 연결)

  • Kafka Service
  • Redis Service
  • MySQL Service

Pod는 재생성될 때마다 IP가 바뀔 수 있기 때문에, 다른 서비스들이 안정적으로 접근할 수 있도록 Service를 통해 고정된 접근 경로를 구성했다.

4) Job

  • Kafka topic 초기화 Job

Kafka topic은 애플리케이션 로직 안에서 매번 생성하기보다, 초기화 단계에서 먼저 준비되어 있어야 하는 기반 리소스에 가까웠다.
따라서 별도 Job으로 분리해 한 번 생성하는 방식으로 구성했다.


5. 서비스 배포

각 리소스는 YAML 기준으로 배포했다.

kubectl apply -f zookeeper.yaml  
kubectl apply -f kafka.yaml
kubectl apply -f redis-service.yaml
kubectl apply -f redis-deployment.yaml
kubectl apply -f mysql-service.yaml 
kubectl apply -f mysql-statefulset.yaml
kubectl apply -f spark-rbac.yaml

이 과정을 통해 클러스터 내부에서 기반 서비스들이 먼저 실행되도록 구성했다.

spark-rbac.yaml은 이후 Spark 작업이 Kubernetes 리소스에 접근할 수 있도록 사전에 준비한 권한 설정이다.


6. Kafka Topic 초기화

  • 이번 파이프라인에서는 outbreak_topic, emergency_alert_topic 두 개의 topic이 필요했다.
  • 초기에는 Airflow DAG에서 topic을 생성한 뒤 데이터를 적재하도록 구성했지만, Spark Streaming 서비스를 먼저 실행하는 구조에서는 topic이 없는 상태로 구독을 시도하면서 오류가 발생했다.

이후 topic은 데이터 적재 이전에 미리 준비되어 있어야 하는 기반 리소스로 보고, 별도 초기화 단계에서 먼저 생성하도록 순서를 조정했다.

  • Kafka topic 초기화
kubectl apply -f kafka-topic-init.yaml

이 방식으로 topic을 먼저 생성해두면, 이후 Spark Streaming 서비스는 topic이 존재하는 상태에서 안정적으로 구독을 시작할 수 있다.

  • kafka job 실행 후 topic 생성 확인
kubectl exec -it kafka-0 -- bash
kafka-topics.sh --bootstrap-server localhost:9092 --list

  • topic을 생성 확인 후 Spark Streaming 서비스 실행
kubectl apply -f outbreak-streaming.yaml
kubectl apply -f emergency-alert-streaming.yaml

 


7. 서비스 간 연결 구조

각 서비스는 Kubernetes Service를 통해 연결되도록 구성했다.

이 방식으로 구성하면 Pod가 재생성되더라도 연결 주소는 바뀌지 않기 때문에, 서비스 간 통신을 더 안정적으로 유지할 수 있다.

 

또한 Kafka topic도 사전에 준비해두면서, Spark가 구독할 입력 경로 역시 고정된 상태로 유지할 수 있도록 했다.


8. 실행 상태 확인

배포 이후 Pod 상태를 확인했다.

kubectl get pods
  • 정상 상태

  • Running → 정상 실행
  • Completed → 작업 완료
  • CrashLoopBackOff → 오류 발생

기반 서비스는 Running 상태를 유지해야 하고, Kafka topic 초기화 Job은 한 번 실행된 뒤 Completed 상태가 되는지를 확인했다.


9. 핵심 포인트

이번 단계에서 중요한 점은 서비스를 한 번에 올린 것이 아니라, 각 서비스의 성격에 맞게 리소스를 나눠서 배포했다는 점이다.

  • 상태 저장 서비스 → StatefulSet
  • 반복 실행 서비스 → Deployment
  • 서비스 간 연결 → Service
  • 초기화 작업 → Job

특히 Kafka topic은 단순한 부가 설정이 아니라, Spark Streaming 서비스가 정상적으로 시작되기 위해 먼저 준비되어야 하는 의존 리소스라는 점을 확인할 수 있었다.


10. 다음 단계

다음 글에서는 상시 실행 중인 Spark Streaming 서비스와 Airflow DAG가 어떤 방식으로 연결되는지, 그리고 Kafka, Redis, MySQL로 이어지는 데이터 흐름을 어떻게 검증했는지 정리할 예정이다.

 

 

Kubernetes 환경 구성 (4) - 데이터 파이프라인 동작 검증

1. 문제 배경3편까지 Kafka, Redis, MySQL, Spark Streaming을 포함한 기반 파이프라인 구성을 완료했다.각 구성 요소가 개별적으로 실행되는 상태는 확인했지만, 실제로 데이터가 흐르는지는 별도로 검증

jjaehyeok.tistory.com