一、DaemonSet
1.1 介绍
与Deployment相似的是,DaemonSet也是基于标签选择器管控一组Pod副本。但是,DaemonSet用于确保所有或指定的工作节点上都运行有一个Pod副本。换句话说,其Pod数量由节点数量而定,因此无需定义replicas字段(Pod的副本数量)。从集群移除节点时,此类Pod对象也将被自动回收而无需重建。
它通常用于运行那些执行系统级操作任务的应用,例如:
- 在每个节点运行日志收集守护进程,比如filebeat和logstash等
- 在每个节点运行监控系统的代理守护进程,比如Prometheus Node Exporter
- 在每个节点运行系统化应用,比如kube-proxy、flannel、Calico等
1.2 DaemonSet资源应用示例
如下示例定义了一个DaemonSet资源,用于在每个节点运行一个Prometheus Node Exporter进程以收集节点级别的监控数据,此进程共享节点的Network和PID名称空间。
vim daemonset-demo.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: daemonset-demo
namespace: default
labels:
app: prometheus
component: node-exporter
spec:
selector:
matchLabels:
app: prometheus
component: node-exporter
template:
metadata:
name: prometheus-node-exporter
labels:
app: prometheus
component: node-exporter
spec:
containers:
- image: prom/node-exporter:v1.6.0
name: prometheus-node-exporter
ports:
- name: prom-node-exp
containerPort: 9100
hostPort: 9100
livenessProbe:
tcpSocket:
port: prom-node-exp
initialDelaySeconds: 3
readinessProbe:
httpGet:
path: '/metrics'
port: prom-node-exp
scheme: HTTP
initialDelaySeconds: 5
hostNetwork: true
hostPID: true
Prometheus Node Exporter默认监听TCP协议的9100端口,基于HTTP协议及/metrics输出指标数据,将如上yaml创建到集群后,向任一节点发起访问来验证。
1.3 DaemonSet的更新策略
其相关配置在spec.updateStrategy字段,目前支持RollingUpdate和OnDelete两种策略。
- RollingUpdate为默认策略,工作逻辑与Deployment控制器的同名策略类似。只是由于节点难以临时增加,因而DaemonSet仅支持使用maxUnavailable属性定义最大不可用Pod副本数(默认为1)。
- OnDelete是在相应节点的Pod模板被删除后重建为新版本,从而允许用户手动编排更新过程。
二、Job控制器
2.1 Job控制器的应用编排机制
Job控制器用于管理那些运行一段时间就能”完成”的任务(即”一次性”任务,比如备份操作)。容器中的进程运行完成后无需再重启,而是由控制器把该Pod对象置于Completed(正常完成任务)状态,并能够在超过用户指定的生存周期后由系统自行删除。但当容器中的进程因”错误”(未完成)而终止时,则根据相关配置决定是否重启。通常,未运行完成的Pod对象因其所在的节点故障而意外终止后被重新创建。
但有的作业任务可能运行不止一次,可以配置它们以串行或并行方式运行。
- 单工作队列的串行式Job:将一个作业串行执行多次直到满足期望的次数,这种Job可理解为并行度为1的作业执行方式,在某个时刻仅有一个Pod资源对象存在。
- 多工作队列的并行式Job:这种方式可以设置工作队列数(即作业数),每个队列仅运行一个作业,也可以用有限的工作队列运行较多的作业,即工作队列数少于总作业数,相当于运行多个串行队列,工作队列数即同时可运行的Pod资源数。
对于有严格次序要求或者拥有”层次”特性的作业,就选择单工作队列串行执行;反之,适度的并行可提升作业运行速度。
2.2 Job资源规范
apiVersion: batch/v1 #API群组及版本
kind: Job #资源类型标识
metadata:
name: <string> #资源名称,在作用域中唯一
namespace: <string> #名称空间:Job资源隶属名称空间级别
pec:
selector: <object> #标签选择器,必须匹配template字段中Pod模板的标签
template: <object> #Pod模板对象
suspend: <boolean> #是否挂起当前Pod的执行,挂起作业会重置StartTime字段中的值
completions: <integer> #期望的成功完成的作业次数,成功运行结束的Pod数量。默认为1
completionMode: <string> #追踪Pod完成的模式,支持Indexed(索引,有序排序)和NonIndexed(无索引,默认使用)两种
ttlSecondsAfterFinished: <integer> #终止状态作业的生存时长,超期将被删除
parallelism: <integer> #作业的最大并行度,默认为1。通常≤completions,在completions大于1时才有意义
backoffLimit: <integer> #将作业标记为”Failed”之前的重试次数,默认为6
activeDeadlineSeconds: <integer> #作业启动后可处于活动状态的时长,之后强行终止
定义Job资源时,Job会为其Pod对象自动添加”job-name=JOB_NAME”和”controller-uid=UID”标签,并使用标签选择器完成对controller-uid标签的关联。因此,selector并非必选字段。
另外,Pod的重启策略(spec.restartPolicy)默认为Always,这对Job控制器并不适用,因此需设置重启策略(restartPolicy)的属性为Never或OnFailure。
此类型Pod的命名格式为(job-name)-(index)-(random-string),其中的index字段取值与completions和completionMode有关。
2.3 Job资源应用示例
2.3.1 串行式Job
如下示例定义了一个名为job-demo的Job资源。基于运行一段时间后终止的目的,该示例中的Pod模板运行一个睡眠60s的应用来模拟此功能。
vim job-demo.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: job-demo
spec:
template:
spec:
containers:
- name: myjob
image: alpine:3.18.2
imagePullPolicy: IfNotPresent
command: ["/bin/sh", "-c", "sleep 60"]
restartPolicy: Never
completions: 2
ttlSecondsAfterFinished: 3600
backoffLimit: 3
activeDeadlineSeconds: 300
将job-demo资源运行到集群上后,用kubectl get job命令查看Job资源的状态信息。其中COMPLETIONS字段(m/n)表示期望完成的作业数(n)和已完成的作业数(m),DURATION为作业完成所运行的时长。
如下命令显示两次作业均运行完成处于Completed状态时的情况。
Job资源的详细描述中可获得进一步的信息,包括使用的标签选择器、为Pod自动添加的标签、作业并行度、各Pod的状态及相应事件等。
kubectl describe job job-demo
Name: job-demo
Namespace: default
Selector: batch.kubernetes.io/controller-uid=9bce100c-8666-4525-bbea-d0d8851d5456
Labels: batch.kubernetes.io/controller-uid=9bce100c-8666-4525-bbea-d0d8851d5456
batch.kubernetes.io/job-name=job-demo
controller-uid=9bce100c-8666-4525-bbea-d0d8851d5456
job-name=job-demo
Annotations: batch.kubernetes.io/job-tracking:
Parallelism: 1
Completions: 2
Completion Mode: NonIndexed
Start Time: Fri, 23 Jun 2023 12:08:43 +0800
Completed At: Fri, 23 Jun 2023 12:11:20 +0800
Duration: 2m37s
Active Deadline Seconds: 300s
Pods Statuses: 0 Active (0 Ready) / 2 Succeeded / 0 Failed
Pod Template:
Labels: batch.kubernetes.io/controller-uid=9bce100c-8666-4525-bbea-d0d8851d5456
batch.kubernetes.io/job-name=job-demo
controller-uid=9bce100c-8666-4525-bbea-d0d8851d5456
job-name=job-demo
Containers:
……
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 9m10s job-controller Created pod: job-demo-75p44
Normal SuccessfulCreate 7m36s job-controller Created pod: job-demo-lgnkl
Normal Completed 6m33s job-controller Job completed
2.3.2 并行式Job
将并行度属性spec.parallelism设置为>1的值,并设置总任务数spec.completions的属性>并行度,便能够让Job资源以并行方式运行多任务。它支持并行地处理一组独立但相关的工作任务,如发送邮件、渲染视频帧、转码文件和扫描NoSql数据库中的主键范围等。
如下示例中定义了一个2路并行且总体运行6次任务的Job资源规范,同时加上索引便于查看效果。按照并行Job的运行规则,job-para-demo资源将允许最多同时运行两个Pod,即两路管道,每个管道串行运行分配的Job。
vim job-para-demo.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: job-para-demo
spec:
template:
spec:
containers:
- name: myjob
image: alpine:3.18.2
imagePullPolicy: IfNotPresent
command: ["/bin/sh", "-c", "sleep 30"]
restartPolicy: Never
completions: 6
completionMode: Indexed
parallelism: 2
ttlSecondsAfterFinished: 3600
backoffLimit: 3
activeDeadlineSeconds: 1200
从Pod的运行状态可看到,第一批次的两个Pod运行完后就处于Completed状态,之后的第二、第三批次也是如此,直到所有的Pod都终止结束为止。
三、CronJob控制器
3.1 介绍
CronJob资源用于管理Job资源的运行时间,它允许用户在特定时间内或以指定的时间间隔运行Job。它适合执行特定的任务,比如备份、报告、发送邮件或清理类的任务等,其功能类似于Linux系统中的周期性作业计划(crontab),可以控制其运行的时间点及周期性运行的方式:
- 仅在未来某时间点将指定的作业运行一次;
- 在指定的周期性时间内重复运行指定的作业。
CronJob资源在指定时间点时,通配符”?”和”*”意义相同,它们都表示任何可用的有效值。
3.2 CronJob资源规范
apiVersion: batch/v1beta1 #API群组及版本
kind: CronJob #资源类型标识
metadata:
name: <string> #资源名称,在作用域中要唯一
namespace: <string> #名称空间,CronJob隶属名称空间级别
spec:
jobTemplate: <Object> #Job作业模板,必选字段
metadata: <object> #模板元数据
spec: <object> #作业的期望状态
schedule: <string> #调度时间设定,必选字段
concurrencyPolicy: <string> #并发策略,可用值有Allow、Forbid和Replace
failedJobsHistoryLimit: <integer> #失败作业的历史记录数,默认为1
successfulJobsHistoryLimit: <integer> #成功作业的历史记录数,默认为3
startingDeadlineSeconds: <integer> #因错过时间而未执行的作业可超期时长
suspend: <boolean> #是否挂起后续的作业,不影响当前作业,默认为false
3.3 CronJob资源应用示例
如下示例定义了一个名为cronjob-demo的CronJob资源,它每分钟运行一次由jobTemplate定义的任务,每次任务以单路运行的方式执行1次,每个任务的执行不超过60s,且完成后600s的Job将会被删除。
vim cronjob-demo.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: cronjob-demo
namespace: default
spec:
schedule: "* * * * *"
jobTemplate:
metadata:
labels:
controller: cronjob-demo
spec:
parallelism: 1
completions: 1
ttlSecondsAfterFinished: 600
backoffLimit: 3
activeDeadlineSeconds: 60
template:
spec:
containers:
- name: myjob
image: alpine
command:
- /bin/sh
- -c
- date; echo Hello from CronJob, sleep a while...; sleep 10
restartPolicy: OnFailure
startingDeadlineSeconds: 300
将cronjob-demo资源创建到集群后通过kubectl get cronjob命令了解运行状态。其中SCHEDULE指其调度时间点,SUSPEND表示后续任务是否处于挂起状态,即暂停任务的调度与运行,ACTIVE表示活动状态的Job对象的数量,LAST SCHEDULE表示前一次调度运行至此刻的时长。
一段时长后,cronjob-demo创建的Job对象可能会存在多个,但如上示例中的CronJob资源的配置使得Job控制器会自动删除那些由cronjob-demo生成已超过600s的的Pod对象。
四、StatefulSet
4.1 介绍
无状态应用它们所管理的Pod的IP、名字、启停顺序都是随机的,其进程接收的每次连接都能独立处理,一次请求和响应构成一个完整的事务,且不受其它连接的影响,即使意外中断或关闭连接也能重新建立连接。同时不依赖外部存储。因此,无状态应用的Pod对象可随时被由同一模板创建的新Pod所替代,这正是Deployment控制器编排应用的方式。
反之就是有状态应用(StatefulSet)了。Pod涉及主从、主备这样的依赖关系,甚至对启动顺序也有要求。而且这些Pod需要外部存储,一旦Pod被清除或被调度到别的工作节点时,怎么让Pod继续绑定先前的外部数据?这就是StatefulSet要去做的。StatefulSet将这些应用的状态记录下来,在需要的时候恢复。
通常,一个完整可用的StatefulSet资源由两个组件组成:Headless Service和StatefulSet资源。StatefulSet在编排Pod对象的同时借助volumeClaimTemplate以静态或动态的PV供给方式为各Pod资源提供专有且固定的存储资源。此外,StatefulSet在Headless Service的基础上又为StatefulSet控制的每个Pod副本创建了一个DNS域名,这个域名的格式为:
$(podname).(headless server name)
FQDN:$(podname).(headless server name).namespace.svc.cluster.local
对于拥有n个副本的StatefulSet资源而言,它会以{0~n-1}的顺序依次对各个Pod对象进行编号及顺序创建,当前Pod对象就绪后才会创建下一个。而删除或缩容则以相反的方向进行,按照逆序先删除编号最大的Pod,再删除编号小的Pod。
StatefulSet也支持用户自定义的更新策略,兼容之前版本的OnDelete和RollingUpdate策略(默认使用)。更新过程中,更新顺序与终止Pod资源的顺序相同,由索引号(编号)最大的开始,终止一个Pod对象并完成其更新后继续进行前一个。此外,StatefulSet资源的滚动更新还支持分区机制,用户可基于某个用于分区的索引号对Pod资源进行分区。所有≥此索引号的Pod对象会被滚动更新,而<此索引号的则不会被更新。若给定的分区号>副本数量,意味着不存在>此分区号的Pod资源索引号,因此,所有的Pod对象均不会被更新,这对于期望暂停发布、金丝雀发布而言非常有用。
4.2 StatefulSet资源规范
apiVersion: apps/v1 #API群组及版本
kind: StatefulSet #资源类型标识
metadata:
name: <string> #资源名称,在作用域中唯一
namespace: <string> #名称空间:StatefulSet隶属名称空间级别
spec:
serviceName: <string> #相关的Headless Service的名称,必选字段
replicas: <integer> #期望的Pod副本数,默认为1
selector: <object> #标签选择器,需匹配Pod模板中的标签,必选字段
template: <object> #Pod模板对象,必选字段
revisionHistoryLimit: <integer> #滚动更新历史记录数量,默认为10
updateStrategy: <Object> #滚动更新策略
type: <string> #滚动更新类型,可用值有OnDelete和RollingUpdate
rollingUpdate: <string> #滚动更新参数,专用于RollingUpdate类型
partition: <integer> #分区指示索引值,默认为0
volumeClaimTemplates: <[]Object> #存储卷申请模板,用来将PVC的定义嵌入到StatefulSet中的字段,是创建PVC的模板,可以让每一个Pod都能自动创建PVC
apiVersion: <string> #PVC资源所属的API群组及版本,可省略
kind: <string> #PVC资源类型标识,可省略
metadata: <Object> #卷申请模板元数据
spec: <Object> #期望的状态,可用字段同PVC
podManagementPolicy: <string> #Pod管理策略,默认的OrderedReady表示顺序创建逆序删除,另一可用值Parallel表示并行模式(Pod之间无顺序关系要求时可用,提高效率)
4.3 StatefulSet资源应用示例
如下示例中定义了名为demodb的Headless Service,以及一个同名的StatefulSet资源,后者使用了存储卷申请模板,为Pod对象从nfs-csi存储类申请动态供给并绑定PV。但是要想apply此yaml,需提前部署好nfs-csi存储类(动态供应PVC)。
vim demodb.yaml
---
apiVersion: v1
kind: Service
metadata:
name: demodb
namespace: default
labels:
app: demodb
spec:
clusterIP: None
ports:
- port: 9907
selector:
app: demodb
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: demodb
namespace: default
spec:
selector:
matchLabels:
app: demodb
serviceName: "demodb"
replicas: 2
template:
metadata:
labels:
app: demodb
spec:
containers:
- name: demodb-shard
image: ikubernetes/demodb:v0.1
ports:
- containerPort: 9907
name: db
env:
- name: DEMODB_DATADIR
value: "/demodb/data"
livenessProbe:
initialDelaySeconds: 2
periodSeconds: 10
httpGet:
path: /status
port: db
readinessProbe:
initialDelaySeconds: 15
periodSeconds: 30
httpGet:
path: /status?level=full
port: db
volumeMounts:
- name: data
mountPath: /demodb/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "fast-rbd"
resources:
requests:
storage: 2Gi
示例中用到的demodb是一个仅用于测试的分布式键值存储系统,支持持久化数据存储,它由一个Leader和一到多个Follower组成,Followers定期从Leader查询并请求同步数据。Leader支持读写请求,而各Follower节点仅支持只读操作,它们会将接收到的写请求通过307响应码重定向到Leader节点。/status用于输出状态,/status?level=full能够以200响应码返回持有的键数量,否则返回响应码500。
由StatefulSet资源创建的Pod对象拥有唯一且固定的标识符,它们基于唯一的索引号及相关的StatefulSet对象的名称生成,且有序创建,格式为<statefulset name>-<ordinal-index>。通过kubectl describe命令获得的信息中显示,StatefulSet对象demodb所创建的demodb-0和demodb-1俩对象的名称即遵循此格式。先创建demodb-0,待其就绪后再创建demodb-1,以此类推。事实上,这类Pod的主机名与其资源名称相同。以demodb-0为例,如下命令打印的主机名称正是Pod资源的名称。
此时查看PVC,发现也有两个对象,以”PVC名称-Pod名称”格式命名,每一个Pod都能分配一个专用的PVC。此类PVC是由volumeClaimTemplates创建的,每一个PVC又绑定在由存储类nfs-csi动态供给的PV之上。即使Pod对象缩容或被误删除,也不会删除相关的PV/PVC,且仍处于绑定状态,确保数据可用性。因而Pod对象因节点故障或被驱逐等原因被调度到其它节点时,先前同名Pod实例专用的PV及其数据可复用。
新建一个用于测试的客户端,进去后写一个测试文件,放到demodb存储服务以发起请求测试。而CoreDNS默认以轮询方式响应对同一个名称的解析请求,因此,访问demodb这一Headless Service的请求会轮询到demodb-0和demodb-1之上。
kubectl run client-$RANDOM --image=ikubernetes/admin-box:v1.2 --restart=Always -it --command -- /bin/bash
echo "demodb test" > demodb.txt
curl -L -XPUT -T demodb.txt http://demodb:9907/set/mydata
调度至从节点(demodb-1)的请求会重定向到主节点(demodb-0),且主节点数据存储完成后会同步到各个从节点。
curl http://demodb:9907/get/mydata
curl http://demodb-1.demodb:9907/get/mydata
demodb的所有节点会将数据存储在/demodb/data目录下,每个键被映射为一个子目录,数据存储在该目录下的content文件中。
kubectl exec demodb-1 -- cat /demodb/data/mydata/content
Pod数量扩容为3个后进入demodb-2,看到的内容也是一样的。同时PVC也会增加(因为是动态SC)。
4.4 StatefulSet滚动更新
编辑之前的demodb/yaml,将镜像名改为ikubernetes/demodb:v0.2,同时添加相关的滚动更新策略(定义在sts.spec字段内,sts为StatefulSet的简称)。
此时通过Pod运行时间可以看出,demodb-2的时间较短,显然是更新了镜像所致。因为分区数设为2,所以只针对索引号≥2的Pod进行更新,demodb-0、demodb-1就不会更新,创建时间仍然较长。
4.5 StatefulSet的局限性
生产环境中的分布式应用的各实例间往往伴随着复杂的协议(例如Zookeeper集群成员基于ZAB协议的Leader/Follower关系),对持久存储的依赖需求也有所不同, 并且集群成员的增减以及在故障后的恢复操作通常都会依赖一系列复杂且精细的步骤才能完成,而StatefulSet不能为其封装统一、标准的管理操作。于是,用户就不得不配置某个特定的有状态应用,在其yaml配置中通过”复杂的运维代码”手动编写相关的运维逻辑。
面对这种情况,CoreOS为Kubernetes引入了一个名为Operator的新概念和新组件,它借助CRD(Customed Resource Definition)创建自定义资源类型来完整描述某个有状态应用集群,并相应创建自定义的控制器来编排这些自定义资源类型所创建的各个资源对象。这意味着在Kubernetes系统上部署分布式有状态应用往往使用Operator。
标签:控制器,StatefulSet,name,Kubernetes,job,demodb,介绍,Job,Pod From: https://blog.51cto.com/u_15796303/6549474