K8S-资源控制器(RC、RS、Deployment、StatefulSet、DaemonSet、Job、Cronjob、HPA)
即如果有容器异常退出,会自动创建新的Pod来替代;而如果异常多出来的容器也会自动回收。在新版本的Kubernetes 中建议使用RepliicaSet来取代ReplicationControlle。
文章目录
资源控制器
Pod分为自主式Pod和控制器管理的Pod。类型:
- ReplicationController 和 ReplicaSet (无状态服务RS-Deployment)
- Deployment (一般推荐)
- DaemonSet(以Node为节点部署)
- Horizontal Pod Autoscaling (根据利用率平滑扩,可以理解为并不是一个控制器,而是一个控制器的附属品,以其他控制器作为模板)
- StateFulSet (有状态服务)
- Job/CronJob (批处理任务部署)
ReplicationController(RC)
ReplicationController用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的Pod来替代;而如果异常多出来的容器也会自动回收。在新版本的Kubernetes 中建议使用RepliicaSet来取代ReplicationControlle。
ReplicaSet(RS)
ReplicaSet跟ReplicationController没有本质的不同,只是名字不一样,并且ReplicaSet支持集合式的selector,通过标签(matchLabels)来管理 Pod。虽然ReplicaSet 可以独立使用,但一般还是建议使用Deployment 来自动管理ReplicaSet,这样就无需担心跟其他机制的不兼容问题(比如ReplicaSet不支持rolling update但Deployment 支持)。
apiVersion: apps/v1 #api版本定义
kind: ReplicaSet #定义资源类型为ReplicaSet
metadata: #元数据定义
name: frontend
namespace: default
spec: # ReplicaSet的规格定义
replicas: 3 #定义副本数量为3个
selector: #标签选择器,定义匹配Pod的标签
matchLabels: # RS通过labels来确定某个Pod是否归该RS管,即RS通过标签来监控Pod
tier: frontend
template: #Pod的模板定义,与上面Pod的定义一致
metadata: #Pod的元数据定义
name: myapp-pod #自定义Pod的名称
labels: #定义Pod的标签,需要和上面的标签选择器内匹配规则中定义的标签一致,可以多出其他标签
tier: frontend
spec: #Pod的规格定义
containers: #容器定义
- name: mynginx #容器名称
image: hub.zyx.com/library/nginx:v1 #容器镜像
imagePullPolicy: IfNotPresent #拉取镜像的规则
env:
- name: GET_HOSTS_FROM
value: dns
ports: #暴露端口
- name: http #端口名称
containerPort: 80
创建RS并查看:
# 创建 RS
[root@k8s-master01 yaml]# kubectl create -f rs.yaml
# 查看创建的 rs
[root@k8s-master01 yaml]# kubectl get rs
NAME DESIRED CURRENT READY AGE
frontend 3 3 3 23m
# 查看rs创建的 3 个 Pod,
[root@k8s-master01 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
frontend-cbxp2 1/1 Running 0 23m
frontend-qnfcd 1/1 Running 0 23m
frontend-qqngq 1/1 Running 0 23m
# 删除 Pod后,RS会自动重建 Pod,维持设置的副本数(3),通过 Pod 后的随机值可以看出,Pod是重新创建的
[root@k8s-master01 yaml]# kubectl delete pod --all
pod "frontend-cbxp2" deleted
pod "frontend-qnfcd" deleted
pod "frontend-qqngq" deleted
[root@k8s-master01 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
frontend-5lgj9 1/1 Running 0 14s
frontend-gxhrv 1/1 Running 0 14s
frontend-rwhc5 1/1 Running 0 14s
修改labels:
# 查看Pod的标签
[root@k8s-master01 yaml]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
frontend-5lgj9 1/1 Running 0 5m20s tier=frontend
frontend-gxhrv 1/1 Running 0 5m20s tier=frontend
frontend-rwhc5 1/1 Running 0 5m20s tier=frontend
# 修改其中一个Pod的标签
[root@k8s-master01 yaml]# kubectl label pod frontend-5lgj9 tier=abc --overwrite=true
pod/frontend-5lgj9 labeled
# RS会通过匹配 labels 来确定哪些 Pod 是自己管理的
# 当改变了 frontend-5lgj9 的 labels 时,该 Pod 已经不归 frontend 这个 RS 管了,所以 RS 又重新创建了一个Pod
[root@k8s-master01 yaml]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
frontend-5lgj9 1/1 Running 0 84m tier=abc
frontend-7fbp8 1/1 Running 0 4s tier=frontend
frontend-gxhrv 1/1 Running 0 84m tier=frontend
frontend-rwhc5 1/1 Running 0 84m tier=frontend
# 删除RS,Pod也会被删除
[root@k8s-master01 yaml]# kubectl delete rs frontend
[root@k8s-master01 yaml]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
frontend-5lgj9 1/1 Running 0 98m tier=abc
Deployment (一般推荐)
Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义 (declarative) 方法,用来替代以前的 ReplicationController 来方便的管理应用。典型的应用场景包括:
- 定义 Deployment 来创建 ReplicaSet和Pod
- 滚动升级和回滚应用
- 扩容和缩容
- 暂停和继续 Deployment
Deployment是通过管理RS来管理Pod的。
滚动更新:
更新V1到V2,新建个RS然后创建1个V2,删除1个V1:
直至:
达到滚动更新,此时RS,停用、保留,可以回滚:
创建并查看
apiVersion: apps/v1 #api版本定义
kind: Deployment #定义资源类型为Deploymant
metadata: #元数据定义
name: nginx-deployment #deployment控制器名称
namespace: default #名称空间
spec: #deployment控制器的规格定义
replicas: 3 #定义deployment副本数量为2个
selector: #标签选择器,定义匹配Pod的标签
matchLabels:
app: nginx-deployment
template: #Pod的模板定义
metadata: #Pod的元数据定义
labels: #定义Pod的标签,和上面的标签选择器标签一致,可以多出其他标签
app: nginx-deployment
spec: #Pod的规格定义
containers: #容器定义
- name: nginx #容器名称
image: hub.zyx.com/library/nginx:v1 #容器镜像
ports: #暴露端口
- name: http #端口名称
containerPort: 80
创建Deployment并查看:
# 创建Deployment对象
# --record 可以方便的查看 revision 的变化(roolout 被触发(spec.template被更改)就会创建一个 revision)
kubectl apply -f deployment.yaml --record
[root@k8s-master01 yaml]# kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 4m30s
[root@k8s-master01 yaml]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-645ccc47cc 3 3 3 4m32s
[root@k8s-master01 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-645ccc47cc-885sz 1/1 Running 0 4m37s
nginx-deployment-645ccc47cc-k5jcm 1/1 Running 0 4m37s
nginx-deployment-645ccc47cc-rwnk5 1/1 Running 0 4m37s
kubectl get deployment 命令所显示的字段有:
- NAME:Deployment 的名称。
- READY:显示应用程序的可用的副本数。显示的模式是“就绪个数/期望个数”。
- UP-TO-DATE:显示为了达到期望状态已经更新的副本数。
- AVAILABLE:显示应用可供用户使用的副本数。
- AGE:显示应用程序运行的时间。
扩容
kubectl scale deployment nginx-deployment --replicas=5
更新
修改 Pod
模板相关的配置参数便能完成 Deployment
控制器资源的更新。
由于是声明式配置,因此对 Deployment
控制器资源的修改尤其适合使用 apply
和 patch
命令来进行;如果仅只是修改容器镜像,set image
命令更为易用。
更新容器的镜像:kubectl set image deployment/[deployment名称] [容器名称]=[镜像名称]
kubectl set image deployment/nginx-deployment nginx=wangyanglinux/myapp:v2
# 可以看到原来的 RS 已经停用并做为备份,并创建了新的 RS
[root@k8s-master01 yaml]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-645ccc47cc 0 0 0 3h45m
nginx-deployment-6c67f64d64 5 5 4 8s
回滚
可以通过设置 .spec.revisonHistoryLimit
项来指定 deployment
最多保留多少 revision
历史记录。默认的会保留所有的 revision
;如果将该项设置为 0
,Deployment
就不允许回退了
# 回到上一个版本
kubectl rollout undo deployment/nginx-deployment
# 查看当前的更新状态
# 如果 rollout 成功完成, 该命令将返回一个 0 值的 Exit Code
kubectl rollout status deployments/nginx-deployment
# echo $? # 输出 0
# 查看当前版本(自定义 Pod 的输出)
kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
# 通过该命令查看更新历史记录,Pod 模板被修改就会创建一个 revision
kubectl rollout history deployment/nginx-deploy
# 查询结果,创建 Deployment 时加上 --record 才会显示CHANGE-CAUSE
# REVISION CHANGE-CAUSE
# 1 kubectl apply --filename=deployment.yaml --record=true
# 2 kubectl apply --filename=deployment.yaml --record=true
# 回滚到指定版本
kubectl rollout undo deployment/nginx-deployment --to-revision=1
# 暂停 deployment 的更新
kubectl rollout pause deployment/nginx-deployment
更新策略
- Deployment 可确保在更新时仅关闭一定数量的 Pod。默认情况下,它确保至少所需 Pods 75% 处于运行状态(最大不可用比例为 25%)。
- Deployment 还确保创建 Pod 数量只可能比期望 Pods 数高一点点。 默认情况下,它可确保启动的 Pod 个数比期望个数最多多出 25%(最大峰值 25%)。
- 如果旧的 Pod 创建还没有达到期望数时(如期望数是 5,但现在只创建了3个),就更新了 Pod。在这种情况下,Deployment 会立即杀掉已创建的旧 Pod,并开始创建新 Pod。它不会等到所有的旧 Pod 都创建完成后才开始创建新 Pod。
例如,如果仔细查看上述 Deployment (kubectl describe deployment),将看到它首先创建了一些新的 Pod,然后删除了一些旧的 Pods。并且创建新的 Pods 创建没有到达 25% ,它不会杀死老 Pods,直到有足够的数量新的 Pods 已经出现。 然后开始杀死老 Pods ,在足够数量的旧 Pods 被杀死前并没有创建新 Pods。它确保至少 4 个 Pod 可用,同时最多总共 7 个 Pod 可用。
Horizontal Pod Autoscaling(HPA)
HPA根据利用率平滑扩展,仅适用于Deployment 和ReplicaSet ,在V1版本中仅支持根据Pod的CPU利用率扩所容,在vlalpha 版本中,支持根据内存和用户自定义的metric扩缩容。
HPA基于RS定义,并且监控V2Pod的资源利用率:
当符合条件后,会创建Pod:
每次创建后判断条件,符合后继续创建,直到最大值。使用率小就回收,直到最小值,实现水平自动扩展(弹性伸缩)。
在后面的组件Prometheus中会有创建。
StatefulSet
StatefulSet是为了解决有状态服务的问题(对应Deployments 和Repl icaSets是为无状态服务而设计),其应用场景包括:
- 稳定的持久化存储,即Pod重新调度(比如删除后重新创建)后还是能访问到相同的持久化数据,基于PVC来实现
- 稳定的网络标志,即Pod重新调度后其PodName 和HostName 不变,基于Headless Service(即没有Cluster IP的Service )来实现
- 有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候**要依据定义的顺序依次依次进行(**即从0到N-1,在下一个Pod运行之前所有之前的Pod必须都是Running 和Ready状态),基于init containers来实现
- 有序收缩,有序删除(即从N-1到0)
部署顺序和收缩顺序是相反的。
一个完整的 StatefulSet 应用由三个部分组成: headless service(无头服务)、StatefulSet controller、volumeClaimTemplate(PVC)。
- Headless Service:用来定义 Pod 网络标识( DNS domain);
- volumeClaimTemplates :存储卷申请模板,创建 PVC,指定 pvc 名称大小,将自动创建 pvc,且 pvc 必须由存储类供应;
- StatefulSet :定义具体应用,名为 Nginx,有三个 Pod 副本,并为每个 Pod 定义了一个域名部署 statefulset。
为什么需要 headless service 无头服务?
在用 Deployment 时,每一个 Pod 名称是没有顺序的,是随机字符串,因此是 Pod 名称是无序的,但是在 statefulset 中要求必须是有序 ,每一个 pod 不能被随意取代,pod 重建后 pod 名称还是一样的。而 pod IP 是变化的,所以是以 Pod 名称来识别。pod 名称是 pod 唯一性的标识符,必须持久稳定有效。这时候要用到无头服务,它可以给每个 Pod 一个唯一的名称 。
除此之外,StatefulSet 在 Headless Service 的基础上又为 StatefulSet 控制的每个 Pod 副本创建了一个 DNS 域名,这个域名的格式为:
$(podname).(headless server name)
FQDN:$(podname).(headless server name).namespace.svc.cluster.local
为什么需要 volumeClaimTemplate?
对于有状态的副本集都会用到持久存储,对于分布式系统来讲,它的最大特点是数据是不一样的,所以各个节点不能使用同一存储卷,每个节点有自已的专用存储,但是如果在 Deployment 中的 Pod template 里定义的存储卷,是所有副本集共用一个存储卷,数据是相同的,因为是基于模板来的;而 statefulset 中每个 Pod 都要自已的专有存储卷,所以 statefulset 的存储卷就不能再用 Pod 模板来创建了,于是 statefulSet 使用 volumeClaimTemplate,称为卷申请模板,它会为每个 Pod 生成不同的 pvc,并绑定 pv,从而实现各 pod 有专用存储。这就是为什么要用 volumeClaimTemplate 的原因。
# headless service
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None # 通过指定 clusterIP 为 None 实现 headless service
selector:
app: nginx # (A) A,B,C 三处要相同,根据 label 来匹配哪些 pod 归无头服务管
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx # (B) A,B,C 三处要相同,根据 label 匹配决定哪些 pod 归StatefulSet管
serviceName: "nginx" # 指定 Service 名称(上面创建的,一定要是个无头服务)
replicas: 3 # 副本数
template:
metadata:
labels:
app: nginx # (C) A,B,C 三处要相同,label标签
spec:
containers: # 容器信息
- name: nginx
image: wangyanglinux/myapp:v2
ports:
- containerPort: 80 # 释放的端口
name: web # 端口名字
volumeMounts: # 挂载
- name: www
mountPath: /usr/share/nginx/html # 容器内目录
volumeClaimTemplates: # 卷请求声明模板(pvc模板)
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ] # 指定要请求的卷的访问模式
storageClassName: "nfs" # 指定要请求的卷的类名,只有与 PV 中的storageClassName 相同时,才会匹配
resources:
requests:
storage: 1Gi # 指定要请求的卷大小必须满足 1G
在PVC中会详细介绍。
DaemonSet
DaemonSet确保全部(或者一些) Node上运行一个Pod的副本(同一个 Node 上运行多个 Pod 需要多个 DaemonSet)。当有Node加入集群时,也会为他们新增一个Pod。当有Node从集群移除时,这些Pod也会被回收。删除DaemonSet 将会删除它创建的所有Pod。使用DaemonSet的–些典型用法:
- 运行集群存储daemon, 例如在每个Node上运行glusterd、 ceph;
- 在每个Node上运行日志收集daemon, 例如fluentd、 logstash;
- 在每个Node上运行监控daemon, 例如Prometheus Node Exporter。
apiVersion: apps/v1 #api版本定义
kind: DaemonSet #定义资源类型为DaemonSet
metadata: #元数据定义
name: daemonset-nginx #daemonset控制器名称
namespace: default #名称空间
labels: #设置daemonset的标签
app: daemonset
spec: #DaemonSet控制器的规格定义
selector: #指定匹配pod的标签
matchLabels: #指定匹配pod的标签
app: daemonset-nginx #注意:这里需要和template中定义的标签一样
template: #Pod的模板定义
metadata: #Pod的元数据定义
name: nginx
labels: #定义Pod的标签,需要和上面的标签一致,可以多出其他标签
app: daemonset-nginx
spec: #Pod的规格定义
containers: #容器定义
- name: nginx-pod #容器名字
image: hub.zyx.com/library/nginx:v1 #容器镜像
ports: #暴露端口
- name: http #端口名称
containerPort: 80 #暴露的端口
可以看到两个节点上各运行一个:
[root@k8s-master01 yaml]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
daemonset-nginx-js4tc 1/1 Running 0 82s 10.244.1.21 k8s-node01 <none> <none>
daemonset-nginx-kkc5q 1/1 Running 0 9s 10.244.2.21 k8s-node02 <none> <none>
Job
job负责一次性的批处理任务,即仅执行一次的任务,他保证批处理任务的一个或者多个Pod成功结束。(比如要备份数据库,备份代码可以放到统一Pod里,再放到Job里执行,与Linux直接运行不同点是是封装好的Job可以重复利用,并且脚本执行异常退出可以重复执行,并且可以设置正常退出次数才算Job执行成功)
随着 Pod 成功结束,Job 跟踪记录成功完成的 Pod 个数。 当数量达到指定的成功个数阈值时,任务(即 Job)结束。如 删除 Job ,会清除所创建的全部 Pod。 挂起 Job 的操作会删除 Job 的所有活跃 Pod,直到 Job 被再次恢复执行。
apiVersion: batch/v1 # kubectl explain job 查看 job 版本
kind: Job
metadata:
name: pi
spec:
template:
metadata:
name: pi
spec:
containers:
- name: pi
image: perl
command: ["perl","-Mbignum=bpi","-wle","print bpi(2000)"] # 通过 perl 进行圆周率计算,输出小数点后2000位
restartPolicy: Never # 重启策略
- spec.template 格式同 Pod
- 容器的 restartPolicy 仅支持 Never 或 OnFailure,因为 Job 就是批处理任务,执行完自动退出,如果是 Always,那么就会不断的执行
- 单个 Pod 时,默认 Pod 成功运行后(返回码为 0) Job 即结束
spec.completions:标志Job结束需要成功运行的 Pod 个数,默认为 1
spec.parallelism:标志并行运行的 Pod 的个数,默认为 1
spec.activeDeadlineSeconds:标志失败 Pod 的重试最大时间,超过这个时间不会继续重试
Cronjob
Cronjob管理基于时间的Job,即在给定时间点运行一次或周期性地在给定时间点运行Job。
- 在给定的时间点调度 Job 运行
- 创建周期性运行的 Job,例如:数据库备份、发送邮件
创建 Job 操作应该是 幂等的。CronJob 仅负责创建与其调度时间相匹配的 Job,而 Job 又负责管理其代表的 Pod。
CronJob Spec
-
spec.schedule:调度,必需字段,指定任务运行周期,格式同 Cron
-
spec.jobTemplate:Job 模板,必需字段,指定需要运行的任务,格式同 Job
-
spec.startingDeadlineSeconds:启动 Job 的期限(秒级别),该字段是可选的。如果因为任何原因而错过了被调度的时间,那么错过执行时间的 Job 将被认为是失败的。如果没有指定,则没有期限
-
spec.concurrencyPolicy:并发策略,该字段也是可选的。它指定了如何处理被 Cron Job 创建的 Job 的并发执行。只允许指定下面策略中的一种:
- Allow (默认):允许并发运行 Job
- Forbid :禁止并发运行,如果前一个还没有完成,则直接跳过下一个
- Replace :取消当前正在运行的 Job,用一个新的来替换
注意:当前策略只能应用于同一个 Cron Job 创建的 Job。如果存在多个 Cron Job,它们创建的 Job 之间总是允许并发运行。
-
spec.suspend:挂起,该字段也是可选的。如果设置为 true ,后续所有执行都会被挂起。它对已经开始执行的 Job 不起作用。默认值为 false 。
-
spec.successfulJobsHistoryLimit 和 .spec.failedJobsHistoryLimit:历史限制,是可选的字段。它们指定了可以保留多少完成和失败的 Job。默认情况下,它们分别设置为 3 和 1 。设置限制的值为 0 ,相关类型的 Job 完成后将不会被保留。
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
args: # 运行命令,输出当前时间
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure
[root@k8s-master01 yaml]# kubectl get cronjob
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
hello */1 * * * * False 0 <none> 29s
[root@k8s-master01 yaml]# kubectl get job
NAME COMPLETIONS DURATION AGE
hello-1603320660 1/1 108s 2m4s
hello-1603320720 0/1 64s 64s
hello-1603320780 0/1 4s 4s
# 删除 CronJob
kubectl delete deployment/nginx-deployment
更多推荐
所有评论(0)