Spring Batch Kubernetes 종료 처리: graceful shutdown, shutdown hook, 컨테이너 runtime hang 완전 정복

Kubernetes 환경에서 sample-batch 시스템은 Java 기반의 Spring Batch Job을 실행하고 있으며, 안정적인 종료 처리가 매우 중요합니다. 특히 다음과 같은 요구사항을 만족해야 합니다:

  • SIGTERM 수신 시 Whatap 등 모니터링 에이전트가 전송을 마무리할 시간 확보
  • 리소스가 부족하거나 컨테이너 runtime이 멈춘(hang) 상황에서도 Job이 명확히 종료될 것
  • Spring Context 내부에서 종료 시 리소스 정리를 할 수 있을 것

이를 위해 다음 설정 및 코드 전략을 활용했습니다:


✅ 핵심 설정

yaml복사편집activeDeadlineSeconds: 180
terminationGracePeriodSeconds: 10
  • 180초가 지나면 종료 신호 전송
  • 이후 10초간 graceful shutdown 기회 부여 (SIGTERM)
  • 이후 종료되지 않으면 SIGKILL 전송

✅ 코드 전략 요약

1. Shutdown Hook에서 Whatap 처리 및 Thread 정리

Runtime.getRuntime().addShutdownHook(new Thread(() -> {
// Spring Context 수동 종료
if (ctx.isActive()) ctx.close();

// 모니터링 대기 시간
Thread.sleep(10000);

// 커스텀 스레드 그룹 interrupt
for (Thread t : Thread.getAllStackTraces().keySet()) {
if (t.getThreadGroup().getName().equals("batch-thread-group")) t.interrupt();
}
}));

2. ContextClosedEventListener에서 Job 및 스케줄러 강제 정지

@Component
public class ContextClosedEventListener implements ApplicationListener<ContextClosedEvent> {
@Override
public void onApplicationEvent(ContextClosedEvent event) {
// 스케줄러 종료
scheduler.shutdown();

// 실행 중인 Job 강제 중단
jobOperator.stop(executionId);

// 스레드 interrupt
interruptBatchThreads();
}
}

🛠️ container runtime hang 이슈란?

Kubernetes가 SIGTERM을 보냈음에도 Pod이 Terminating 상태에서 수분간 멈춰있는 경우, container runtime (예: containerd)이 중단되었거나 응답을 못하는 상태일 수 있습니다.

  • 디스크 IO 병목
  • 컨테이너 상태를 알 수 없는 zombie 상태
  • containerd <-> kubelet 통신 실패

이런 경우에는 kubelet 로그 분석, 디스크/메모리/CPU 자원 확인이 필요합니다.


🧠 결론

Spring Batch를 Kubernetes 위에서 운영할 때는 단순히 activeDeadlineSeconds 설정만으로는 충분하지 않습니다.
shutdown hook, graceful shutdown을 위한 ContextClosedEvent, 그리고 container runtime hang에 대한 이해까지 함께 갖추면 안정적이고 모니터링 가능한 종료 환경을 구축할 수 있습니다.

관련 글

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다