crictl
container runtime interface controller 의 약자로 말 그대로 실행 중인 컨테이너를 제어하는 컨트롤러이다.
공식 문서: https://kubernetes.io/docs/reference/tools/map-crictl-dockercli/
k8s 에서 crictl 로 도커 명령어를 대신할 수 있다.
데몬셋
데몬셋은 모든(또는 일부) 노드가 파드의 사본을 실행하도록 한다. 노드가 클러스터에 추가되면 파드도 추가된다. 노드가 클러스터에서 제거되면 해당 파드는 가비지(garbage)로 수집된다. 데몬셋을 삭제하면 데몬셋이 생성한 파드들이 정리된다.
데몬셋은 모든 노드에 하나씩 존재한다.
데몬셋의 일부 대표적인 용도는 다음과 같다. 주로 에이전트의 역할을 한다.
- 모든 노드에서 클러스터 스토리지 데몬 실행
- 모든 노드에서 로그 수집 데몬 실행
- 모든 노드에서 노드 모니터링 데몬 실행
단순한 케이스에서는, 각 데몬 유형의 처리를 위해서 모든 노드를 커버하는 하나의 데몬셋이 사용된다. 더 복잡한 구성에서는 단일 유형의 데몬에 여러 데몬셋을 사용할 수 있지만, 각기 다른 하드웨어 유형에 따라 서로 다른 플래그, 메모리, CPU 요구가 달라진다.
myweb-ds.yml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: myweb-ds
spec:
selector:
matchExpressions:
- key: app
operator: In
values:
- myweb
- key: env
operator: Exists
template:
metadata:
labels:
app: myweb
env: dev
spec:
containers:
- name: myweb
image: ghcr.io/c1t1d0s7/go-myweb
ports:
- containerPort: 8080
protocol: TCP
kubespray 에서 node 추가 및 삭제
https://kubespray.io/#/docs/getting-started
cd ~/kubespray
노드 제거
ansible-playbook inventory/mycluster/inventory.ini remove-node.yml -b --extra-vars "node=node-2,node-3" --extra-vars reset_nodes=false
노드 추가
ansible-playbook inventory/mycluster/inventory.ini scale.yml -b
잡
잡에서 하나 이상의 파드를 생성하고 지정된 수의 파드가 성공적으로 종료될 때까지 계속해서 파드의 실행을 재시도한다. 파드가 성공적으로 완료되면, 성공적으로 완료된 잡을 추적한다. 지정된 수의 성공 완료에 도달하면, 작업(즉, 잡)이 완료된다. 잡을 삭제하면 잡이 생성한 파드가 정리된다. 작업을 일시 중지하면 작업이 다시 재개될 때까지 활성 파드가 삭제된다.
간단한 사례는 잡 오브젝트를 하나 생성해서 파드 하나를 안정적으로 실행하고 완료하는 것이다. 첫 번째 파드가 실패 또는 삭제된 경우(예로는 노드 하드웨어의 실패 또는 노드 재부팅) 잡 오브젝트는 새로운 파드를 기동시킨다.
잡을 사용하면 여러 파드를 병렬로 실행할 수도 있다.
파드 템플릿의 레이블 / 잡 컨트롤러의 레이블 셀렉터는 지정하지 않는다. → 잘못된 매핑으로 기존의 파드를 종료하지 않게 하기 위함이다.
잡 예제
다음은 잡 설정 예시이다. 예시는 파이(π)의 2000 자리까지 계산해서 출력한다. 이를 완료하는 데 약 10초가 소요된다.
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
spec:
containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
backoffLimit: 4
kubectl 을 사용해서 잡 상태를 확인한다.
kubectl describe jobs/pi
출력 결과는 다음과 같다.
Name: pi
Namespace: default
Selector: controller-uid=c9948307-e56d-4b5d-8302-ae2d7b7da67c
Labels: controller-uid=c9948307-e56d-4b5d-8302-ae2d7b7da67c
job-name=pi
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"batch/v1","kind":"Job","metadata":{"annotations":{},"name":"pi","namespace":"default"},"spec":{"backoffLimit":4,"template":...
Parallelism: 1
Completions: 1
Start Time: Mon, 02 Dec 2019 15:20:11 +0200
Completed At: Mon, 02 Dec 2019 15:21:16 +0200
Duration: 65s
Pods Statuses: 0 Running / 1 Succeeded / 0 Failed
Pod Template:
Labels: controller-uid=c9948307-e56d-4b5d-8302-ae2d7b7da67c
job-name=pi
Containers:
pi:
Image: perl
Port: <none>
Host Port: <none>
Command:
perl
-Mbignum=bpi
-wle
print bpi(2000)
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 14m job-controller Created pod: pi-5rwd7
kubectl get pods 를 사용해서 잡의 완료된 파드를 본다.
잡에 속하는 모든 파드를 기계적으로 읽을 수 있는 양식으로 나열하려면, 다음과 같은 명령을 사용할 수 있다.
pods=$(kubectl get pods --selector=job-name=pi --output=jsonpath='{.items[*].metadata.name}')
echo $pods
출력 결과는 다음과 같다.
pi-5rwd7
여기서 셀렉터는 잡의 셀렉터와 동일하다. --output=jsonpath 옵션은 반환된 목록에 있는 각 파드의 이름으로 표현식을 지정한다.
파드 중 하나를 표준 출력으로 본다.
kubectl logs $pods
출력 결과는 다음과 같다.
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275901
잡 spec 작성하기
다른 쿠버네티스의 설정과 마찬가지로 잡에는 apiVersion, kind 그리고 metadata 필드가 필요하다. 잡의 이름은 유효한 DNS 서브도메인 이름이어야 한다.
잡에는 .spec 섹션도 필요하다.
파드 템플릿
.spec.template 은 .spec 의 유일한 필수 필드이다.
.spec.template 은 파드 템플릿이다. 이것은 apiVersion 또는 kind 가 없다는 것을 제외한다면 파드와 정확하게 같은 스키마를 가지고 있다.
추가로 파드의 필수 필드 외에도 잡의 파드 템플릿은 적절한 레이블(파드 셀렉터를 본다)과 적절한 재시작 정책을 명시해야 한다.
Never 또는 OnFailure 와 같은 RestartPolicy만 허용된다.
파드 셀렉터
.spec.selector 필드는 선택 사항이다. 대부분의 케이스에서 지정해서는 안된다. 자신의 파드 셀렉터를 지정하기 섹션을 참고한다.
잡에 대한 병렬 실행
잡으로 실행하기에 적합한 작업 유형은 크게 세 가지가 있다.
- 비-병렬(Non-parallel) 잡:
- 일반적으로, 파드가 실패하지 않은 한, 하나의 파드만 시작된다.
- 파드가 성공적으로 종료하자마자 즉시 잡이 완료된다.
- 고정적(fixed)인 완료 횟수 를 가진 병렬 잡:
- .spec.completions 에 0이 아닌 양수 값을 지정한다.
- 잡은 전체 작업을 나타내며, .spec.completions 성공한 파드가 있을 때 완료된다.
- .spec.completionMode="Indexed" 를 사용할 때, 각 파드는 0에서 .spec.completions-1 범위 내의 서로 다른 인덱스를 가져온다.
- 작업 큐(queue) 가 있는 병렬 잡:
- .spec.completions 를 지정하지 않고, .spec.parallelism 를 기본으로 한다.
- 파드는 각자 또는 외부 서비스 간에 조정을 통해 각각의 작업을 결정해야 한다. 예를 들어 파드는 작업 큐에서 최대 N 개의 항목을 일괄로 가져올(fetch) 수 있다.
- 각 파드는 모든 피어들의 작업이 완료되었는지 여부를 독립적으로 판단할 수 있으며, 결과적으로 전체 잡이 완료되게 한다.
- 잡의 모든 파드가 성공적으로 종료되면, 새로운 파드는 생성되지 않는다.
- 하나 이상의 파드가 성공적으로 종료되고, 모든 파드가 종료되면 잡은 성공적으로 완료된다.
- 성공적으로 종료된 파드가 하나라도 생긴 경우, 다른 파드들은 해당 작업을 지속하지 않아야 하며 어떠한 출력도 작성하면 안 된다. 파드들은 모두 종료되는 과정에 있어야 한다.
비-병렬 잡은 .spec.completions 와 .spec.parallelism 모두를 설정하지 않은 채로 둘 수 있다. 이때 둘 다 설정하지 않은 경우 1이 기본으로 설정된다.
고정적인 완료 횟수 잡은 .spec.completions 을 필요한 완료 횟수로 설정해야 한다. .spec.parallelism 을 설정할 수 있고, 설정하지 않으면 1이 기본으로 설정된다.
작업 큐 잡은 .spec.completions 를 설정하지 않은 상태로 두고, .spec.parallelism 을 음수가 아닌 정수로 설정해야 한다.
다른 유형의 잡을 사용하는 방법에 대한 더 자세한 정보는 잡 패턴 섹션을 본다.
병렬 처리 제어하기
parallelism: 3 일 경우 3개의 파드를 병렬적으로 처리한다.
요청된 병렬 처리(.spec.parallelism)는 음수가 아닌 값으로 설정할 수 있다. 만약 지정되지 않은 경우에는 1이 기본이 된다. 만약 0으로 지정되면 병렬 처리가 증가할 때까지 사실상 일시 중지된다.
실제 병렬 처리(모든 인스턴스에서 실행되는 파드의 수)는 여러가지 이유로 요청된 병렬 처리보다 많거나 적을 수 있다.
- 고정적인 완료 횟수(fixed completion count) 잡의 경우, 병렬로 실행 중인 파드의 수는 남은 완료 수를 초과하지 않는다. .spec.parallelism 의 더 큰 값은 사실상 무시된다.
- 작업 큐 잡은 파드가 성공한 이후에 새로운 파드가 시작되지 않는다. 그러나 나머지 파드는 완료될 수 있다.
- 만약 잡 컨트롤러 가 반응할 시간이 없는 경우
- 만약 잡 컨트롤러가 어떤 이유(ResourceQuota 의 부족, 권한 부족 등)로든 파드 생성에 실패한 경우, 요청한 것보다 적은 수의 파드가 있을 수 있다.
- 잡 컨트롤러는 동일한 잡에서 과도하게 실패한 이전 파드들로 인해 새로운 파드의 생성을 조절할 수 있다.
- 파드가 정상적으로(gracefully) 종료되면, 중지하는데 시간이 소요된다.
완료 모드
completions: 3 일 경우에는 첫 번째 파드를 만들어서 실행한 후 종료하고, 두 번째 파드를 만들고 실행한 후 종료하고, 세 번 째 파드를 만들고 실행한 후 종료한다. 즉 작업의 완료 횟수가 3번 이라는 뜻이다.
completions 의 수는 parallelism 의 수 보다 많아야 한다.
완료 횟수가 고정적인 완료 횟수 즉, null이 아닌 .spec.completions 가 있는 잡은 .spec.completionMode 에 지정된 완료 모드를 가질 수 있다.
- NonIndexed (기본값): .spec.completions 가 성공적으로 완료된 파드가 있는 경우 작업이 완료된 것으로 간주된다. 즉, 각 파드 완료는 서로 상동하다(homologous). null .spec.completions 가 있는 잡은 암시적으로 NonIndexed 이다.
- Indexed: 잡의 파드는 연결된 완료 인덱스를 0에서 .spec.completions-1 까지 가져온다. 이 인덱스는 다음의 세 가지 메카니즘으로 얻을 수 있다.
- 파드 어노테이션 batch.kubernetes.io/job-completion-index.
- 파드 호스트네임 중 일부($(job-name)-$(index) 형태). 인덱스된(Indexed) 잡과 서비스를 결합하여 사용하고 있다면, 잡에 속한 파드는 DNS를 이용하여 서로를 디스커버 하기 위해 사전에 결정된 호스트네임을 사용할 수 있다.
- 컨테이너화된 태스크의 경우, JOB_COMPLETION_INDEX 환경 변수.
파드와 컨테이너 장애 처리하기
파드내 컨테이너의 프로세스가 0이 아닌 종료 코드로 종료되었거나 컨테이너 메모리 제한을 초과해서 죽는 등의 여러가지 이유로 실패할 수 있다. 만약 이런 일이 발생하고 .spec.template.spec.restartPolicy = "OnFailure" 라면 파드는 노드에 그대로 유지되지만, 컨테이너는 다시 실행된다. 따라서 프로그램은 로컬에서 재시작될 때의 케이스를 다루거나 .spec.template.spec.restartPolicy = "Never" 로 지정해야 한다. 더 자세한 정보는 파드 라이프사이클의 restartPolicy 를 본다.
파드가 노드에서 내보내지는 경우(노드 업그레이드, 재부팅, 삭제 등) 또는 파드의 컨테이너가 실패되고 .spec.template.spec.restartPolicy = "Never" 로 설정됨과 같은 여러 이유로 전체 파드가 실패할 수 있다.
파드가 실패하면 잡 컨트롤러는 새 파드를 시작한다. 이 의미는 애플리케이션이 새 파드에서 재시작될 때 이 케이스를 처리해야 한다는 점이다. 특히, 이전 실행으로 인한 임시파일, 잠금, 불완전한 출력 그리고 이와 유사한 것들을 처리해야 한다.
.spec.parallelism = 1, .spec.completions = 1 그리고 .spec.template.spec.restartPolicy = "Never" 를 지정하더라도 같은 프로그램을 두 번 시작하는 경우가 있다는 점을 참고한다.
.spec.parallelism 그리고 .spec.completions 를 모두 1보다 크게 지정한다면 한번에 여러 개의 파드가 실행될 수 있다. 따라서 파드는 동시성에 대해서도 관대(tolerant)해야 한다.
파드 백오프(backoff) 실패 정책
구성 등의 논리적 오류로 인해 약간의 재시도 이후에 잡을 실패하게 만들려는 경우가 있다.
이렇게 하려면 .spec.backoffLimit 에 잡을 실패로 간주하기 이전에 재시도할 횟수를 설정한다. 백오프 제한은 기본적으로 6으로 설정되어 있다.
잡과 관련한 실패한 파드는 최대 6분안에서 기하급수적으로 증가하는 백-오프 지연 (10초, 20초, 40초 ...) 한도가 되어 잡 컨트롤러에 의해 재생성된다. 잡의 파드가 삭제되거나 해당 시간 동안 잡에 대한 다른 파드가 실패 없이 성공했을 때 백 오프 카운트가 재설정된다.
참고: 만약 잡에 restartPolicy = "OnFailure" 가 있는 경우 잡 백오프 한계에 도달하면 잡을 실행 중인 파드가 종료된다. 이로 인해 잡 실행 파일의 디버깅이 더 어려워질 수 있다. 디버깅하거나 로깅 시스템을 사용해서 실패한 작업의 결과를 실수로 손실되지 않도록 하려면 restartPolicy = "Never" 로 설정하는 것을 권장한다.
잡의 종료와 정리
잡이 완료되면 파드가 더 이상 생성되지도 않지만, 일반적으로는 삭제되지도 않는다.
이를 유지하면 완료된 파드의 로그를 계속 보며 에러, 경고 또는 다른 기타 진단 출력을 확인할 수 있다.
잡 오브젝트는 완료된 후에도 상태를 볼 수 있도록 남아 있다. 상태를 확인한 후 이전 잡을 삭제하는 것은 사용자의 몫이다.
kubectl 로 잡을 삭제할 수 있다 (예: kubectl delete jobs/pi 또는 kubectl delete -f ./job.yaml). kubectl 을 사용해서 잡을 삭제하면 생성된 모든 파드도 함께 삭제된다.
기본적으로 파드의 실패(restartPolicy=Never) 또는 컨테이너가 오류(restartPolicy=OnFailure)로 종료되지 않는 한, 잡은 중단되지 않고 실행되고 이때 위에서 설명했던 .spec.backoffLimit 까지 연기된다. .spec.backoffLimit 에 도달하면 잡은 실패로 표기되고 실행 중인 모든 파드는 종료된다.
잡을 종료하는 또 다른 방법은 유효 데드라인을 설정하는 것이다. 잡의 .spec.activeDeadlineSeconds 필드를 초 단위로 설정하면 된다. activeDeadlineSeconds 는 생성된 파드의 수에 관계 없이 잡의 기간에 적용된다. 잡이 activeDeadlineSeconds 에 도달하면, 실행 중인 모든 파드가 종료되고 잡의 상태는 reason: DeadlineExceeded 와 함께 type: Failed 가 된다.
잡의 .spec.activeDeadlineSeconds 는 .spec.backoffLimit 보다 우선한다는 점을 참고한다. 따라서 하나 이상 실패한 파드를 재시도하는 잡은 backoffLimit 에 도달하지 않은 경우에도 activeDeadlineSeconds 에 지정된 시간 제한에 도달하면 추가 파드를 배포하지 않는다.
예시
apiVersion: batch/v1
kind: Job
metadata:
name: pi-with-timeout
spec:
backoffLimit: 5
activeDeadlineSeconds: 100
template:
spec:
containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
잡의 사양과 잡의 파드 템플릿 사양에는 모두 activeDeadlineSeconds 필드가 있다는 점을 참고한다. 이 필드를 적절한 레벨로 설정해야 한다.
restartPolicy 는 잡 자체에 적용되는 것이 아니라 파드에 적용된다는 점을 유념한다. 잡의 상태가 type: Failed 이 되면, 잡의 자동 재시작은 없다. 즉, .spec.activeDeadlineSeconds 와 .spec.backoffLimit 로 활성화된 잡의 종료 메커니즘은 영구적인 잡의 실패를 유발하며 이를 해결하기 위해 수동 개입이 필요하다.
완료된 잡을 자동으로 정리
완료된 잡은 일반적으로 시스템에서 더 이상 필요로 하지 않는다. 시스템 내에 이를 유지한다면 API 서버에 부담이 된다. 만약 크론잡과 같은 상위 레벨 컨트롤러가 잡을 직접 관리하는 경우, 지정된 용량 기반 정리 정책에 따라 크론잡이 잡을 정리할 수 있다.
완료된 잡을 위한 TTL 메커니즘
완료된 잡 (Complete 또는 Failed)을 자동으로 정리하는 또 다른 방법은 잡의 .spec.ttlSecondsAfterFinished 필드를 지정해서 완료된 리소스에 대해 TTL 컨트롤러에서 제공하는 TTL 메커니즘을 사용하는 것이다.
TTL 컨트롤러는 잡을 정리하면 잡을 계단식으로 삭제한다. 즉, 잡과 함께 파드와 같은 종속 오브젝트를 삭제한다. 잡을 삭제하면 finalizer와 같은 라이프사이클 보증이 보장되는 것을 참고한다.
예시
apiVersion: batch/v1
kind: Job
metadata:
name: pi-with-ttl
spec:
ttlSecondsAfterFinished: 100
template:
spec:
containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
pi-with-ttl 잡은 완료 후 100 초 이후에 자동으로 삭제될 수 있다.
만약 필드를 0 으로 설정하면, 잡이 완료된 직후에 자동으로 삭제되도록 할 수 있다. 만약 필드를 설정하지 않으면, 이 잡이 완료된 후에 TTL 컨트롤러에 의해 정리되지 않는다.
Cron Job
크론잡은 반복 일정에 따라 잡을 만든다.
하나의 크론잡 오브젝트는 크론탭 (크론 테이블) 파일의 한 줄과 같다. 크론잡은 잡을 크론 형식으로 쓰여진 주어진 일정에 따라 주기적으로 동작시킨다.
크론잡은 백업, 리포트 생성 등의 정기적 작업을 수행하기 위해 사용된다. 각 작업은 무기한 반복되도록 구성해야 한다(예: 1일/1주/1달마다 1회). 작업을 시작해야 하는 해당 간격 내 특정 시점을 정의할 수 있다.
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello
spec:
schedule: "* * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure
크론 스케줄 문법
# ┌───────────── 분 (0 - 59)
# │ ┌───────────── 시 (0 - 23)
# │ │ ┌───────────── 일 (1 - 31)
# │ │ │ ┌───────────── 월 (1 - 12)
# │ │ │ │ ┌───────────── 요일 (0 - 6) (일요일부터 토요일까지;
# │ │ │ │ │ 특정 시스템에서는 7도 일요일)
# │ │ │ │ │
# │ │ │ │ │
# * * * * *
예를 들면, 다음은 해당 작업이 매주 금요일 자정에 시작되어야 하고, 매월 13일 자정에도 시작되어야 한다는 뜻이다.
0 0 13 * 5
크론잡 스케줄 표현을 생성하기 위해서 crontab.guru와 같은 웹 도구를 사용할 수도 있다.
모든 크론잡에 대해 크론잡 컨트롤러는 마지막 일정부터 지금까지 얼마나 많은 일정이 누락되었는지 확인한다. 만약 100회 이상의 일정이 누락되었다면, 잡을 실행하지 않고 아래와 같은 에러 로그를 남긴다.
Cannot determine if job needs to be started. Too many missed start time (> 100). Set or decrease .spec.startingDeadlineSeconds or check clock skew.
중요한 것은 만약 startingDeadlineSeconds 필드가 설정이 되면(nil 이 아닌 값으로), 컨트롤러는 마지막 일정부터 지금까지 대신 startingDeadlineSeconds 값에서 몇 개의 잡이 누락되었는지 카운팅한다. 예를 들면, startingDeadlineSeconds 가 200 이면, 컨트롤러는 최근 200초 내 몇 개의 잡이 누락되었는지 카운팅한다.
크론잡은 정해진 일정에 잡 실행을 실패하면 놓쳤다고 카운팅된다. 예를 들면, concurrencyPolicy 가 Forbid 로 설정되었고, 크론잡이 이전 일정이 스케줄되어 여전히 시도하고 있을 때, 그 때 누락되었다고 판단한다.
즉, 크론잡이 08:30:00 에 시작하여 매 분마다 새로운 잡을 실행하도록 설정이 되었고, startingDeadlineSeconds 값이 설정되어 있지 않는다고 가정해보자. 만약 크론잡 컨트롤러가 08:29:00 부터 10:21:00 까지 고장이 나면, 일정을 놓친 작업 수가 100개를 초과하여 잡이 실행되지 않을 것이다.
이 개념을 더 자세히 설명하자면, 크론잡이 08:30:00 부터 매 분 실행되는 일정으로 설정되고, startingDeadlineSeconds 이 200이라고 가정한다. 크론잡 컨트롤러가 전의 예시와 같이 고장났다고 하면 (08:29:00 부터 10:21:00 까지), 잡은 10:22:00 부터 시작될 것이다. 이 경우, 컨트롤러가 마지막 일정부터 지금까지가 아니라, 최근 200초 안에 얼마나 놓쳤는지 체크하기 때문이다. (여기서는 3번 놓쳤다고 체크함)
크론잡은 오직 그 일정에 맞는 잡 생성에 책임이 있고, 잡은 그 잡이 대표하는 파드 관리에 책임이 있다.