본문으로 건너뛰기
김신건의 로그

[K8s] Job / CronJob: 일회성 + 스케줄 작업

· 수정 · 📖 약 1분 · 468자/단어 #kubernetes #job #cronjob #batch #k8s
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=NN개 병렬
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

  1. restartPolicy: Always = Job 의 의미 깨짐. OnFailure 또는 Never.
  2. ttlSecondsAfterFinished 없음 = 완료된 Job 누적. cluster cluttered.
  3. CronJob 의 시간대 = K8s 1.27+ 까지 UTC 만. timeZone 명시 권장.
  4. concurrencyPolicy: Allow + 무거운 작업 = job 들이 겹쳐 시스템 부하. Forbid 안전.
  5. JOB 실패 알림 부재 = silent fail. Prometheus + Alertmanager 로 failed Job 알림.
  6. activeDeadlineSeconds 미설정 + 무한 루프 = Job 이 영구 실행, 클러스터 자원 점유.

관련 위키

이 글의 용어 (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…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기