Cronjob
개요
A CronJob starts one-time Jobs on a repeating schedule.[1]
크론잡은 잡을 반복된 일정에 맞춰 실행한다.
주기적인 백업, 리포팅 등에 사용된다.
유닉스의 crontab과 비슷하게 만들어진 오브젝트로, crontab에서 쓰는 양식처럼 사용할 수 있다.
기능
별 거 없이, 그냥 잡을 일정 주기에 맞춰 생성해주는 일을 한다.
근데 이후 보겠지만 여러 개의 동시 잡을 생성한다던가 하는 몇 가지 고려할 만한 특이점들이 있긴 하다.
크론 작성법
일단 크론을 작성하는 방법을 먼저 알아야 할 것이다. 이런 건 그냥 지피티한테 맡기는 게 낫다
기본적으로 크론은 * * * * *
라는 식으로 5개의 숫자를 기입한다.
# ┌───────────── 분 (0 - 59)
# │ ┌───────────── 시 (0 - 23)
# │ │ ┌───────────── 일 (1 - 31)
# │ │ │ ┌───────────── 월 (1 - 12)
# │ │ │ │ ┌───────────── 요일 (0 - 6) (일, 월, 화, 수, 목, 금, 토)
# │ │ │ │ │
# │ │ │ │ │
# │ │ │ │ │
# * * * * *
각 위치는 이러한 단위를 가지며, 해당 자리에 숫자를 보통 쓰지만 *
를 쓴다면 모든 값을 이야기한다.
0 3 * * 1
이면 매주 월요일 3시 0분마다 주기가 돌아온다는 것이다.
가령 * * 3 1 2
를 설정한다면 1월 3일이 화요일이 아니면 어떻게 되는건가?
일과 요일이 같이 설정되는 경우에는 두 조건을 OR 로 평가하여 1월 3일과, 1월달의 모든 화요일에 주기가 돌아온다고 한다.
여기에 Vixie cron이라 하여 /숫자
같은 식으로 단계를 적용하는 것이 가능하다.
0-23/2
라고 하면 0부터 23까지, 2개씩 건너뛰는 주기를 가진다는 뜻이다.
그러니 0,2,4,...22까지의 값이 되는 것이다.
월 자리에 */2
라고 하면 모든 짝수 월을 의미하게 된다.
추가적으로 표준화된 구문도 존재한다.
@yearly(@annually) - 매년 1월 자정
@monthly - 매달 1일 자정
@weekly - 매주 일요일 자정
@daily(@midnight) - 매일 자정
@hourly - 매 정각
잘 모르겠다면, 이런 사이트의 도움을 빌리는 것도 좋은 방법이다.[2]
양식 작성법
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello
spec:
schedule: "* * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox:1.28
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure
참고로 자동으로 붙여지는 이름에 11자가 쓰이기 때문에 최대 길이 63자인 이름 중에서 관리자가 직접 매길 수 있는 길이는 53자이다.
이렇게 길게 이름 붙일 일은 없길 바란다.
위에서 본 크론은 schedule
필드에 작성하면 된다.
크론잡의 잡의 파드의(..) 스펙은 spec이란 필드로만 3번이나 들여써서 작성해야 한다!
잡 스펙을 일단 잘 작성하고, 아래 추가적인 필드를 보자.
startingDeadlineSeconds
클러스터에 자원이 부족하다던가, 하는 모종의 이유로 제 시간에 맞춰 잡이 실행되지 못할 수 있다.
이틀마다 백업을 시키려했는데 한번은 너무 늦어져서 하루가 이미 넘어가버렸다면, 그제서라도 백업하는 건 큰 의미가 없다.
그래서 이 필드로 잡이 시작하기 위한 마감기한을 지정한다.
이 필드가 100초로 걸려 있다면, 예정 일정 100초까지 잡이 시작되지 않으면 해당 주기는 건너뛰게 된다.
크론잡 컨트롤러는 예정 일정이 되면 현재 시간과 잡이 만들어질 것으로 예상되는 시간을 측정한다.
물론 해당 회차의 잡은 실패로 반영된다.
크론잡 컨트롤러는 10초마다 모든 사항을 체크하기 때문에 이 값은 10초 미만으로 설정하지 않는 것이 좋다.
여차하면 생성될 수 있었던 놈도 생성 못 되는 수가 있다.
이 필드를 정하는 게 꽤나 중요한 게, 아래의 필드들에도 영향이 가기 때문이다.
만약 예정된 잡이 5개 정도 밀렸다가 리소스가 확보돼버리면.. 이 잡들이 우루루 실행될 수도 있다.
그래도 이런 상황의 최악을 피하고자, 크론잡 컨트롤러는 100개 이상의 밀린 스케줄이 있으면 에러를 기록하며 잡 생성을 하지 않는다.
만약 이 필드가 설정됐다면 컨트롤러는 밀린 스케줄 개수를 체킹할 때 현재 시간에서부터 밀린 잡들의 개수를 체크한다(원래는 마지막으로 생성된 놈부터 전부).
문서의 좋은 예시가 있는 것 같아서 가져온다.
매분 실행되는 크론잡이 있다.
근데 이놈의 컨트롤러가 대충 200분 뻑나갔다 다시 실행됐다.
이때 이 필드가 설정이 안 됐다면? 컨트롤러는 100개 이상 밀렸다 판단하고 아예 작동을 안 한다.
그러나 이 필드가 200초 정도로 잡혀있다면 대충 3개의 잡만이 밀렸다 판단하고 작동은 계속 하게 된다.
concurrencyPolicy
잡들이 실행되다보면 오래 걸릴 수도 있고, 크론잡 주기가 짧아서라던가 이전과 이후 잡이 동시에 존재하게 되는 경우가 나올 수 있다.
이 필드로 잡들이 동시에 실행되고 있어도 되는지 지정할 수 있다.
- Allow
- 기본값으로, 잡들이 동시에 존재하고 있어도 상관없다.
- Forbid
- 동시 존재를 금지하여, 이전 잡이 아직 실행 중이면 이후 잡은 건너뛴다.
- 그래도 이전 잡이 끝난 이후, 위의
.spec.startingDeadlineSeconds
를 고려해서 이후 잡이 생성될 수는 있긴 하다.
- Replace
- 이전 잡을 종료시키고 이후 잡을 실행시킨다.
- 그럼 이전 잡은 실패로 표시되나?
- 이전 잡을 종료시키고 이후 잡을 실행시킨다.
suspend
크론잡의 실행을 잠시 중단하고 싶다면 이 필드를 true로 걸면 된다.
이미 생성돼 실행 중인 잡은 계속 실행되긴 할 것이다.
.spec.startingDeadlineSeconds
이 안 걸려 있다면, suspend를 풀자마자 새로운 잡이 생성되어버릴 것이다.
잡 히스토리 제한
.spec.successfulJobHistoryLimit
, .spec.failedJobHistoryLimit
이 있다.
크론잡에 의해 실행된 잡들은 기본적으로는 남아 있게 되는데, 이 제한에 맞춰 남아있다.
기본값은 각각 3, 1이다.
timeZone
타임존이 명시되지 않았다면 kube-controller-manager가 측정하는 로컬 시간을 사용한다.
하지만 .spec.timeZone: "Etc/UTC"
과 같이 유효한 타임존 문자열[3]을 이 필드에 쓰면 해당 시간을 기준으로 실행하게 된다.
만약 클러스터에서 외부 시간 데이터베이스에 접근할 수 없다면 Go 언어 라이브러리에 바이너리로 적힌 데이터베이스를 활용하게 된다.
한계
과거에 어떤 사람들이 .spec.schedule
필드에 타임존 관련 변수를 적는 일이 있었나 본데, 이것은 공식적으로 지원되지 않는다.
만약 그렇게 사용한다면 유효성 검사 에러가 날 것이다.
양식 업데이트
크론잡은 양식에 적힌 것으로 새로운 잡을 계속 만든다.
만약 이 양식을 수정한다면 이미 실행되고 있는 놈은 어쩔 수 없고 다음 잡부터 적용이 될 것이다.
잡 생성
크론잡은 잡을 생성하는 주기가 있다.
위에서 말한 것처럼 시작 시간 제한이 없어서 여러 잡이 밀렸을 때 여차하면 잡이 동시에 여러 개 생기는 불상사도 날 수 있다는 말이다.
이런 상황에 대해 쿠버네티스는 막지 않기 때문에 관리자가 처음부터 잡을 멱등하게 만들어야만 한다.
Kubernetes v1.32 - Penelope부터는 크론잡은 자신이 만든 잡에 batch.kubernetes.io/cronjob-scheduled-timestamp
어노테이션을 붙인다.
이를 통해 원래 이 잡이 크론잡에 의해 생성된 시간을 알 수 있다.
관련 문서
이름 | noteType | created |
---|