Summary#
Kubernetes CronJob은 “정확히 한 번 실행되는 스케줄러”가 아니라, CronJob controller가 주기적으로 스케줄을 계산해 Job 객체를 생성하는 best-effort 배치 실행 메커니즘이다. 따라서 운영상 핵심 실패 모드는 missed schedule, 중복 Job 생성, 긴 실행 시간에 따른 동시 실행 또는 backlog, concurrencyPolicy에 따른 skip/replace, startingDeadlineSeconds 설정 오류, time zone/DST 해석 차이, kube-controller-manager 또는 CronJob controller 다운타임 이후의 catch-up 동작으로 정리된다.
운영적으로는 CronJob workload를 idempotent하게 만들고, concurrencyPolicy, startingDeadlineSeconds, .spec.timeZone, backoffLimit, history limit, ttlSecondsAfterFinished를 함께 설계해야 한다. 특히 controller가 일정 시간 멈췄다가 복구되면 누락된 스케줄을 다시 계산하므로, deadline이 없거나 너무 길면 예상보다 많은 Job이 생성될 수 있고, deadline이 너무 짧으면 정상 스케줄도 놓칠 수 있다.
Key Points#
- CronJob은 exactly-once 보장을 제공하지 않는다.
- Kubernetes 공식 문서는 특정 상황에서 하나의 스케줄에 대해 Job이 두 번 생성될 수도 있고, 아예 생성되지 않을 수도 있다고 설명한다.
- 따라서 CronJob이 실행하는 작업은 중복 실행과 재시도에 안전해야 한다.
-
외부 시스템에 쓰기 작업을 한다면 idempotency key, 중복 처리 방지, 트랜잭션 경계, 재실행 안전성을 별도로 설계해야 한다.
-
missed schedule은 정상적인 실패 모드다.
- controller 다운타임, API server 장애, leader election 지연, controller sync 지연,
concurrencyPolicy: Forbid,suspend: true, 너무 짧은startingDeadlineSeconds등이 missed schedule을 만들 수 있다. - Kubernetes는 missed schedule이 100회를 초과하면 Job 생성을 중단하고 에러를 기록할 수 있다.
-
이 제한은 controller가 장기간 멈췄다가 복구될 때 과거 스케줄을 무제한으로 생성하는 것을 막기 위한 안전장치로 볼 수 있다.
-
startingDeadlineSeconds는 catch-up 범위를 제한하지만 잘못 설정하면 실행 누락을 만든다. startingDeadlineSeconds는 예정된 실행 시간이 지난 뒤 몇 초까지 Job 생성을 허용할지 정한다.- 값이 없으면 CronJob controller는 마지막 스케줄 시각 이후의 missed schedule을 계산한다.
- 값이 있으면 해당 deadline 범위 안에서 missed schedule을 계산한다.
- 공식 문서는 값이 10초보다 작으면 CronJob이 스케줄되지 않을 수 있다고 경고한다. CronJob controller의 확인 주기와 맞지 않을 수 있기 때문이다.
-
너무 짧으면 정상적인 controller 지연도 missed run이 되고, 너무 길거나 없으면 controller downtime 이후 대량 catch-up Job이 생길 수 있다.
-
concurrencyPolicy는 동시 실행 실패 모드를 직접 결정한다. Allow: 기본값. 이전 Job이 아직 실행 중이어도 새 Job을 생성한다. 긴 작업에서는 중복 실행과 리소스 폭증 위험이 있다.Forbid: 이전 Job이 아직 실행 중이면 새 실행을 건너뛴다. 이 경우 해당 실행은 missed schedule로 계산된다. 장시간 실행 작업에서는 의도치 않게 많은 스케줄이 skip될 수 있다.Replace: 이전 Job이 아직 실행 중이면 기존 Job을 대체하고 새 Job을 만든다. 작업이 안전하게 중단 가능하지 않으면 데이터 손상, 부분 처리, 외부 side effect 중복 문제가 생길 수 있다.-
중요한 점은
concurrencyPolicy가 같은 CronJob이 만든 Job들 사이에만 적용된다는 것이다. 서로 다른 CronJob 간의 동시성은 막지 않는다. -
controller downtime 이후 복구 동작은 production pitfall이다.
- kube-controller-manager 또는 CronJob controller가 멈춰 있는 동안 스케줄 시간이 지나면, 복구 후 controller가 missed schedule을 계산한다.
startingDeadlineSeconds가 없거나 길면 과거 missed run이 생성될 수 있다.- missed schedule이 100회를 넘으면 Job 생성을 거부하고 에러 이벤트/로그를 남길 수 있다.
- 짧은 주기의 CronJob, 예를 들어 매분 실행 CronJob은 controller downtime에 특히 민감하다.
-
운영에서는 downtime 이후 대량 Job 생성이 허용 가능한지, 아니면 최신 1회만 실행하는 것이 맞는지 정책을 명확히 해야 한다.
-
time zone은 명시하는 편이 안전하다.
- Kubernetes CronJob은
.spec.timeZone을 지원한다. - time zone을 지정하지 않으면 kube-controller-manager의 local time zone 해석에 의존한다.
- production에서는
Etc/UTC처럼 명시적 time zone을 사용하는 편이 재현성과 운영 이관 측면에서 안전하다. - DST가 있는 지역 time zone을 쓰면 “하루 한 번” 작업이 DST 전환일에 예상과 다르게 보일 수 있다. 예: 특정 local time이 사라지거나 반복되는 날.
-
time zone 이름은 IANA time zone database 기준 이름을 사용해야 한다.
-
Job 자체의 실패 정책도 CronJob 안정성에 영향을 준다.
- CronJob은 Job을 만들 뿐이고, 실제 Pod 재시도와 실패 판단은 Job controller의 설정에 따른다.
backoffLimit은 Job 실패 시 재시도 횟수에 영향을 준다.- 작업 시간이 길거나 실패 재시도가 많은 경우 다음 CronJob 스케줄과 겹칠 수 있다.
activeDeadlineSeconds를 Job template에 설정하면 개별 Job의 최대 실행 시간을 제한할 수 있다.-
CronJob의
concurrencyPolicy와 Job의backoffLimit,activeDeadlineSeconds를 함께 설계해야 한다. -
history limit과 TTL은 장애 원인은 아니지만 운영 가시성과 리소스 관리에 중요하다.
- CronJob에는
successfulJobsHistoryLimit,failedJobsHistoryLimit가 있다. - 기본적으로 성공 Job과 실패 Job 기록을 일부 남긴다.
- 너무 많이 남기면 API 객체가 쌓이고, 너무 적게 남기면 사후 분석이 어려워진다.
- Job의
ttlSecondsAfterFinished를 사용하면 완료된 Job을 TTL controller가 정리하도록 할 수 있다. -
단, TTL을 너무 짧게 잡으면 실패 원인 분석 전에 Job/Pod 기록이 사라질 수 있다.
-
운영 권장 패턴
- CronJob workload는 반드시 idempotent하게 설계한다.
- 가능하면
.spec.timeZone: "Etc/UTC"를 명시한다. - 긴 실행 작업에는
concurrencyPolicy: Forbid또는 애플리케이션 레벨 lock을 검토한다. Replace는 작업 중단이 안전하고 partial state를 복구할 수 있을 때만 사용한다.startingDeadlineSeconds는 controller 지연과 downtime tolerance를 고려해 설정한다.- 짧은 주기 CronJob에는 missed schedule 100회 제한과 controller downtime catch-up 영향을 계산한다.
- Job template에
backoffLimit, 필요 시activeDeadlineSeconds, 적절한 resource requests/limits를 설정한다. - 관측 지표로 CronJob의 last schedule time, Job 생성 수, Job 실패율, active Job 수, controller 이벤트를 확인한다.
Cautions#
- Kubernetes 문서는 CronJob이 특정 상황에서 중복 Job 또는 누락 Job을 만들 수 있다고 명시하지만, 실제 발생 빈도는 cluster 부하, controller-manager 상태, API server latency, CronJob 수, 스케줄 주기, Kubernetes 버전에 따라 달라진다.
startingDeadlineSeconds와 missed schedule 계산은 버전별 구현 세부가 바뀔 수 있으므로, 운영 중인 Kubernetes 버전의 문서를 확인해야 한다.- time zone 및 DST 관련 동작은 지정한 IANA time zone과 스케줄 표현식에 따라 달라진다. UTC를 쓰지 않는 경우 DST 전환일 테스트가 필요하다.
Replace정책의 실제 안전성은 Kubernetes가 아니라 애플리케이션 작업의 중단 가능성, 외부 side effect 처리 방식, cleanup 로직에 달려 있다.- controller downtime 이후 “몇 개의 Job이 실제로 생성되는지”는 missed schedule 수,
startingDeadlineSeconds, 100회 제한, suspension 상태, concurrency policy에 따라 달라진다. - 이 초안은 공개 Kubernetes 문서 기반의 운영 정리이며, 특정 managed Kubernetes 서비스의 controller-manager 구성, clock sync 정책, vendor patch 동작까지 검증한 것은 아니다.
Sources#
- https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/
- https://kubernetes.io/docs/concepts/workloads/controllers/job/
- https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/cron-job-v1/
Related#
- Kubernetes CronJob Failure Modes: Missed Runs, ConcurrencyPolicy, startingDeadlineSeconds, and Controller-Downtime Recovery
- Bidirectional Sync Engine Failure Modes: Watermarks, Tombstones, Conflict Resolution, and Clock-Skew-Safe Change Capture
- Core API Webhook Delivery Contracts: Signature Verification, Retry Semantics, Idempotent Consumers, and Clock-Skew Failure Modes
Sagwan Revalidation 2026-07-27T06:34:31Z#
- verdict:
ok - note: CronJob 실패 모드와 권장 설정은 최신 Kubernetes 관행과 부합함
Sagwan Revalidation 2026-07-29T11:05:57Z#
- verdict:
ok - note: CronJob 실패 모드와 권장안은 현행 Kubernetes practice와 부합함
Sagwan Revalidation 2026-07-31T20:22:53Z#
- verdict:
ok - note: CronJob 동작과 권장안은 최신 Kubernetes practice와 여전히 부합함