[K8s] Job / CronJob: 일회성 + 스케줄 작업
K8s Job, K8s CronJob, completions, parallelism, backoffLimit, TTLAfterFinished, activeDeadlineSeconds
정의
| 컨트롤러 | 의미 |
|---|---|
| Job | 완료까지 실행하는 일회성 작업 |
| CronJob | 스케줄 (cron) 에 따라 Job 생성 |
Deployment 와 다른 점: 완료를 목표로 함. pod 가 종료되어도 재시작 안 함.
Job
apiVersion: batch/v1
kind: Job
metadata: { name: migrate }
spec:
backoffLimit: 3 # 실패 시 재시도 한도
activeDeadlineSeconds: 600 # 10분 초과 시 강제 종료
ttlSecondsAfterFinished: 3600 # 완료 후 1시간 뒤 정리
template:
spec:
restartPolicy: OnFailure
containers:
- name: migrate
image: app:v2
command: ['python', 'manage.py', 'migrate']
흐름
stateDiagram-v2
[*] --> Active: Job 생성
Active --> Succeeded: completions 달성
Active --> Failed: backoffLimit 초과
Succeeded --> Cleaned: TTL 후 자동 삭제
Failed --> Cleaned: TTL 후
Job 생명주기 상세
sequenceDiagram
autonumber
participant K as K8s API
participant J as Job controller
participant P as Pod
K->>J: Job 생성
J->>P: Pod 시작
P->>P: 작업 실행
alt 성공
P-->>J: exit 0
J->>K: Succeeded
else 실패 (backoffLimit 이내)
P-->>J: exit 1
J->>P: 재시도 Pod 생성
else backoffLimit 초과
J->>K: Failed
end
병렬 실행 (parallelism / completions)
spec:
completions: 10 # 총 10개 완료 필요
parallelism: 3 # 동시 3개 실행
| 패턴 | 의미 |
|---|---|
completions=1, parallelism=1 | 단일 작업 (기본) |
completions=N, parallelism=N | N개 병렬 |
completions=N, parallelism=M < N | 동시 M, 총 N |
completions=null, parallelism=M | 무한 (작업 큐 패턴) |
activeDeadlineSeconds
spec:
activeDeadlineSeconds: 300 # 5분 초과 시 강제 종료
backoffLimit: 2
- backoffLimit = 실패 재시도 한도 (pod 수준)
- activeDeadlineSeconds = 전체 Job 의 최대 실행 시간 (시간 초과 시 Failed)
- 둘 다 지정 시 먼저 도달하는 조건 에 따라 종료
Job Suspend (1.24+)
실행 중인 Job 을 일시 정지 후 재개 가능:
# 일시 정지
kubectl patch job migrate -p '{"spec":{"suspend":true}}'
# 재개
kubectl patch job migrate -p '{"spec":{"suspend":false}}'
- 정지 시 활성 pod 는 삭제, 완료된 pod 는 유지
- CronJob 에도 적용:
spec.suspend: true로 스케줄 중단
Failure Policy (1.26+)
특정 종료 코드를 성공 또는 영구 실패 로 처리:
spec:
podFailurePolicy:
rules:
- action: FailJob # 즉시 전체 Job 실패
onExitCodes:
operator: In
values: [42] # 비즈니스 오류 코드
- action: Ignore # 무시 (재시도 카운트 안 함)
onPodConditions:
- type: DisruptionTarget # node eviction 은 재시도
작업 큐 패턴
flowchart LR
Queue[("Job Queue<br/>Redis / SQS")] --> P1[Pod 1]
Queue --> P2[Pod 2]
Queue --> P3[Pod 3]
P1 --> Output[("처리 완료")]
P2 --> Output
P3 --> Output
각 pod 가 큐에서 work 가져와 처리 후 종료. completions 없이 queue 가 빌 때까지.
Indexed Job (1.24+)
spec:
completions: 10
parallelism: 3
completionMode: Indexed
template:
spec:
containers:
- name: worker
image: app:v1
env:
- name: JOB_COMPLETION_INDEX
valueFrom:
fieldRef:
fieldPath: metadata.annotations['batch.kubernetes.io/job-completion-index']
각 pod 가 고유 인덱스 (0..N-1). 파티션된 작업 분배.
CronJob
apiVersion: batch/v1
kind: CronJob
metadata: { name: nightly-backup }
spec:
schedule: "0 2 * * *" # 매일 2시
timeZone: "Asia/Seoul" # K8s 1.27+
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
concurrencyPolicy: Forbid # 이전 job 끝나기 전 새 job 안 만듦
startingDeadlineSeconds: 300 # 5분 안에 시작 못 하면 skip
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: backup
image: db-backup:v1
concurrencyPolicy
| 정책 | 의미 |
|---|---|
Allow (기본) | 동시 실행 허용 |
Forbid | 이전 job 끝나기 전 새 job skip |
Replace | 이전 job 중단 + 새 job |
CronJob 누락 스케줄 처리
K8s 컨트롤러가 오프라인이었다가 복구 되거나 startingDeadlineSeconds 기간 내 에 놓친 스케줄이 많을 때:
startingDeadlineSeconds미설정: 마지막 스케줄 시간부터 현재까지 놓친 횟수를 계산, 100회 초과 시 CronJob 비활성화startingDeadlineSeconds: 300: 최근 5분 이내 놓친 횟수만 계산
WARNING
startingDeadlineSeconds 를 설정하지 않으면 컨트롤러 장기 다운 후 복구 시 CronJob 이 영구 비활성화 될 수 있다.
Cron 식
┌──── 분 (0-59)
│ ┌── 시 (0-23)
│ │ ┌── 일 (1-31)
│ │ │ ┌── 월 (1-12)
│ │ │ │ ┌── 요일 (0-6, 0=Sun)
│ │ │ │ │
0 2 * * * 매일 2시
*/15 * * * * 15분마다
0 9 * * 1-5 평일 9시
0 0 1 * * 매월 1일 자정
@hourly 매시 (alias)
Job vs Deployment 선택 기준
| 상황 | 선택 |
|---|---|
| DB 마이그레이션, 배치 처리 | Job |
| 스케줄 리포트, 백업 | CronJob |
| 상시 실행 API 서버 | Deployment |
| 큐 소비 + 무한 대기 | Deployment |
| 큐 소비 + 작업 완료 후 종료 | Job (parallelism) |
흔한 함정
WARNING
restartPolicy: Always= Job 의 의미 깨짐.OnFailure또는Never.ttlSecondsAfterFinished없음 = 완료된 Job 누적. cluster cluttered.- CronJob 의 시간대 = K8s 1.27+ 까지 UTC 만.
timeZone명시 권장. concurrencyPolicy: Allow+ 무거운 작업 = job 들이 겹쳐 시스템 부하.Forbid안전.- JOB 실패 알림 부재 = silent fail. Prometheus + Alertmanager 로 failed Job 알림.
- activeDeadlineSeconds 미설정 + 무한 루프 = Job 이 영구 실행, 클러스터 자원 점유.
관련 위키
- k8s-deployment
- k8s-pod
- prometheus (job 모니터링)
- kafka (작업 큐 대안)
이 글의 용어 (4개)
- [Distributed] Kafka: 분산 로그, partition, consumer groupdistributed-systems
- 정의 Apache Kafka = 분산 commit log. 고처리량 (수백만 msg/s), 영속, 수평 확장. event-driven 아키텍처 의 de facto. 핵심 개념: …
- [K8s] Deployment: ReplicaSet, rolling update, rollbackkubernetes
- 정의 Deployment = stateless 워크로드를 위한 컨트롤러. 내부적으로 ReplicaSet 관리 + rolling update / rollback. 사용 시나리오 |…
- [K8s] Pod: 컨테이너의 최소 단위, sidecar, lifecyclekubernetes
- 정의 Pod = K8s 의 가장 작은 배포 단위. 1개 이상의 컨테이너 + 공유 네트워크 + 공유 스토리지. [!IMPORTANT] Pod 는 컨테이너의 wrapping 이 아니…
- [Observability] Prometheus: pull 기반 메트릭, PromQLdevops
- 정의 Prometheus = pull 기반 시계열 metric 시스템. PromQL 로 쿼리. CNCF graduated. 2026 클라우드 네이티브 메트릭 표준. 아키텍처 Pu…
💬 댓글