系列目录

job是什么

对于ReplicaSet、ReplicationController等类型的控制器而言,它希望pod保持预期数目、持久运行下去,除非用户明确删除,否则这些对象一直存在,它们针对的是耐久性任务,如web服务等。对于非耐久性任务,比如压缩文件,任务完成后,pod需要结束运行,不需要pod继续保持在系统中,这个时候就要用到Job。因此说Job是对ReplicaSet、ReplicationController等持久性控制器的补充。

Job与其它控制器的细微差别

Job定义方法与ReplicaSet等控制器相似,只有细微差别,如下:

  • Job中的restart policy必需是"Never"或者"OnFailure",这个很好理解,因为pod要运行到结束,而不是反复重新启动。

  • Job不需要选择器,其中的pod也不需要标签,系统在创建Job时会自动添加相关内容。当然用户也可以出于资源组织的目的添加标签,但这个与Job本身的实现没有关系。

  • Job新增加两个字段:.spec.completions、.spec.parallelism。详细用法在示例中说明

  • backoffLimit字段:示例中说明

示例

非并发Job

非并发Job的含义是,Job启动后,只运行一个pod,pod运行结束后整个Job也就立刻结束。

以下是简单的Job配置文件,只包含一个pod,输出圆周率小数点后2000位,运行时间大概为10s:

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

以上示例无需设置选择器、pod标签。无需设置.spec.completions、.spec.parallelism,这两个字段的默认值都是1。backoffLimit=4,表示允许pod失败的次数。将以上内容保存成文件并创建Job:

$ kubectl create -f https://k8s.io/examples/controllers/job.yaml
job "pi" created

确认Job状态:

$ kubectl describe jobs/pi
Name: pi
Namespace: default
Selector: controller-uid=b1db589a-2c8d-11e6-b324-0209dc45a495
Labels: controller-uid=b1db589a-2c8d-11e6-b324-0209dc45a495
job-name=pi
Annotations: <none>
Parallelism: 1
Completions: 1
Start Time: Tue, 07 Jun 2016 10:56:16 +0200
Pods Statuses: 0 Running / 1 Succeeded / 0 Failed
Pod Template:
Labels: controller-uid=b1db589a-2c8d-11e6-b324-0209dc45a495
job-name=pi
Containers:
pi:
Image: perl
Port:
Command:
perl
-Mbignum=bpi
-wle
print bpi(2000)
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 1m 1 {job-controller } Normal SuccessfulCreate Created pod: pi-dtn4q

从以上输出可以看到系统自动添加的Selector、Pod labels。注意Events的输出,全程只创建了一个pod。

列出Job的所有pod:

$ pods=$(kubectl get pods --selector=job-name=pi --output=jsonpath={.items..metadata.name})
$ echo $pods
pi-aiw0a

查看Pod的输出

$ kubectl logs $pods
3.14159265358979323846264......

以上是最简单的Job应用示例,输出圆周率小数点后2000位。但是,考虑另外一种情况,假如我们需要计算圆周率小数点后3000、4000、5000位怎么办?一种方案是先将上例中的2000改成3000,创建并运行。然后再改成4000,再创建并运行,一直到5000。显然这种方案并不高明:麻烦、资源利用率低。另外一种方法是同时创建4个Job,分别计算2000、3000、4000、5000。注意4个Job的name字段不能冲突分别是pi-2000、pi-3000、pi-4000、pi-5000,

文件名分别为pi-2000.yaml、pi-3000.yaml、pi-4000.yaml、pi-5000.yaml,并保存在目录/tmp/pi下。利用kubectl对目录的支持一次性创建4个Job:

$ kubectl create -f /tmp/pi
job "pi-2000" created
job "pi-3000" created
job "pi-4000" created
job "pi-5000" created

以上方法是伪并发,只适用于任务量少的情况。假如我们需要处理的任务是从pi-1到pi-10000,那么以上方法就不适用了:

  • 需要同时创建太多的Job与pod,不好管理。

  • 资源配额限制。

粗并发Job

本例创建一个Job,但Job要创建多个pod。了解完示例后就明白为什么叫“粗并发”。

本示例需要一个消息队列服务的配合,不详细描述如何部署、填充消息队列服务。假设我们有一个RabbitMQ服务,集群内访问地址为:amqp://guest:guest@rabbitmq-service:5672。其有一个名为job1的队列,队列内有apple banana cherry date fig grape lemon melon共8个成员。

另外假设我们有一个名为gcr.io//job-wq-1的image,其功能是从队列中读取出一个元素并打印到标准输出,然后结束。注意,它只处理一个元素就结束了。接下来创建如下Job:

apiVersion: batch/v1
kind: Job
metadata:
name: job-wq-1
spec:
completions: 8
parallelism: 2
template:
metadata:
name: job-wq-1
spec:
containers:
- name: c
image: gcr.io/<project>/job-wq-1
env:
- name: BROKER_URL
value: amqp://guest:guest@rabbitmq-service:5672
- name: QUEUE
value: job1
restartPolicy: OnFailure

上例中,completions的值为8,等于job1队列中元素的个数。因为每个成功的pod处理一个元素,所以需要成功8次,job1中的所有成员就会被处理完成。在粗并发模式下,completions的值必需指定,否则其默认值为1,整个Job只处理一个成员就结束了。

上例中,parallelism的值是2。虽然需要pod成功8次,但在同一时间,只允许有两个pod并发。一个成功结束后,再启动另一个。这个参数的主要目的是控制并发pod的个数,可根据实际情况调整。当然可以不指定,那么默认的并发个数就是1。

env中的内容告诉image如何访问队列。

将以上内容保存在job.yaml文件中,运行Job:

kubectl create -f ./job.yaml

稍等片刻Job运行完成,查看结果:

$ kubectl describe jobs/job-wq-1
Name: job-wq-1
Namespace: default
Selector: controller-uid=41d75705-92df-11e7-b85e-fa163ee3c11f
Labels: controller-uid=41d75705-92df-11e7-b85e-fa163ee3c11f
job-name=job-wq-1
Annotations: <none>
Parallelism: 2
Completions: 8
Start Time: Wed, 06 Sep 2017 16:42:02 +0800
Pods Statuses: 0 Running / 8 Succeeded / 0 Failed
Pod Template:
Labels: controller-uid=41d75705-92df-11e7-b85e-fa163ee3c11f
job-name=job-wq-1
Containers:
c:
Image: gcr.io/causal-jigsaw-637/job-wq-1
Port:
Environment:
BROKER_URL: amqp://guest:guest@rabbitmq-service:5672
QUEUE: job1
Mounts: <none>
Volumes: <none>
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
───────── ──────── ───── ──── ───────────── ────── ────── ───────
27s 27s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-hcobb
27s 27s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-weytj
27s 27s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-qaam5
27s 27s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-b67sr
26s 26s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-xe5hj
15s 15s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-w2zqe
14s 14s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-d6ppa
14s 14s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-p17e0

查看Events,可以看到总共创建了8个pod。在本例中,每处理队列中的一个成员都需要创建一个pod,开销很大。如果队列中的成员个数非常庞大,那么这种处理方式就不适用。我们希望少创建pod、每个pod能处理多条记录,请看下面示例

细并发Job

redis:6379> lrange job2 0 -1
1) "apple"
2) "banana"
3) "cherry"
4) "date"
5) "fig"
6) "grape"
7) "lemon"
8) "melon"
9) "orange"

接下来创建image,详细过程不描述。只需确定这个image运行如下名为worker.py的python程序

#!/usr/bin/env python

import time
import rediswq host="redis"
# Uncomment next two lines if you do not have Kube-DNS working.
# import os
# host = os.getenv("REDIS_SERVICE_HOST") q = rediswq.RedisWQ(name="job2", host="redis")
print("Worker with sessionID: " + q.sessionID())
print("Initial queue state: empty=" + str(q.empty()))
while not q.empty():
item = q.lease(lease_secs=10, block=True, timeout=2)
if item is not None:
itemstr = item.decode("utf=8")
print("Working on " + itemstr)
time.sleep(10) # Put your actual work here instead of sleep.
q.complete(item)
else:
print("Waiting for work")
print("Queue empty, exiting")

首先连接到redis的job2队列。然后是一个while循环,每次读job2中的一条记录并输出,然后sleep 10s。循环退出的条件是job2队列为空。这个image与示例2不同,示例2只处理一条记录这就结束,而这个可以处理多条一直到队列为空。

接下来定义Job:

apiVersion: batch/v1
kind: Job
metadata:
name: job-wq-2
spec:
parallelism: 2
template:
metadata:
name: job-wq-2
spec:
containers:
- name: c
image: gcr.io/myproject/job-wq-2
restartPolicy: OnFailure

上例中,无需像示例2一样指定 completions的值,因为结束条件是job2为空,已经内嵌在image的逻辑中。parallelism=2表示可以并发两个pod,不设置默认为1,在实际应用中可据实际情况自行调整。

运行Job:

kubectl create -f ./job.yaml

过一会查看Job运行状况:

$ kubectl describe jobs/job-wq-2
Name: job-wq-2
Namespace: default
Selector: controller-uid=b1c7e4e3-92e1-11e7-b85e-fa163ee3c11f
Labels: controller-uid=b1c7e4e3-92e1-11e7-b85e-fa163ee3c11f
job-name=job-wq-2
Annotations: <none>
Parallelism: 2
Completions: <unset>
Start Time: Mon, 11 Jan 2016 17:07:59 -0800
Pods Statuses: 1 Running / 0 Succeeded / 0 Failed
Pod Template:
Labels: controller-uid=b1c7e4e3-92e1-11e7-b85e-fa163ee3c11f
job-name=job-wq-2
Containers:
c:
Image: gcr.io/exampleproject/job-wq-2
Port:
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
33s 33s 1 {job-controller } Normal SuccessfulCreate Created pod: job-wq-2-lglf8

虽然允许的最大并发数是2,但Events显示只创建成功一个pod,这个是正常情况,最大并非必需,可能系统因为资源问题达不到最大。

查看pod输出:

$ kubectl logs pods/job-wq-2-7r7b2
Worker with sessionID: bbd72d0a-9e5c-4dd6-abf6-416cc267991f
Initial queue state: empty=False
Working on banana
Working on date
Working on lemon

细并发相比与粗并发,减少了创建pod的开销,使每个pod能处理多条记录,但是pod要自己决定退出条件,如果不退出,那么Job永远无法结束。

关于资源回收

Job创建的pod在结束运行后,无论是成功还是失败,不会默认删除,仍然保留在系统中,这样用户才可以查看其日志、状态信息、排除错误。用户需要手动运行kubectl delete删除所有运行结束的pod,为了方便组织资源,一次性删除会部pod,可以被pod自定义标签。Job在运行完成后也仍然保留在系统中,由用户删除。所以使用Job,用户应注意资源回收,避免资源被耗尽。

kubernetes对象之Job的更多相关文章

  1. Kubernetes对象之Service

    系列目录 通过ReplicaSet来创建一组Pod来提供具有高可用性的服务.虽然每个Pod都会分配一个单独的Pod IP,然而却存在如下两问题: Pod IP仅仅是集群内可见的虚拟IP,外部无法访问. ...

  2. Kubernetes对象

    Kubernetes对象 在之前的文章已经讲到了很多Kubernets对象,包括pod,service,deployment等等.Kubernets对象是一种持久化,表示集群状态的实体.它是一种声明式 ...

  3. Kubernetes 对象管理的三种方式

    Kubernetes 中文文档 1. Kubernetes 对象管理的三种方式对比 Kubernetes 中的对象管理方式,根据对象配置信息的位置不同可以分为两大类: 命令式:对象的参数通过命令指定 ...

  4. Kubernetes对象之Pod

    系列目录 Pod是Kubernetes调度的最小单元.一个Pod可以包含一个或多个容器,因此它可以被看作是内部容器的逻辑宿主机.Pod的设计理念是为了支持多个容器在一个Pod中共享网络和文件系统 因此 ...

  5. Kubernetes对象之ReplicaSet

    系列目录 说到ReplicaSet对象,得先说说ReplicationController(简称为RC).在旧版本的Kubernetes中,只有ReplicationController对象.它的主要 ...

  6. kubernetes对象之secrets

    系列目录 Secrets是Kubernetes中一种对象类型,用来保存密码.私钥.口令等敏感信息.与直接将敏感信息嵌入image.pod相比,Secrets更安全.更灵活,用户对敏感信息的控制力更强. ...

  7. kubernetes对象之Volume

    系列目录 概述 Volume是对各种存储资源的抽象.虚拟化.为管理.控制.使用存储资源提供统一接口.Openstack中的volume为虚拟机提供存储,Docker中的volume为容器提供存储.因为 ...

  8. kubernetes对象之Ingress

    系列目录 概述 向外网暴露集群内服务,以使客户端能够访问,有以下几种方法,本文重点描述Ingress. LoadBalancer LoadBalancer一般由云服务供应商提供或者用户自定义,运行在集 ...

  9. Kubernetes对象中的PersistentVolume、PersistentVolumeClaim和StorageClass的概念关系

    Kubernetes容器要持久化数据,离不开volume,k8s的volume和Docker原生概念中的volume有一些差别,不过本次不讲这个,本次要明确的是k8s持久化数据用到的几个对象Persi ...

  10. kubernetes对象之deployment

    系列目录 简述 Deployment为Pod和ReplicaSet提供了一个声明式定义(declarative)方法,用来替代以前的ReplicationController来方便的管理应用.典型的应 ...

随机推荐

  1. linux下编译静态库openssl

    先编译zlib cmake . -DCMAKE_INSTALL_PREFIX=/depends make make install 然后编译openssl ./config zlib no-rc5 n ...

  2. cssText批量修改样式

    cssText所有浏览器都支持. cssText 的使用 obj.style.cssText = " width:200px;position:absolute;left:100px;&qu ...

  3. LineageOS源码定制手机系统

    LineageOS源码定制手机系统 导语: 现在市场的手机基本就两种:  苹果机和android机. 今天我们不谈苹果机, 对小编我来讲,那是个奢侈品, android是我的最爱.对于一般androi ...

  4. 我要好offer之 概率题大总结

    1. 利用等概率Rand5生成等概率Rand3 Rand5生成等概率Rand3 这个题目可以扩展为:利用等概率RandM生成等概率RandN (M > N) 这里,我们首先明白一个简单的知识点: ...

  5. 转 Centos下安装apahce的configure: error: APR not found. Please read the documentation解决办法

    转自: http://www.cnblogs.com/Anker/p/3355573.html 今天从Apache官网上http://httpd.apache.org/下载httpd web服务器,由 ...

  6. 一个页面多个ng-app注意事项

    1.一个页面会自动加载第一个ng-app 2.如果想启动其它ng-app,需要通过下列代码的红色部分来启动,此时一共启动了2个ng-app 3.特别注意:代码红色部分一定要放在最后,比如,不能放在蓝色 ...

  7. AC日记——Sign on Fence Codeforces 484e

    E. Sign on Fence time limit per test 4 seconds memory limit per test 256 megabytes input standard in ...

  8. [原创][FPGA][IP-Core]altlvds_tx & altlvds_rx

    1. 概述 Alter公司的QuartusII软件提供了LVDS发送和接收的IP核供我们使用,其在本质上可以理解为并行-串行数据的转换器.其在官方文档(见附件)上也这样说过.其中的应用场景有告诉AD/ ...

  9. linux time

    uint32_t midtime; static struct timeval startstart,midmid; while (ros::ok()) { gettimeofday(&sta ...

  10. assigning to uiimagepickercontrollerdelegate from incompatible type

    I have added a UIImagePickerController to a UIViewController. I have assigned the UIImagePickerContr ...