存活探针
面临的问题
使用k8s的一个主要好处是,如果一个pod的其中一个容器终止,或者一个pod的所有容器都终止。只要该pod存在,pod所在节点的Kubelet会重启容器,修复这样的问题。
但是,==有时候容器进程没有崩溃,但应用程序也会停止正常工作。==例如,具有内存泄漏的Java应用程序抛出OutOfMemoryErrors,JVM进程仍然在运行。此时,k8s就无法监测并修复这样的问题。如果有一种方法,能让应用程序向k8s发出信号,告诉k8s它运行异常并让k8s重新启动,那就很棒了。
介绍存活探针
上述问题可以通过存活探针(liveness probe)解决。
k8s通过存活探针检查容器是否还在运行。也可以为pod中的每个容器单独指定存活探针。如果探测失败,k8s将定期执行探针并重新启动容器。
k8s会在你的容器崩溃或其存活探针失败时,通过重启容器来保持运行。这项任务由承载pod的节点上的Kubelet执行。在主服务器上运行的Kubernetes Control Plane组件不会参与此过程。
k8s有三种探测容器的机制:
- HTTP GET探针:对容器的IP地址(你指定的端口和路径)执行HTTP GET请求。如果探测器收到响应,并且响应状态码不代表错误(换句话说,如果HTTP响应状态码是2xx或3xx),则认为探测成功。如果服务器返回错误响应状态码或者根本没有响应,那么探测就被认为是失败的,容器将被重新启动。
- TCP套接字探针:尝试与容器指定端口建立TCP连接。如果连接成功建立,则探测成功。否则,容器重新启动。
- Exec探针:在容器内执行任意命令,并检查命令的退出状态码。如果状态码是0,则探测成功。所有其他状态码都被认为失败。
创建基于HTTP的存活探针
在书《Kubernetes in Action》的代码档案中找到新应用程序的代码(在Chapter04/kubia-unhealthy文件夹中)。打包镜像并导入k8s中。
创建pod的yaml文件(kubia-liveness-probe.yaml)
apiVersion: v1
kind: Pod
metadata:
name: "kubia-liveness"
namespace: "xylearn"
spec:
containers:
- name: kubia-unhealthy
image: "kubia-unhealthy:v1"
# http get存活探针
livenessProbe:
httpGet:
path: /
port: 8080
创建pod后,等2分钟可以看到pod被重启了。
# 查看pod重启信息
kubectl describe pod kubia-liveness -n xylearn
配置存活探针附加信息
kubectl describe pod kubia-liveness -n xylearn
的信息中还有如下内容:
- delay(延迟):delay=0s表示在容器启动后立即开始探测。
- timeout=1s:表示容器必须在1秒内响应探针。
- period=10s:表示每10秒探测一次容器
- #failure=3:表示在探测连续三次失败后重启容器。
一般来说,应用程序启动是需要时间,所以delay不设为0。如下:
apiVersion: v1
kind: Pod
metadata:
name: "kubia-liveness"
namespace: "xylearn"
spec:
containers:
- name: kubia-unhealthy
image: "kubia-unhealthy:v1"
# http get存活探针
livenessProbe:
httpGet:
path: /
port: 8080
failureThreshold: 3
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
# 容器启动后15s开始探测
initialDelaySeconds: 15
创建有效的存活探针(生产中如何使用存活探针)
- 存活探针应该检查应用程序的内部,且没有任何外部因素(比如:外部数据库)的影响。
- 保持探针轻量,不消耗太多资源,不花太长时间。
- 无须在探针中实现重试循环
了解ReplicationController
存活探针可以保证pod中的容器正常运行。
但是如果pod所在的节点本身崩溃,存活探针就没有办法了。此时Kubernetes Control Plane必须在其他节点中为所有随崩溃节点停止运行的pod创建替代品。
ReplicationController可以提供这样的功能,不过==现在k8s不用ReplicationController了,更多用的是ReplicaSet。==这部分了解一下。
介绍ReplicationController
ReplicationController根据标签选择器管理pod的,通过检查pod是否匹配某个标签选择器来判断当前pod副本的数量。
ReplicationController相关命令
创建rc
创建ReplicationController (rc)的yaml文件
apiVersion: v1
kind: ReplicationController
metadata:
name: xyrc01
spec:
# 副本数
replicas: 3
# rc的标签选择器,决定rc管理的对象
selector:
xy.com.cn/app: kubia
# pod模板
template:
metadata:
name: kubia-rc
# pod的标签
labels:
xy.com.cn/app: kubia
spec:
containers:
- name: kubia
image: registry.cn-hangzhou.aliyuncs.com/xylearn/kubia:v1
ports:
- containerPort: 8080
# 创建rc
kubectl create -f kubia-rc.yaml
# 查看rc的信息
kubectl get rc
# 可以查看到创建的rc管理的pod
kubectl get pods
# 删除一个pod,可以看到rc会启动新pod,保证副本数为3
kubectl delete pod xyrc01-tvg5d
# 查看rc的详情信息
kubectl describe rc xyrc01
rc如何创建新的pod
从技术上讲,rc没有对删除本身做出反应,而是针对由此产生的状态——pod数量不足做的反应。删除pod的通知会触发rc检查实际的pod数量并采取适当的措施。
将 pod 移入或移出 ReplicationController 的作用域
我们知道,ReplicationController是通过标签选择器管理pod的。它只能管理与标签选择器匹配的pod。所以通过更改pod的标签,可以将它从ReplicationController的作用域中添加或删除。它甚至可以从一个ReplicationController移动到另一个ReplicationController。
# 上面创建的rc匹配的label是xy.com.cn/app=kubia
kubectl get pods --show-labels
# 在rc管理的pod中添加其他label不影响rc
kubectl label pod xyrc01-tfspn xy.com.cn/type=result
# 修改标签xy.com.cn/app=kubia会将当前的pod移出rc的作用域,rc会创建新的pod保持副本数平衡。如下图
kubectl label pod xyrc01-xxkp4 xy.com.cn/app=bms --overwrite
更改ReplicationController 的标签选择器
如果修改了ReplicationController 的标签选择器,那会让原先所有的pod脱离ReplicationController的管理,然后ReplicationController 创建三个新的pod。
修改ReplicationController中的pod模板
ReplicationController的pod模板修改后不会影响到已创建的pod。只有先将旧的pod删除,ReplicationController才会根据新模板创建pod。
水平缩放pod
- 通过命令实现
kubectl scale rc xyrc01 --replicas=5
- 通过修改rc的副本数配置实现。
kubectl edit rc xyrc01
# 修改副本数
spec:
replicas: 5
删除rc
删除rc分两种情况:
- 连同管理的pod一起删除(默认)
kubectl delete rc xyrc01
- 只删除ReplicationController不删除管理的pod
kubectl delete rc xyrc01 --cascade=false
ReplicaSet
k8s引入了ReplicaSet并将完全代替ReplicationController。
我们实际不会直接创建ReplicaSet,而是创建更高层级的Deployment。
比较ReplicatSet和ReplicationController
- ReplicatSet和ReplicationController几乎完全相同。
- ReplicatSet有更具表达力的标签选择器。
- ReplicationController的标签选择器只允许包含某个标签的匹配pod。类比为查询条件:‘xy.com.cn/app=kubia’。
- ReplicatSet的标签选择器更复杂。
- 匹配缺少某个标签的pod。(类比为查询条件:xy.com.cn/app!=kubia)
- 匹配包含特定标签名的pod。(‘xy.com.cn/app=*’)
- 根据多个标签匹配。(‘xy.com.cn/app=kubia, xy.com.cn/type=result’)
ReplicaSet相关命令
创建ReplicatSet
yaml描述文件如下
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: xyreplicaset
spec:
# 副本数
replicas: 3
selector:
matchLabels:
xy.com.cn/app: kubia
# 模板与ReplicationController相同
template:
metadata:
labels:
xy.com.cn/app: kubia
spec:
containers:
- name: kubia
image: registry.cn-hangzhou.aliyuncs.com/xylearn/kubia:v1
ports:
- containerPort: 8080
注
创建ReplicatSet时不一定会创建pod,如果已存在满足labelSelector的pod,则会将其纳入管理,不创建新pod。
查询ReplicatSet
kubectl get rs
kubectl describe rs xyreplicaset
ReplicatSet的标签选择器
ReplicaSet相对于ReplicationController的主要改进是它更具表达力的标签选择器。如下:
可以给选择器添加额外的表达式。每个表达式都必须包含一个key,一个operator(运算符),并且可能还有一个values的列表(取决于运算符)。
operator有4种:
- In:Label的值必须与其中一个指定的values匹配。
- NotIn:Label的值与任何指定的values不匹配。
- Exists:pod必须包含一个指定名称的标签(值不重要)。此时不指定values字段。
- DoesNotExist:pod不得包含有指定名称的标签。values属性不指定。
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: myrs02
spec:
replicas: 3
# 标签选择器,筛选符合条件的pod
selector:
matchExpressions:
- key: xy.com.cn/app
operator: In
values:
- sky
- moon
# pod模板
template:
metadata:
# 创建新pod时,label应该要填的内容
labels:
xy.com.cn/app: sky
spec:
containers:
- name: kubia
image: registry.cn-hangzhou.aliyuncs.com/xylearn/kubia:v1
ports:
- containerPort: 8080
删除ReplicatSet
删除ReplicatSet会删除所有的pod
kubectl delete rs myrs02
DaemonSet
DaemonSet主要用于在集群的每个节点上都部署一个pod的场景。比如,日志收集器、资源监控器,这样的pod要求每个节点都要有,且只需要一个。
使用DaemonSet在每个节点上运行一个pod
- DaemonSet给每个节点创建一个pod
- 如果某个节点下线,DaemonSet不会在其他地方重新创建pod。
- 如果有一个新节点添加到集群中,DaemonSet会在新节点上创建一个新的pod。
- 手动删除一个DaemonSet的pod,DaemonSet会在原节点上重新创建一个pod。
使用DaemonSet只在特定的节点上运行pod
DaemonSet可以设置只在特定的符合条件的节点上部署pod。这个条件通过pod模板中的nodeSelector属性设置。
DaemonSet的相关命令
创建DaemonSet
yaml描述文件:ssd-monitor-daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: xyds01
namespace: default
spec:
# 标签选择器,筛选符合条件的pod
selector:
matchLabels:
xy.com.cn/devicetype: ssd
template:
# 创建新pod时,label应该要填的内容。这个label要符合上面的pod的标签选择器
metadata:
labels:
xy.com.cn/devicetype: ssd
spec:
# 标签选择器,筛选符合条件的node
nodeSelector:
disk: ssd
containers:
- name: main
image: registry.cn-hangzhou.aliyuncs.com/xylearn/kubia:v1
ports:
- containerPort: 8080
# 1. 在node中加上disk=ssd的标签
kubectl edit node kind-worker
# 2. 创建DaemonSet
kubectl create -f ssd-monitor-daemonset.yaml
# 查询,结果如下,可以看到集群中有一个节点符合条件,并创建了一个pod
kubectl get ds -n default
Job
目前为止,提到的资源都是创建持续运行的pod。即pod创建后处于一直运行的状态。但有时候,我们也会遇到创建的pod运行完任务后就终止的情况(比如一些训练机器学习模型的任务)。这种情况可以通过Job实现。
Job与上述的资源类似,但它允许你运行一种pod,该pod在内部进程执行任务成功并结束容器后,不重启容器。一旦任务完成,pod就被认为处于完成状态。
在执行任务期间,如果发生节点异常或pod被从节点中逐出,Job会自动创建新的pod执行任务。
Job的相关命令
创建Job
- yaml描述文件:pi-job.yaml。这个job的功能是计算π 到小数点后 2000 位,并将结果打印出来。 此计算大约需要 10 秒钟完成。
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
spec:
containers:
- name: pi
image: registry.cn-beijing.aliyuncs.com/google_registry/perl:5.26
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
# Job不能使用Always为默认的重新启动策略
restartPolicy: Never
backoffLimit: 4
- restartPolicy:指定什么情况下需要重启容器。有3个值:Always、OnFailure、Never。==对于 Job,只能设置为 Never 或者 OnFailure。==Never表示任何情况都不重启容器;OnFailure表示容器运行失败后会重启容器。
Job运行一个pod
用kubectl create命令创建上述作业后,可以看到它立即启动了一个pod
kubectl get job
kubectl get pods
刚创建的pod的状态是Running,过大约10s后,pod状态变为Completed
# 查看日志,可以看到pi的计算结果
kubectl logs -f pi-cn7bf
Job运行多个pod
顺序运行Job pod
如果需要一个Job运行多次,可以设置completions
apiVersion: batch/v1
kind: Job
metadata:
name: mult-completions-job
spec:
# 设置job运行的次数
completions: 5
template:
metadata:
labels:
xy.com.cn/app: pi
spec:
containers:
- name: pi
image: registry.cn-beijing.aliyuncs.com/google_registry/perl:5.26
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
# Job不能使用Always为默认的重新启动策略
restartPolicy: Never
backoffLimit: 4
Job将一个接一个地运行5个pod,只有前一个pod运行完成,才能运行下一个
并行运行Job pod
也可以并行运行Job,通过parallelism设置。如下
apiVersion: batch/v1
kind: Job
metadata:
name: mult-completions-job
spec:
# 设置job运行的次数
completions: 5
# 最多有2个pod并行运行
parallelism: 2
template:
metadata:
labels:
xy.com.cn/app: pi
spec:
containers:
- name: pi
image: registry.cn-beijing.aliyuncs.com/google_registry/perl:5.26
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
# Job不能使用Always为默认的重新启动策略
restartPolicy: Never
backoffLimit: 4
Job的并行运行数的缩放
parallelism属性可以在Job运行时更改。
kubectl scale job mult-completions-job --replicas 3
限制Job 的pod完成任务的时间和可重试次数
在pod配置中设置spec.activeDeadlineSeconds属性,可以限制pod的时间,单位是s。如果pod运行时间超过此时间,系统将尝试终止pod,并将Job标记为失败。
通过指定Job manifest中的spec.backoffLimit字段,可以配置Job在被标记为失败之前可以重试的次数。如果你没有明确指定它,则默认为6。
activeDeadlineSeconds的优先级高于backoffLimit。当pod执行时间超过activeDeadlineSeconds时,即使重试次数没到backoffLimit,job也会被标记失败。
apiVersion: batch/v1
kind: Job
metadata:
name: mult-completions-job
spec:
# 设置job运行的次数
completions: 5
parallelism: 2
template:
metadata:
labels:
xy.com.cn/app: pi
spec:
containers:
- name: pi
image: registry.cn-beijing.aliyuncs.com/google_registry/perl:5.26
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
# Job不能使用Always为默认的重新启动策略
restartPolicy: Never
# 在job被标记为失败之前可以重试的次数
backoffLimit: 4
# pod执行的超时时间
activeDeadlineSeconds: 100
CronJob
介绍CronJob
k8s可以定时或在指定的时间间隔内重复运行任务。这些任务通常被称为cron任务。k8s通过CronJob实现。运行任务的时间表以cron格式指定。
创建CronJob
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: batch-job-every-fifteen-minutes
spec:
# 这里表示:每小时的第0,15,30,45分运行
schedule: "0,15,30,45 * * * *"
# CronJob通过CronJob规范中配置的jobTemplate属性创建任务资源。
jobTemplate:
spec:
template:
metadata:
labels:
app: periodic-batch-job
spec:
restartPolicy: OnFailure
containers:
- name: main
image: luksa/batch-job
配置Cron
# cron表格式:分钟 时 每月中的第几天 月 星期
schedule: "0,15,30,45 * * * *"
了解计划运行的运行方式
在计划的时间内,CronJob资源会创建Job资源,然后job创建pod。所以可能发生Job或pod创建并运行得相对较晚的情况。
小结
- 存活探针:可以监测容器的健康状态,并在不健康的情况下重启它。
- 不应该直接创建pod,而是通过其他控制资源创建,防止误删和便于管理。
- ReplicationController:可以始终保持所需数量的pod副本处于运行状态。
- 通过修改ReplicationController的副本数,可以水平缩放pod。
- 实际不应该使用ReplicationController,应该用ReplicaSet和Deployment代替。
- ReplicationController、ReplicaSet通过标签选择器管理pod。
- ReplicationController和ReplicaSet将pod安排到随机集群节点,而DaemonSet确保每个节点都运行一个DaemonSet中定义的pod实例。
- Job:用于处理一次性任务,完成后容器就退出。
- CronJob:用于定时或在指定的时间间隔内重复运行任务。通过创建Job实现。
参考资料
- Kubernetes K8S之资源控制器Job和CronJob详解
https://cloud.tencent.com/developer/article/1718420
- 《Kubernetes in Action》