存活探针
Kubernetes可以通过存活探针(liveness probe)检查容器是否存活。如果探测失败,Kubernetes将定期执行探针并重新启动容器。
官方文档请见:https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
存活探针分为三种:
- exec:在容器内执行任意命令,并检查命令的退出状态码,为0则成功,否则失败。
- httpGet:执行http get请求,http code大于等于200并且小于400表示成功,否则失败。
- tcp:尝试与指定端口建立socket连接,建立成功则探测成功,否则失败。
exec探针
从官网复制个yaml,但是要将image从k8s.gcr.io/busybox更改为busybox。
-> [[email protected]] [~] cat exec-liveness.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
运行然后30秒后查看
-> [[email protected]] [~] k create -f exec-liveness.yaml
pod/liveness-exec created
-> [[email protected]] [~] k describe po liveness-exec
.......
Liveness: exec [cat /tmp/healthy] delay=5s timeout=1s period=5s #success=1 #failure=3
.......
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled default-scheduler Successfully assigned default/liveness-exec to kube1.vm
Normal Pulling kubelet, kube1.vm Pulling image "busybox"
Normal Pulled kubelet, kube1.vm Successfully pulled image "busybox"
Normal Created kubelet, kube1.vm Created container liveness
Normal Started kubelet, kube1.vm Started container liveness
Warning Unhealthy (x3 over ) kubelet, kube1.vm Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
Normal Killing kubelet, kube1.vm Container liveness failed liveness probe, will be restarted
前30秒,/tmp/healthy是存在的,探针返回成功。30秒后,因为/tmp/healthy不存在了,所以一直失败,直到失败3次后重启。
livenessProbe下的字段
这时候kubectl explain po.spec.containers.livenessProbe
就派上了用场。
- exec:exec探针配置
- httpGet:httpGet探针配置
- tcpSocket:tcpSocket探针配置
- initialDelaySeconds:初始延迟时间,在此时间内不进行探测,给程序预留启动时间。
- periodSeconds:探测周期,默认10s
- timeoutSeconds:超时时间,默认1s
- failureThreshold:被认为失活的最小连续失败次数,默认3次
- successThreshold:失败后被认为存活的最小连续成功次数,默认为1次。
这些参数在上面的kubectl describe
的结果中的Liveness字段有:
exec [cat /tmp/healthy] delay=5s timeout=1s period=5s #success=1 #failure=3
注意事项
- 一定要检查程序的内部,而没有外界因素影响。
例如,当服务器无法连接到数据库时,前端服务的探针不应返回失败。因为问题在数据库,重启前端服务也无法解决问题。 - 无须再探针中实现重试
- 探针要轻量
ReplicationController
ReplicationController是一种Kubernetes资源,可以确保他的pod始终处于运行状态。
ReplicationController描述文件分为三大部分:
- label selector(标签选择器):用于确定ReplicationController管理哪些pod
- replica count(副本个数):指定运行pod的数量
- pod template(pod模板):用于创建pod
ReplicationController的目的就是创建和管理若干个pod副本,它会持续监控正在运行的pod列表,保证标签选择器匹配的pod数量与副本个数一致。如果少于副本数量,就要根据pod模板创建新的副本;如果多余副本数量,就要删除多余的pod。
数量少的原因可能是:
- 增加了副本个数
- pod所在的工作节点出现故障
- pod的标签更改了,导致pod与ReplicationController的标签选择器不再匹配了。此时,如果它不被任何ReplicationController的标签选择器匹配,它就称为一个孤儿了。
数量多的原因可能是:
- 减少了副本个数
- 新建的pod与该ReplicationController的标签选择器匹配
- 已存在的pod标签修改后与该ReplicationController的标签选择器匹配
nginx-rc.yaml
API服务器会检查模板中的标签是否与selector匹配,如果不匹配是无法创建的。可以不指定selector,它会根据模板中的labels自动配置。
apiVersion: v1
kind: ReplicationController
metadata:
name: nginx-rc
spec:
replicas: 3 # 副本数量
selector: # pod选择器,决定RC的操作对象
app: nginx
template: # pod模板
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
使用ReplicationController
创建ReplicationController
-> [[email protected]] [~] k create -f nginx-rc.yaml
replicationcontroller/nginx-rc created
查看pod,确实新建了3个pod。
-> [[email protected]] [~] k get po --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx-rc-2c47w 0/1 ContainerCreating 0 5s app=nginx
nginx-rc-jrcl2 0/1 ContainerCreating 0 5s app=nginx
nginx-rc-qgchh 0/1 ContainerCreating 0 5s app=nginx
查看ReplicationController,rc是ReplicationController的简写。
-> [[email protected]] [~] k get rc
NAME DESIRED CURRENT READY AGE
nginx-rc 3 3 3 5m58s
查看详情
-> [[email protected]] [~] k describe rc nginx-rc
Name: nginx-rc
Namespace: default
Selector: app=nginx
Labels: app=nginx
Annotations:
Replicas: 3 current / 3 desired # 当前数量、期望数量
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed # 各种状态下的数量
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx
Port: 80/TCP
Host Port: 0/TCP
Environment:
Mounts:
Volumes:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 7m26s replication-controller Created pod: nginx-rc-2c47w
Normal SuccessfulCreate 7m26s replication-controller Created pod: nginx-rc-jrcl2
Normal SuccessfulCreate 7m26s replication-controller Created pod: nginx-rc-qgchh
可以搞一些破坏,比如更改、删除pod的标签,或者干脆删除pod。ReplicationController会因为当前数量与期望数量不符而创建新的副本。
控制器如何创建的pod
控制器通过创建一个新的副本代替被删除的副本时,它并没有对删除本身做出反应,而是针对由此产生的状态——副本数量不足做出反应。
虽然控制器会立即受到pod被删除的通知,但这并不是它创建新副本的原因。该通知会触发控制器检查实际的副本数量并采取相应措施。
kubectl edit
kubectl edit rc nginx-rc
可以在编辑器中打开nginx-rc的yaml配置,修改在保存后会立刻做出改变。
-> [[email protected]] [~] k edit rc nginx-rc
replicationcontroller/nginx-rc edited
通过KUBE_EDITOR环境变量可以指定用什么编辑器打开。
kubectl scale
可以使用kubectl scale
命令进行扩缩容。
-> [[email protected]] [~] k scale rc nginx-rc --replicas=6
replicationcontroller/nginx-rc scaled
以上操作会修改spec.replicas
字段,就像通过kubectl edit
修改一样。
删除ReplicationController
使用 kubectl delete 删除ReplicationController时,pod也会被删除。但由于pod是被ReplicationController创建的而不是它的组成部分,所以可以通过指定--cascade=false
而不删除pod。
注意事项
- pod永远不会被重新安置到另一个节点。
- 虽然一个pod没有绑定在ReplicationController上,但该pod在
metadata.ownerReferences
引用它。
ReplicaSet
ReplicationController最终将要被弃用,代替它的是ReplicaSet。它们的行为完全相同,但是ReplicaSet的选择器更具有表达力。
nginx-rs.yaml
让我们来看一个ReplicaSet的描述文件:
apiVersion: apps/v1 # api版本与ReplicationController不同
kind: ReplicaSet
metadata:
name: nginx-rs
spec:
replicas: 3
selector: # ReplicaSet的pod选择器有matchLabels和matchExpressions,与ReplicationController的是相似的,但更强大
matchLabels:
app: nginx
template: # 模板内容是一致的
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
主要区别在于pod选择器。ReplicaSet的创建于ReplicationController一样,缩写是rs,就不再赘叙了。
matchExpressions
上面描述文件的选择器使用matchExpressions可以改为:
selector:
matchExpressions:
- key: app
operator: In
values:
- nginx
每个表达式都必须包含key、operator(运算符),有可能包含values(取决于运算符),运算符有以下四种:
- In:Label的值必须与values中的一个相等
- NotIn:Label的值不能与values中的任何一个相等
- Exists:Pod必须包含一个指定名称的标签,values无所谓
- DoesNotExists:Pod不得包含指定名称的标签,values不能指定
DaemonSet
DaemonSet与ReplicaSet的不同在于,DaemonSet可以让pod在集群的每个节点上运行,有且只有一个。
如果节点下线,DaemonSet不会在其他地方重建pod;如果集群新加入了一个节点,DaemonSet会立刻部署一个新的pod。如果有人删除了pod,DaemonSet会建立一个新的。
这些pod通常用于执行系统级别或基础结构相关的工作,如日志收集和资源监控。典型的例子就是Kubernetes自己的kube-proxy。
如果想让DaemonSet只在特定节点运行pod,需要通过pod模板中的nodeSelector属性指定。
DaemonSet中没有期望副本数的概念,它不需要。因为它的工作是确保有一个匹配它选择器的pod在节点上运行。
nginx-ds.yaml
可能这里用继续用nginx作为例子不太恰当,但目前我们关注的重点是DaemonSet,继续吧。。。
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nginx-ds
spec: # 去掉了replicas,因为不需要
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
nodeSelector: # 添加了一个节点的标签选择器,选择只部署地区在在北京的节点上
region: "beijing"
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
创建DaemonSet
先给kube1.vm打个标签
-> [[email protected]] [~] k label node kube1.vm region=beijing
node/kube1.vm labeled
-> [[email protected]] [~] k get node -L region
NAME STATUS ROLES AGE VERSION REGION
kube0.vm Ready master 40h v1.17.3
kube1.vm Ready 40h v1.17.3 beijing
kube2.vm Ready 40h v1.17.3
提交描述文件
-> [[email protected]] [~] k create -f nginx-ds.yaml
daemonset.apps/nginx-ds created
-> [[email protected]] [~] k get ds,po -o wide
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR
daemonset.apps/nginx-ds 1 1 1 1 1 region=beijing 52s nginx nginx app=nginx
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/nginx-ds-5z95c 1/1 Running 0 52s 10.244.1.24 kube1.vm
给kube2.vm也打个标签
-> [[email protected]] [~] k label node kube2.vm region=beijing
node/kube2.vm labeled
-> [[email protected]] [~] k get ds,po -o wide
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR
daemonset.apps/nginx-ds 2 2 1 2 1 region=beijing 113s nginx nginx app=nginx
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/nginx-ds-5z95c 1/1 Running 0 113s 10.244.1.24 kube1.vm
pod/nginx-ds-b46lb 0/1 ContainerCreating 0 3s kube2.vm
Job
Job可以运行一种pod,在该pod内的进程成功结束时,不再重启。一旦任务完成,pod就被认为处于完成状态。
比如可以使用在将一些数据导出到其他地方,这个工作可能会持续几个小时。
我们基于busybox镜像,sleep一段时间用于模拟这个操作。
job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: job
spec:
template: # 没有指定selector,会根据pod标签中自动创建
metadata:
labels:
app: job
spec:
restartPolicy: OnFailure # 执行遇到异常则重启,默认为Always。
containers:
- name: sleepbusybox
image: busybox
command: ["/bin/sh","-c","sleep 60;echo this is busybox"]
restartPolicy表示pod的重启策略,默认Always,其他两项为OnFailure和Never。
运行查看
创建job
-> [[email protected]] [~] k create -f job.yaml
job.batch/job created
60秒内查看:
-> [[email protected]] [~] k get job,pod
NAME COMPLETIONS DURATION AGE
job.batch/job 0/1 14s 14s
NAME READY STATUS RESTARTS AGE
pod/job-4sfv4 1/1 Running 0 14s
60秒后查看:
-> [[email protected]] [~] k get job,pod
NAME COMPLETIONS DURATION AGE
job.batch/job 1/1 68s 71s
NAME READY STATUS RESTARTS AGE
pod/job-4sfv4 0/1 Completed 0 71s
使用jsonpath获取 pod name 查看log
-> [[email protected]] [~] k logs $(k get po --selector=app=job --output=jsonpath={.items..metadata.name})
this is busybox
completions与parallelism
job描述文件下的spec有两个字段:
- completions:job要确保完成多少个pod,默认为1。
- parallelism:最多并行运行多少个pod,默认为1。
job-batch.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: job-batch
spec:
completions: 5
parallelism: 2
template:
# 与job.yaml相同
activeDeadlineSeconds
job.spec.activeDeadlineSeconds
属性来限制Job在集群中的存活时间,超过此值,所有的pod都被终止。Job的status变为 type: Failed
,reason: DeadlineExceeded
CronJob
与Linux的crontab类似,使pod可以在特定时间运行,或者周期运行。
cronjob.yaml
这个描述文件是个套娃。。
CronJob包含job的模板,也就是jobTemplate;job里还包含pod的模板,也就是template。
schedule字段中的值是"分 小时 每月第几天 月份 星期几",详情请参考Linux crontab。
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: cron-job
spec:
schedule: "*/3 * * * * " # 每三分钟运行一次
jobTemplate: # job的模板
spec:
template: # pod的模板
metadata:
labels:
app: job-in-cron
spec:
restartPolicy: OnFailure
containers:
- name: sleepbusybox
image: busybox
command: ["/bin/sh","-c","sleep 60;echo this is busybox"]
运行
创建cron-job
-> [[email protected]] [~] k create -f cronjob.yaml
cronjob.batch/cron-job created
等了几分钟
-> [[email protected]] [~] k get all
NAME READY STATUS RESTARTS AGE
pod/cron-job-1590053040-pqhhh 0/1 Completed 0 97s
NAME COMPLETIONS DURATION AGE
job.batch/cron-job-1590053040 1/1 68s 97s
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
cronjob.batch/cron-job */3 * * * * False 0 105s 4m39s
又等了几分钟
-> [[email protected]] [~] k get all
NAME READY STATUS RESTARTS AGE
pod/cron-job-1590053040-pqhhh 0/1 Completed 0 3m4s
pod/cron-job-1590053220-whflp 0/1 ContainerCreating 0 3s
NAME COMPLETIONS DURATION AGE
job.batch/cron-job-1590053040 1/1 68s 3m4s
job.batch/cron-job-1590053220 0/1 3s 3s
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
cronjob.batch/cron-job */3 * * * * False 1 12s 6m6s
可以看到就当前的描述文件而言,cron-job每次创建一个job,job创建一个pod的运行。
startingDeadlineSeconds
cronjob.spec.startingDeadlineSeconds
规定pod必须预定时间之后的startingDeadlineSeconds秒内运行,超过此时间则不运行,并将其显示未Failed。
小结
- 使用存活探针检查容器是否存活。
- ReplicationController创建并管理Pod,但并不是绑定关系。它始终保持期望数量的副本正在运行。
- ReplicationController将被弃用,ReplicaSet拥有更强的标签选择器。
- DaemonSet会在每个节点上保持运行有且只有一个Pod,可以通过nodeSelector让其只在特定节点运行。
- Job创建Pod运行完成后,Pod为为
Completed
状态。completions与parallelism指定需要完成的数量与并行度。 - restartPolicy:默认Always,还有OnFailure、Never。
- CronJob创建Job,Job创建Pod。
- 命令:edit、scale