← 아티클 목록

쿠버네티스 CronJob 실패 디버깅 — Job 안 도는 진짜 원인

2027-04-05#kubernetes#cronjob#트러블슈팅

kubectl get cronjob을 쳤더니 LAST SCHEDULE<none>이거나, kubectl get jobsCOMPLETIONS 0/1인 Job이 쌓여 있다면, 스케줄은 정의됐는데 컨테이너가 제대로 끝나지 못하고 있다는 뜻입니다. CronJob은 Job을 만들고, Job은 Pod를 만듭니다. 그래서 실패의 진짜 원인은 항상 맨 아래 Pod에 있습니다. 위에서부터 한 단계씩 내려가며 좁힙니다.

1단계 — 어느 계층에서 막혔는지 본다

Kubernetes
# CronJob이 Job을 만들고 있나
kubectl get cronjob my-job

# 그 CronJob이 만든 Job들
kubectl get jobs --selector=job-name

# Job 상세 — 백오프·실패 횟수
kubectl describe job <job-name>

# 실제로 죽은 Pod 로그
kubectl logs job/<job-name>

LAST SCHEDULE이 갱신되는데 Job이 실패하면 앱 문제, LAST SCHEDULE이 아예 안 갱신되면 스케줄·권한 문제입니다.

2단계 — 증상별 원인

증상흔한 원인확인
LAST SCHEDULE: <none>스케줄 표현식 오류·suspend: truekubectl get cronjob -o yaml
Job은 생기는데 0/1컨테이너 Exit 1·이미지 못 받음kubectl logs job/...
BackoffLimitExceeded재시도 한도 초과 후 포기describe job의 이벤트
Job이 안 끝나고 멈춤activeDeadlineSeconds 없음·무한 대기Pod 상태·로그

원인 6가지와 해결

① 스케줄 표현식 오류schedule은 표준 5필드 cron입니다. "*/5 * * * *"처럼 따옴표로 감싸지 않으면 YAML이 잘못 파싱합니다. 분 단위가 최소 단위라 초 단위 실행은 불가능합니다.

② 일시정지(suspend)spec.suspend: true면 스케줄이 와도 Job을 안 만듭니다. 운영 중 꺼두고 잊는 경우가 많습니다. kubectl patch cronjob my-job -p '{"spec":{"suspend":false}}'로 풉니다.

③ 컨테이너가 비정상 종료 — 앱이 Exit 1로 죽으면 Job은 backoffLimit(기본 6)만큼 재시도 후 BackoffLimitExceeded로 실패합니다. kubectl logs job/<name>의 스택트레이스가 1차 단서입니다.

④ 이미지·시크릿 누락ImagePullBackOff면 태그 오타나 imagePullSecrets 누락입니다. describe pod의 이벤트에 사유가 찍힙니다.

⑤ 동시 실행 충돌concurrencyPolicy가 기본 Allow라 이전 Job이 안 끝났는데 다음 스케줄이 겹쳐 중복 실행됩니다. 배치 작업은 Forbid로 막습니다.

⑥ 무한 대기 — 외부 API 응답을 기다리며 Pod가 안 끝나는 경우. activeDeadlineSeconds로 상한을 줘서 강제 종료시킵니다.

체크리스트

Kubernetes
kubectl get cronjob my-job          # suspend·LAST SCHEDULE
kubectl get jobs                    # COMPLETIONS·실패 Job
kubectl describe job <job-name>     # backoff·이벤트
kubectl logs job/<job-name>         # 죽은 컨테이너 로그

이 4개면 스케줄 계층인지 앱 계층인지 바로 갈립니다.


CronJob을 직접 만들어 일부러 실패시키고 백오프·동시성을 관찰하는 실습은 쿠버네티스 트랙에서 해볼 수 있습니다 — 회원가입 없이 무료로.