傲视Kubernetes(六):Pod管理及控制器
本文主要内容:
1、Kubernetes如何管理Pod?
2、Kubernetes Control Plane组件有哪几种?作用效果是什么?
一、Kubernetes如何管理Pod
Kubernetes中的Pod根据创建方式的不同,可以分为两种:一种是直接创建的Pod,比如自己写了一个Pod的yaml文件,通过kubectl create命令创建的Pod;一种是通过控制器,也就是Control Plane创建的Pod。
对于第一种Pod,也就是自己创建的Pod,创建完成之后由它所在的Node节点上的Kubelet管理。第二种Pod由控制器Control Plane管理。
Kubelet管理Pod
Kubelet管理Pod的手段很简单,就是重启大法。每个Pod创建时,都可以给配置存活探针,如下所示,创建Pod之后Kubernetes会每隔一段时间调用一次这个存活探针,也就是请求,如果执行失败或者没有响应,Kubelet则重启Pod
... spec: containers: - image:xxx livenessProbe: httpGet: / port: 8080
Kubernetes提供了三种探针类型,上面示例中的是httpGet(返回的状态码是2xx或3xx则会被认定成功),还有两种是TCP套接字探针和Exec探针。常用的一般都是HttpGet类型。
注意,如果不设置存活探针,kubelet只会根据容器进程是否存在来判断进程是否健康,也就是没有了健康检查应有的效果(因为比如OOM这样的异常发生时,JVM进程仍然运行),所以存活探针基本是一个必须的配置项。
在存活探针的配置项livenessProbe的同一级,还可以配置探针的其他属性,比如delay、timeout、period等,还有一个参数叫初始延迟initialDelaySeconds一般来说也需要配置上。如果不配置初始延迟参数,探针将在容器启动时就探测容器,这很容易失败,因为应用还没完成启动。配置这个参数就能有效避免这种情况的发生。
到此为止,都是在讲Pod出异常之后的重启处理,但如果Pod所在的Node节点出异常导致宕机呢?此时Node节点上的kubelet也就挂了,从而那些我们自己创建的依赖于Kubelet管理的Pod也就彻底GG了。
遇到这种情况该怎么办呢?这时候Kubernetes Control Plane就可以发挥作用了。
Control Plane管理Pod
Kubernetes的控制器,也就是Control Plane组件,有很多种,比如ReplicationController、ReplicationSet、DaemonSet、Job等。
在创建这些控制器的时候,会指定对应非副本数,控制器创建完成之后就会检测实际运行的pod数是否跟副本数一致,如果实际运行的少了(Pod出异常挂掉了或者Pod所在的节点挂了),控制器会根据配置的模板创建新的Pod;如果实际运行的多了,则会删掉多余的Pod。总之控制器会控制实际运行的Pod数与配置的副本数目一致。
当然,如果这些控制器所属Pod的探针存活检测异常,还是由Pod所在节点的kubelet来重启容器。即kubelet负责重启,控制器负责创建/删除。
二、Kubernetes Control Plane的组件有哪些?作用各是什么?
下面分别对五种Control Plane的作用进行说明,其实除此之外还有两种最常用的Deployment和StatefulSet,这两种会在后面着重学习。
1、ReplicationController
ReplicationController顾名思义,副本的控制器。它主要由三部分组成: 标签选择器(label selector)、副本个数(replica count)、pod模板(pod template)。ReplicationController的yaml配置示例如下:
apiVersion: v1 kind: ReplicationController metadata: name: kubia spec: replicas: 3 # 副本数 selector: # 标签选择器 app: kubia template: # pod模板 metadata: labels: app: kubia spec: containers: - name: kubia image: xxx/kubia port: - containerPort:8080
标签选择器用户查询并监控所有拥有这个标签的Pod;而副本数则用户控制跟标签选择器匹配上的Pod的数量;如果Pod数量少于副本数,则会按照Pod模板创建新的Pod。所以这里的标签选择器必须要与pod模板中的标签一致,当然也可以不指定标签选择器,此时会默认按照pod模板中的标签来选择。
从上面就可以知道很重要的一点:Kubernetes是通过标签与标签选择器实现的控制器与Pod的归属关系。
具体操作的指令如下,很多操作跟操作其他对象没什么差别:
kubectl create -f kubia-rc.yaml # 根据yaml文件创建ReplicationController kubectl get rc # 查看ReplicationController kubectl delete pod kubia-xxx # 删掉一个pod后再用get pod会看到正在创建新pod
kubectl delete rc kubia # 删除kubia这个rc,此时连它所对应的Pod也都会被删掉
kubectl delete rc kubia --cascade=false # 删除kubia这个rc,但它所对应的Pod会被保留下来 kubectl describe rc kubia # 查看ReplicationController的详细信息
kubectl label pod kubia-xxx app=kulet --overwrite # 改变pod的标签,此时rs会创建一个新Pod来达到3个的副本数
kubectl get pods -L app # 查看pod的标签
kubectl edit rc kubia # 进入修改名为kubia的rc的页面,修改后会立即生效,如果改了pod模板,只会对从此以后新创建的pod有效,不会影响已有pod
kubectl scale rc kubia --replicas=4 # 将副本数置为4,此时如果实际pod数少了则会新建
注意,如果是一个Node节点不可用导致的Pod失效,Kubernetes会等待一段时间(几分钟)来等待Node的恢复,如果几分钟后仍未恢复,才会创建新Pod来代替之前失效的Pod。
2、ReplicationSet
ReplicationSet是ReplicationController的升级版,前者rs拥有rc所有的功能,而且还有更富表达力的标签选择器,所以后者现在完全可以弃之不用。
ReplicationSet的yaml示例:
apiVersion: apps/v1beta2 kind: ReplicationSet metadata: name: kubia spec: replicas: 3 # 副本数 selector: # 标签选择器 matchLabels: app: kubia template: # pod模板 metadata: labels: app: kubia spec: containers: - name: kubia image: xxx/kubia port: - containerPort:8080
对比ReplicationController可以看到有两处有区别:一是apiVersion不再是v1了(此处的apps是api组,后面的v1beta2是实际的api版本),二是选择器那里中间又加了一级matchLabels。
上面所有对ReplicationController的指令都可以用于ReplicationSet,只需将rc替换为rs即可。
下面着重看看ReplicationSet对于标签选择器的升级:
1)、matchLabels
具体用法已经在上面的yaml示例中体现了,它的作用跟ReplicationController中的标签选择器相同,即完全匹配key和value(允许有其他的标签)。
2)matchExpressions
使用方式如下:
selector: matchExpressions: - key: app operator: In values: - kubia # 表示标签的值必须是kubia
matchExpressions下面必须有key和operator标签,而value标签有还是无取决于operator的值。operator有如下几种:
In: 此时需要有values标签,表示pod必须有与其中一个指定的values匹配的标签
NotIn:此时需要有values标签,表示pod必须的标签与任何指定的values不匹配
Exists:不需要values标签,表示pod必须包含指定key的标签,不关注value
DoesNotExist:不需要values标签,表示pod不得包含有指定key的标签
需要注意的是,selector下面可以指定多个标签表达式,即matchLabels和matchExpressions可以有一个也可以有多个也可以混合,此时这多个match的关系是与的关系,即都为true的pod才满足要求。一般不建议设置多个。
3、DaemonSet
该控制器可以达到一种效果,即在每个Node节点上创建一个Pod。如果Node有增加或减少,相应的Pod也增加减少。DaemonSet的yaml配置如下所示:
apiVersion: apps/v1beta2 kind: DaemonSet metadata: name: kubia-monitor spec: selector: # 标签选择器 matchLabels: app: kubia-monitor template: # pod模板 metadata: labels: app: kubia-monitor spec: nodeSelector: # 节点选择器 disk: ssd containers: - name: kubia-monitor image: xxx/kubia-monitor port: - containerPort:8080
可以看到,DaemonSet不需要设置副本数,因为每个Node节点只有一个Pod。在上面的配置中,还多了一个节点选择器nodeSelector,它是用于控制只在满足节点选择器的节点上创建Pod,即对节点做一个过滤。注意,DaemonSet对Pod的创建是绕过了调度器的,所以即使对节点设置了不可调度,只要满足DaemonSet的节点选择器,则仍然可以在上面创建一个Pod。
对DaemonSet的create、get、describe、delete等操作与其他控制器相同,就不在此赘述了,只需将对应的描述改成ds即可。
4、Job
上面介绍的三种控制器都是启动后一直运行的,而Job是用于执行一次性任务的,执行完之后就会被自动删掉。Job的yaml文件示例如下:
apiVersion: batch/v1 #Job属于batch API组,版本为v1 kind: Job metadata: name: kubia-job spec: template: # pod模板 metadata: labels: app: kubia-job spec: restartPolicy: OnFailure # 设置重启策略 containers: - name: main image: xxx/kubia-job port: - containerPort:8080
着重看一下重启策略 restartPolicy。重启策略一共有三种:Always(总是重启,即执行完成之后会再次启动,一直这样进行下去)、OnFailure(失败重启)、Never(不重启,即使执行失败)。一般来说只会用
后两者,不会用Always。
Job执行完之后,通过kubectl get pod是无法查看到它的,需要用 kubectl get pod -a ,状态是Completed。
Job还支持运行多次和并行执行,配置方式如下:
apiVersion: batch/v1 kind: Job metadata: name: kubia-job spec: completions: 5 parallelism: 2 template: # pod模板 ...
completions配置的数目,表示要执行多少次。如果未配置parallelism,则默认并行度是1,即同一时间只有一个Pod在运行,运行完这个Pod再创建第二个,一直运行完5个为止。
若如上所示,配置了parallelism=2,则同一时间会有两个Pod在运行,其中一个执行完之后再创建一个,一直执行完5个为止。
在Job运行时更改parallelism的指令:
kubectl scale job kubia-job --replicas=3
可以看到,跟扩容指令相同。
为应对异常情况,Job还有两个属性配置:
spec.activeDeadlineSeconds: 设置超时时间,Job实例运行时间超过这个配置时间,会被标记为失败,pod被终止运行。
spec.backoffLimit:重试次数,未配置时默认为6次。
5、CronJob
熟悉定时任务的,应该不难猜到,该类型的控制器用于精确控制Pod定期执行的。配置的yaml如下所示:
apiVersion: batch/v1beta1 kind: CronJob metadata: name: kubia-cronjob spec: schedule: "0,15,30,45 * * * *" startingDeadlineSeconds: 15 #表示如果离预定时间15s后还未启动Job,则本次任务不会执行 jobTemplate: metadata: labels: app: kubia-cronjob spec: restartPolicy: OnFailure # 设置重启策略 containers: - name: main image: xxx/kubia-cronjob port: - containerPort:8080
CronJob创建后,会在每个指定的cron表达式时间点创建一个新的Job。但有点坑的地方在于,它可能一下子创建两个Job,也可能一个不创建。所以需要在业务侧进行兼容,一方面是可以幂等,另一方面后面运行的任务需将前面未运行的任务未做的事情给做了。
本文到这里就结束了,下一节将一起学习Kubernetes中的服务。