Job负责批处理任务,即只执行一次的任务,它保证批处理任务的一个或多个Pod
说明:
- spce.template格式同Pod
- RestartPolicy仅支持Never或OnFailur
- 单个Pod时,默认Pod成功运行后Job即结束
- spec.completions标志Job结束需要成功运行的Pod个数,默认为1
- spec.activeDeadlineSeconds标志失败Pod的重试最大时间,超过这个时间不会继续重试
Job
准备
通过计算π来演示job
计算2000位的pi,然后发送给指定web服务器
main.sh
pi=$(echo "scale=2000; 4*a (1)" | bc -l)
pi=$(echo $pi| sed 's/\\ //g')
curl http://192.168.0.221:5000/pi?pi=$pi
创建包含bc命令与curl命令。以及main.sh脚本的镜像并推送到自有仓库
dockerfile
FROM ubuntu:22.04
RUN apt update && apt install -y curl bc
WORKDIR /tmp
COPY main.sh /tmp/main.sh
ENTRYPOINT ["/bin/sh", "/tmp/main.sh"]
构建并推送到自有仓库
docker build -t harbor.tangotz.com/os/ubutnu-pi:0.1 .
docker push harbor.tangotz.com/os/ubutnu-pi:0.1
构建job资源文件
j.yml
apiVersion: batch/v1
kind: Job
metadata:
name: gen-pi
spec:
template:
metadata:
name: pi
spec:
containers:
- name: pi-pod
image: harbor.tangotz.com/os/ubutnu-pi:0.2
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "curl 192.168.0.221:5000/start"]
preStop:
exec:
command: ["/bin/sh", "-c", "curl 192.168.0.221:5000/stop"]
restartPolicy: Never
这里添加了lifecycle。在Job资源中,会有非预期结果。为了验证lifecycle,这里用一个简单的flask应用来处理http请求
app.py
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/pi', methods=['GET'])
def pi_endpoint():
pi = request.args.get('pi', None)
# 返回响应]
print(pi)
return 'pi OK'
@app.route('/start', methods=['GET'])
def start_endpoint():
name = request.args.get('name', None)
# 返回响应]
print(name)
return 'start OK'
@app.route('/stop', methods=['GET'])
def stop_endpoint():
name = request.args.get('name', None)
# 返回响应]
print(name)
return 'stop OK'
if __name__ == '__main__':
app.run("0.0.0.0", debug=True)
验证
运行flask应用
python3 app.py
创建Job
kubectl apply -f j.yml
此时观察app.py输出结果,可以看到定义的postStart钩子可以正常运行,稍后pi数值也会输出,但是没有preStop钩子的运行结果。
预期外
Job 控制器的主要目的是成功完成指定的任务(即Pod中的容器)。一旦Pod成功完成其任务(即主容器退出码为0),Job就会认为该任务已完成,并且不会重新启动Pod(即使设置了 restartPolicy: Never
也一样,因为这个设置是在Pod层面,用于定义容器退出后Pod是否重启)。因此,preStop
钩子可能在Pod结束前不会执行,因为它预期在容器正常终止之前执行,但Job的Pod通常只运行到任务完成。
另外,如果job运行时间很短,比如只计算10位的圆周率,postStart和preStop都会出错,由于 Job 任务运行得很快,有可能 postStart
和 preStop
钩子尝试在容器还没有完全启动或立即要停止的时候运行,这可能导致它们无法正确执行。
CronJob
管理基于时间的Job,即:
- 在给定时间只运行一次
- 周期性的在给定时间运行
说明:
- spec.template格式同Pod
- RestartPlicy仅支持Never和OnFailure
- 单个pod时,默认Pod成功后Job即结束
- .spec.completions标志Jpb结束需要成功运行的Pod个数,默认位1
- .spec.parallelism标志并行运行的Pod的个数,默认位1
- spec.actibeDeadlinesSeconds标志失败Pod的重试最大时间, 超过这个时间不会继续重试。
典型用法
- 在给定时间调度Job运行
- 创建周期性运行的Job,例如数据库备份、发送邮件
资源清单关键属性
- .spec.schedule 调度 指定运行周期,格式同cron
- .spec.jobTemplate Job模板,格式同Job
- .spec.startingDeadlineSecond 启动job的期限(秒级)。默认为无限制。若错过调度时间,则认为job失败
- .spec.concurrentyPolicy 并发策略。用于指定处理被CronJob创建的Job并发执行的策略
Allow(默认):允许并发运行Job
Forbid :禁止并发 ,如果前一个没有完成,则直接跳过下一个
Replace:取消当前正在运行的Job,用一个新的来替换
示例
设定一个每分钟发送时间的CronJob
与上文类似,设定一个
main.sh
t=$(date +"%Y-%m-%d_%H:%M:%S")
curl http://192.168.0.221:5000/time?time=$t
生成镜像
dockerfile
FROM ubuntu:22.04
RUN apt update && apt install -y curl bc
WORKDIR /tmp
COPY main.sh /tmp/main.sh
ENTRYPOINT ["/bin/sh", "/tmp/main.sh"]
推送到harbor
docker build -t harbor.tangotz.com/os/u-time:0.1 .
docker push harbor.tangotz.com/os/u-time:0.1
编写资源文件
cj.yml
apiVersion: batch/v1
kind: CronJob
metadata:
name: time
spec:
schedule: "* * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: timer
image: harbor.tangotz.com/os/u-time:0.1
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "curl 192.168.0.221:5000/start"]
preStop:
exec:
command: ["/bin/sh", "-c", "curl 192.168.0.221:5000/stop"]
restartPolicy: Never
观察结果
每分钟都会发送一个请求
但是也有一个小问题,通过CronJob调用Job,再由Job生成的Pod并不会在任务结束后就立刻清理
在使用 CronJob 生成的 Job 时,Pod 的存活时间并不是直接由 CronJob 控制的,而是由 Job 的配置和 Kubernetes 的默认行为共同决定的。Pod 的存活时间通常取决于以下几个因素:
- Job 的完成状态:如果 Job 成功完成(即
.spec.completions
指定的 Pod 数量都成功执行并退出),那么这些 Pod 通常会在短时间内被自动删除。Kubernetes 会监控这些 Pod 的状态,一旦 Job 被标记为完成(即所有 Pod 都成功完成或失败达到了一定的次数限制),它就会开始清理过程。 ttlSecondsAfterFinished
:这是 Kubernetes 1.12+ 版本中引入的一个特性,允许指定 Job 完成后 Pod 保持存活的秒数。如果设置了这个字段,Pod 会在指定的时间后自动被删除。但默认情况下,这个字段是不设置的,因此 Pod 可能会根据 Kubernetes 的垃圾收集机制来决定何时被删除。- 垃圾收集机制:Kubernetes 的节点控制器(Node Controller)和 API 服务器(API Server)会定期清理不再需要的 Pod。这些 Pod 可能是已经完成的 Job 的一部分,或者是因为其他原因(如节点故障)而不再需要的。但是,这个清理过程并不是实时的,可能会有一定的延迟。
- 其他因素:Pod 的存活时间还可能受到其他因素的影响,如网络延迟、API 服务器的负载等。这些因素都可能导致 Pod 的删除操作被延迟。
如果希望更精确地控制 Pod 的存活时间,可以考虑在 Job 的配置中设置 ttlSecondsAfterFinished
字段。这样,就可以指定一个明确的时间段,在 Job 完成后自动删除 Pod。请注意,这个字段是在 Kubernetes 1.12+ 版本中引入的,因此请确保集群版本支持这个特性。
存活时间
根据上文添加存活时间参数
apiVersion: batch/v1
kind: CronJob
metadata:
name: time
spec:
schedule: "* * * * *"
jobTemplate:
spec:
ttlSecondsAfterFinished: 30 # 设置Job完成后Pod的存活时间为30秒
template:
spec:
containers:
- name: timer
image: harbor.tangotz.com/os/u-time:0.1
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "curl 192.168.0.221:5000/start"]
preStop:
exec:
command: ["/bin/sh", "-c", "curl 192.168.0.221:5000/stop"]
restartPolicy: Never
再次查看pod,可以看到大约是在32s的时候pod被清理