3.8 Job
一个Job创建1个或多个Pod,并确保特定数量的Pod被成功终止,当pods成功完成时,Job将跟踪成功完成的操作。当达到指定数量的成功完成时,任务(即Job)就完成了,删除Job时会清理它创建的Pod。一个简单的例子是创建一个Job对象,以便可靠地运行一个pod完成。如果第一个Pod失败或删除了,Job对象将会开始一个新的Pod。还可以使用一个Job并行运行多个Pod。
【Job的规约Spec】
和其他的差不多,Job对象需要apiVersion
、kind
和metadata
字段,同样需要.spec
:
- Pod Template:
.spec.template
是.spec
必要的字段,是创建Pod的模板,和pod中的模式一样,除了它是嵌套的没有apiVersion
或kind
,此外还需要Pod的字段,Job中的pod template必须指定合适的标签和重启策略,RestartPolicy
只能设置为Never
或OnFailure
; - Pod Selector:
.spec.selector
是可选参数,一般不需要指定; - Parallel Jobs:主要有3种类型的task合适作为Job运行:
- 非并行Job(Non-parallel):正常只有一个Pod启动(除非Pod失败),一旦pod成功终止,Job就完成了;
- 固定计数的并行Job:为
.spec.completions
指定一个非0整数,一个Job代表多个task,在1到.spec.completions
范围内的每个值都有一个成功的pod时完成; - 具有work queue的并行Job:不需要指定
.spec.completions
(默认为.spec.parallelism
),Pod之间自我协调或通过额外的Service决定在哪个Pod上运行,一个pod可以从work queue中获取一批最多n个元素。每个Pod能够独立决定是否完成了对等的任务,因此整个Job完成。当Job中的任意一个Pod完成task成功结束,将不会再创建新的Pod,当最后一个Pod结束时,就意味着所有的Pod都停止了,这时Job完成。
注:
- 对于
non-parallel
Job,可以不设置.spec.completions
和.spec.parallelism
参数(此时它们的默认值为1); - 对于
fixed completion count
Job,需要设置对应的.spec.completions
,此外也可以设置.spec.parallelism
(不设置默认为1); - 对于
work queue
Job,.spec.completions
参数不能设置,.spec.parallelism
对应设置为非负整数; .spec.parallelism
表示并行度(默认为1),当指定为0时,Job将停止直到这个数值增加,但实际的并行度可能会和请求的不一样。在固定计数的并行Job中,实际并行的Pod数量不会超过剩余数量,.spec.parallelism
将会被忽略;在work queue的并行Job中在Job完成后将不会在启动新的Pod,但允许剩余Pod执行完成;此外如果Controller创建Pod失败可能会导实际的Pod比请求的少。
【Pod和Container失败】
如果Pod失败了且.spec.template.spec.restartPolicy = "OnFailure"
,Pod将会残留在节点上,但container是会重新运行的,因此当本地重启可能需要解决这样的问题或者指定.spec.template.spec.restartPolicy = "Never"
。对于失败的策略,比如由于配置文件错误的原因在重试过指定次数后直接让整个Job失败,back-off限制值.spec.backoffLimit
默认为6,和Job相关的失败Pod会由Job Controller进行back-off(每次back-off的时间间隔会逐渐增大10s、20s、40s,封顶6min)。
【Job的停止和清理】
当Job完成后,就不会再创建Pod了,但之前创建的Pod也没有被删除,保留这些Pod可以让我们看到Pod的日志以便检查错误。同样的道理,完成任务的Job对象也不会删除。当然如确定不要了,可以用kubectl
命令删除Job对象(该Job创建的对应的Pod也会被删除):kubectl delete jobs/pi
或kubectl delete -f ./job.yaml
。
默认一个Job将会一直运行除非Pod失败且遵从.spec.backoffLimit
的限制,可以通过设置deadline来终止Job对象:.spec.activeDeadlineSeconds
设置为多少秒,一旦设置了这个参数,所有的Pod将会终止且Job的状态将会就变成type: Failed
原因为reason: DeadlineExceeded
,.spec.activeDeadlineSeconds
的优先级高于.spec.backoffLimit
,因此Job重试过一个或多个失败的Pod达到限制的时间(activeDeadlineSeconds
)后将不会部署额外的Pod,即使此时backoffLimit
还没达到。下面是一个示例:
apiVersion: batch/v1
kind: Job
metadata:
name: pi-with-timeout
spec:
# 指定失败时可以重试5次
backoffLimit: 5
# 指定存活时长
activeDeadlineSeconds: 100
template:
spec:
containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
【自动清理已完成的Job】
通常已完成的Job对象需要进行清理,否则会对API Server造成压力,如果Job是由更高级别的controller管理(比如CronJobs),那Job将会基于指定的容量清理策略被CronJobs清理
3.9 CronJob
Cron Job是基于时间进行调度的,CronJob对象就像一行crontab文件,它会在给定的时间定期(以cron格式编写)地运行一个Job。一个Cron Job创建Job对象基于它的调度执行时间,当然也有可能0个或2个Job会被创建,这些目前都不是确定的,因此Job之间应该保证幂等性,startingDeadlineSeconds
设置为大一点的值或者不设置让其默认且concurrencyPolicy
设置为Allow
,Job应该至少运行一次。对于CronJob,CronJob Controller将会检查从上一次调度到现在将会错过多少调度,如果错过超过了100个,那它将不会再启动Job并记录错误: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
,Controller从startingDeadlineSeconds
开始计算直到现在(即之前的时间内,并不是上次调度到现在)。比如,如果startingDeadlineSeconds
设置为200
,控制器将会计算在刚刚过去的200s中错失了多少Job。
CronJob是从它在调度时间内创建失败进行计算的,比如,concurrencyPolicy
设置为Forbid
,CronJob将会尝试调度,如果之前的调度仍在运行,那么它将被视为错过。