kubernetes的五种控制器
k8s的控制器类型
Kubernetes中内建了很多controller(控制器),这些相当于一个状态机,用来控制Pod的具体状态和行为
- Deployment:适合无状态的服务部署
- StatefullSet:适合有状态的服务部署
- DaemonSet:一次部署,所有的node节点都会部署,例如一些典型的应用场景:
运行集群存储 daemon,例如在每个Node上运行 glusterd、ceph
在每个Node上运行日志收集 daemon,例如 fluentd、 logstash
在每个Node上运行监控 daemon,例如 Prometheus Node Exporter - Job:一次性的执行任务
- Cronjob:周期性的执行任务
Deployment控制器
Deployment概述
Deployment对象,顾名思义,是用于部署应用的对象。它使Kubernetes中最常用的一个对象,它为ReplicaSet和Pod的创建提供了一种声明式的定义方法,从而无需像前两篇文章中那样手动创建ReplicaSet和Pod对象(使用Deployment而不直接创建ReplicaSet是因为Deployment对象拥有许多ReplicaSet没有的特性,例如滚动升级和回滚)。
通过Deployment对象,你可以轻松的做到以下事情:
- 创建ReplicaSet和Pod
- 滚动升级(不停止旧服务的状态下升级)和回滚应用(将应用回滚到之前的版本)
- 平滑地扩容和缩容
- 暂停和继续Deployment
Deployment的创建
以下列的deploy.yml文件为例,使用以下命令创建一个nginx的Deployment:
[root@master ~]# vi deploy.yml
[root@master ~]# cat deploy.yml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
[root@master ~]# kubectl create -f deploy.yml --record
Flag --record has been deprecated, --record will be removed in the future
deployment.apps/nginx-deployment created
--record
参数可以记录当前版本的Deployment都执行过哪些命令。
创建完成后立即执行get命令可以查看这个Deployment:
[root@master ~]# kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 2m14s
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-74d589986c-kxcvx 1/1 Running 0 2m11s
nginx-deployment-74d589986c-s277p 1/1 Running 0 2m11s
nginx-deployment-74d589986c-zlf8v 1/1 Running 0 2m11s
NAME
代表Deployment的名字,DESIRED
代表这个Deployment期望的副本数量,CURRENT
代表当前已经创建了的副本数量,UP-TO-DATE
代表已经更新完成的副本数量,AVAILABLE
代表对于当前用户可用的副本数量,AGE
代表当前Deployment已经运行的时长。
等待几秒钟,再次运行get命令,可以查看到变化:
[root@master ~]# kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 3m4s
通过kubectl get rs来查看系统中ReplicaSet对象,由此可以看出Deployment会自动创建一个ReplicaSet对象。
[root@master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-74d589986c 3 3 3 4m29s
通过kubectl get pods --show-labels命令来查看当前系统中的Pod对象,可以成功观察到nginx-deployment创建的3个Pod。
[root@master ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx-deployment-74d589986c-kxcvx 1/1 Running 0 3m55s app=nginx,pod-template-hash=74d589986c
nginx-deployment-74d589986c-s277p 1/1 Running 0 3m55s app=nginx,pod-template-hash=74d589986c
nginx-deployment-74d589986c-zlf8v 1/1 Running 0 3m55s app=nginx,pod-template-hash=74d589986c
Deployment的更新
假如我们现在想要让 nginx pod 使用 nginx:1.9.1 的镜像来代替原来的 nginx的镜像,运行以下命令:
[root@master ~]# kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
deployment.apps/nginx-deployment image updated
或者我们可以使用 edit 命令来编辑 Deployment,将image从nginx改写成 nginx:1.9.1。
kubectl edit deployment/nginx-deployment
查看更新进度:
[root@master ~]# kubectl rollout status deployment/nginx-deployment
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
deployment "nginx-deployment" successfully rolled out
Deployment更新时会创建一个新的ReplicaSet,然后将新的ReplicaSet中的Pod慢慢扩容到指定的副本数,将旧的ReplicaSet慢慢缩容到0。因此,更新时总能够确保旧的服务不会停止,这就是滚动更新。
Deployment的回滚
当我们像上文一样更新了Deployment之后,我们发现nginx:1.9.1的镜像不是很稳定,因此想要修改回nginx:1.7.9的版本,此时我们不需要手动更改Deployment文件,而是利用Deployment的回滚功能。
使用rollout history命令查看Deployment的版本(revision):
[root@master ~]# kubectl rollout history deployment/nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
1 kubectl create --filename=deploy.yml --record=true
2 kubectl create --filename=deploy.yml --record=true
因为我们创建 Deployment 的时候使用了 —recored 参数可以记录命令,我们可以很方便的查看每次 revison 的变化。
查看单个 revision 的详细信息:
[root@master ~]# kubectl rollout history deployment/nginx-deployment --revision=2
deployment.apps/nginx-deployment with revision #2
Pod Template:
Labels: app=nginx
pod-template-hash=658d7f4b4b
Annotations: kubernetes.io/change-cause: kubectl create --filename=deploy.yml --record=true
Containers:
nginx:
Image: nginx:1.9.1
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
现在,可以使用rollout undo命令回滚到前一个revision:
[root@master ~]# kubectl rollout undo deployment/nginx-deployment
deployment.apps/nginx-deployment rolled back
[root@master ~]# kubectl describe deployment/nginx-deployment
Name: nginx-deployment
Namespace: default
CreationTimestamp: Fri, 24 Dec 2021 22:24:10 +0800
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 3
kubernetes.io/change-cause: kubectl create --filename=deploy.yml --record=true
Selector: app=nginx
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
也可以使用–to-revision参数指定某个历史版本:
[root@master ~]# kubectl rollout undo deployment/nginx-deployment --to-revision=2
deployment.apps/nginx-deployment rolled back
[root@master ~]# kubectl describe deployment/nginx-deployment
Name: nginx-deployment
Namespace: default
CreationTimestamp: Fri, 24 Dec 2021 22:24:10 +0800
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 4
kubernetes.io/change-cause: kubectl create --filename=deploy.yml --record=true
Selector: app=nginx
Replicas: 3 desired | 3 updated | 4 total | 3 available | 1 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.9.1
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
你可以通过设置 .spec.revisonHistoryLimit 项来指定 deployment 最多保留多少 revison 历史记录。默认的会保留所有的 revision;如果将该项设置为 0,Deployment 就不允许回退了。
只有 Deployment 的 rollout 被触发才会创建一个 revision!注意!当且仅当 Deployment 的 Pod template被更改,例如更新 template 中的 label 和容器镜像时,才会触发一个rollout,从而为Deployment创建出一个新的 revision。
rollout
命令的更多用法:
- history(查看历史版本)
- pause(暂停Deployment)
- resume(恢复暂停的Deployment)
- status(查看资源状态)
- undo(回滚版本)
Replicaset控制器
Replicaset概述
ReplicaSet是kubernetes中的一种副本控制器,简称rs,主要作用是控制由其管理的pod,使pod副本的数量始终维持在预设的个数。它的主要作用就是保证一定数量的Pod能够在集群中正常运行,它会持续监听这些Pod的运行状态,在Pod发生故障时重启pod,pod数量减少时重新运行新的 Pod副本。官方推荐不要直接使用ReplicaSet,用Deployments取而代之,Deployments是比ReplicaSet更高级的概念,它会管理ReplicaSet并提供很多其它有用的特性,最重要的是Deployments支持声明式更新,声明式更新的好处是不会丢失历史变更。所以Deployment控制器不直接管理Pod对象,而是由 Deployment 管理ReplicaSet,再由ReplicaSet负责管理Pod对象。
Replicaset工作原理
Replicaset核心作用在于用户创建指定数量的pod副本,并确保pod副本一直处于满足用户期望的数量, 起到多退少补的作用,并且还具有自动扩容缩容等制。
Replicaset控制器主要由三个部分组成:
- 用户期望的pod副本数:用来定义由这个控制器管控的pod副本有几个
- 标签选择器:选定哪些pod是自己管理的,如果通过标签选择器选到的pod副本数量少于我们指定的数量,需要用到下面的组件
- pod资源模板:如果集群中现存的pod数量不够我们定义的副本中期望的数量怎么办,需要新建pod,这就需要pod模板,新建的pod是基于模板来创建的。
Replicaset使用案例
#编写一个ReplicaSet资源清单
[root@k8s-master1 ~]# cat replicaset.yml
---
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: nginx
tier: frontend
spec:
replicas: 3
selector:
matchLabels:
tier: frontend
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
[root@master ~]# kubectl apply -f replicaset.yaml
replicaset.apps/frontend created
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
frontend-7rrp6 1/1 Running 0 9s
frontend-drmcf 1/1 Running 0 9s
frontend-qnlz6 1/1 Running 0 9s
[root@master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
frontend 3 3 3 41s
DaemonSet控制器
DaemonSet 简介
DaemonSet:服务守护进程,它的主要作用是在Kubernetes集群的所有节点中运行我们部署的守护进程,相当于在集群节点上分别部署Pod副本,如果有新节点加入集群,Daemonset会自动的在该节点上运行我们需要部署的Pod副本,相反如果有节点退出集群,Daemonset也会移除掉部署在旧节点的Pod副本。
DaemonSet的主要特征
- 这个 Pod 运行在 Kubernetes 集群里的每一个节点(Node)上;
- 每个节点上只会运行一个这样的 Pod 实例;
- 如果新的节点加入 Kubernetes 集群后,该 Pod 会自动地在新节点上被创建出来;
- 而当旧节点被删除后,它上面的 Pod 也相应地会被回收掉。
Daemon Pods的调度特性
默认情况下,Pod被分配到具体哪一台Node上运行是由Scheduler(负责分配调度Pod到集群内的Node上,它通过监听ApiServer,查询还未分配Node的Pod,然后根据调度策略为这些Pod分配Node)决定的。但是,DaemonSet对象创建的Pod却拥有一些特殊的特性:
- Node的
unschedulable
属性会被DaemonSet Controller忽略。 - 即使Scheduler还未启动,DaemonSet Controller也能够创建并运行Pod。
Daemon Pods支持taints and tolerations, 但是这些Pods在创建时就默认容忍下列effect为NoExecute的taints(未设置tolerationSeconds):
Toleration Key | Effect | Version | Description |
---|---|---|---|
node.kubernetes.io/not-ready | NoExecute | 1.13+ | DaemonSet pods will not be evicted when there are node problems such as a network partition. |
node.kubernetes.io/unreachable | NoExecute | 1.13+ | DaemonSet pods will not be evicted when there are node problems such as a network partition. |
node.kubernetes.io/disk-pressure | NoSchedule | 1.8+ | … |
node.kubernetes.io/memory-pressure | NoSchedule | 1.8+ | … |
node.kubernetes.io/unschedulable | NoSchedule | 1.12+ | DaemonSet pods tolerate unschedulable attributes by default scheduler. |
node.kubernetes.io/network-unavailable | NoSchedule | 1.12+ | DaemonSet pods, who uses host network, tolerate network-unavailable attributes by default scheduler. |
DaemonSet常用场景
- 网络插件的 Agent 组件,如(Flannel,Calico)需要运行在每一个节点上,用来处理这个节点上的容器网络;
- 存储插件的 Agent 组件,如(Ceph,Glusterfs)需要运行在每一个节点上,用来在这个节点上挂载F远程存储目录;
- 监控系统的数据收集组件,如(Prometheus Node Exporter,Cadvisor)需要运行在每一个节点上,负责这个节点上的监控信息搜集。
- 日志系统的数据收集组件,如(Fluent,Logstash)需要运行在每一个节点上,负责这个节点上的日志信息搜集。
创建一个DaemonSet对象
下面的描述文件创建了一个运行着nginx镜像的DaemonSet对象:
[root@master kubenetres]# vi daemonset.yml
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
labels:
app: fluentd-logging
spec:
selector:
matchLabels:
name: fluentd-elasticsearch
template:
metadata:
labels:
name: fluentd-elasticsearch
spec:
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
containers:
- name: fluentd-elasticsearch
image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
[root@master ~]# kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-6d8c4cb4d-6n2xc 1/1 Running 2 (53m ago) 3d1h
coredns-6d8c4cb4d-hjznw 1/1 Running 2 (53m ago) 3d1h
etcd-master.example.com 1/1 Running 8 (53m ago) 3d1h
fluentd-elasticsearch-6sgnt 1/1 Running 0 44s
fluentd-elasticsearch-chfhc 1/1 Running 0 42s
kube-apiserver-master.example.com 1/1 Running 9 (53m ago) 3d1h
kube-controller-manager-master.example.com 1/1 Running 8 (53m ago) 3d1h
kube-flannel-ds-67kht 1/1 Running 3 (53m ago) 3d1h
kube-flannel-ds-hr47p 1/1 Running 2 (53m ago) 3d1h
kube-flannel-ds-k678m 1/1 Running 2 (53m ago) 3d1h
kube-proxy-44zx6 1/1 Running 2 (53m ago) 3d1h
kube-proxy-knkbm 1/1 Running 2 (53m ago) 3d1h
kube-proxy-n875j 1/1 Running 3 (53m ago) 3d1h
kube-scheduler-master.example.com 1/1 Running 8 (53m ago) 3d1h
Job控制器
Job Controller
Job Controller负责根据Job Spec创建Pod,并持续监控Pod的状态,直至其成功结束。如果失败,则根据restartPolicy(只支持OnFailure和Never,不支持Always)决定是否创建新的Pod再次重试任务。
Job负责批量处理短暂的一次性任务 (short lived one-off tasks),即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束。
Kubernetes支持以下几种Job:
- 非并行Job:通常创建一个Pod直至其成功结束
- 固定结束次数的Job:设置.spec.completions,创建多个Pod,直到.spec.completions个Pod成功结束
- 带有工作队列的并行Job:设置.spec.Parallelism但不设置.spec.completions,当所有Pod结束并且至少一个成功时,Job就认为是成功
根据.spec.completions和.spec.Parallelism的设置,可以将Job划分为以下几种pattern:
Job类型 | 使用示例 | 行为 | completions | Parallelism |
---|---|---|---|---|
一次性Job | 数据库迁移 | 创建一个Pod直至其成功结束 | 1 | 1 |
固定结束次数的Job | 处理工作队列的Pod | 依次创建一个Pod运行直至completions个成功结束 | 2+ | 1 |
固定结束次数的并行Job | 多个Pod同时处理工作队列 | 依次创建多个Pod运行直至completions个成功结束 | 2+ | 2+ |
并行Job | 多个Pod同时处理工作队列 | 创建一个或多个Pod直至有一个成功结束 | 1 | 2+ |
job的使用
[root@master ~]# vi job.yml
---
apiVersion: batch/v1
kind: Job
metadata:
name: myjob
spec:
template:
spec:
containers:
- name: myjob
image: busybox
command: ["echo", "hello k8s job"]
restartPolicy: Never
[root@master ~]# kubectl apply -f job.yml
job.batch/myjob created
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myjob-gq27p 0/1 Completed 0 37s
#查看这个 pod的任务
[root@master ~]# kubectl get job
NAME COMPLETIONS DURATION AGE
myjob 1/1 19s 5m11s
#查看这个 pod的日志
[root@master ~]# kubectl logs myjob-gq27p
hello k8s job
CronJob控制器
CronJob可以用来执行基于时间计划的定时任务,类似于Linux/Unix系统中的 crontable (opens new window)。
CronJob 执行周期性的重复任务时非常有用,例如备份数据、发送邮件等。CronJob 也可以用来指定将来某个时间点执行单个任务,例如将某项任务定时到系统负载比较低的时候执行。
一个 CronJob 对象就像 crontab (cron table) 文件中的一行。 它用Cron格式进行编写, 并周期性地在给定的调度时间执行 Job。
注意:
所有 CronJob 的 schedule: 时间都是基于kube-controller-manager. 的时区。
如果你的控制平面在 Pod 或是裸容器中运行了 kube-controller-manager, 那么为该容器所设置的时区将会决定 Cron Job 的控制器所使用的时区。
为 CronJob 资源创建清单时,请确保所提供的名称是一个合法的DNS 子域名. 名称不能超过 52 个字符。 这是因为 CronJob 控制器将自动在提供的 Job 名称后附加 11 个字符,并且存在一个限制, 即 Job 名称的最大长度不能超过 63 个字符。
CronJob 用于执行周期性的动作,例如备份、报告生成等。 这些任务中的每一个都应该配置为周期性重复的(例如:每天/每周/每月一次); 你可以定义任务开始执行的时间间隔。
下面的 CronJob 示例清单会在每分钟打印出当前时间和问候消息:
[root@master kubenetres]# vi cronjob.yml
---
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- date; echo Hello world
restartPolicy: OnFailure
创建pod查看
[root@master ~]# kubectl apply -f cronjob.yml
Warning: batch/v1beta1 CronJob is deprecated in v1.21+, unavailable in v1.25+; use batch/v1 CronJob
cronjob.batch/hello created
#等一分钟查看
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-27339330-kkfxv 0/1 Completed 0 2s
#查看日志
[root@master ~]# kubectl logs hello-27339330-kkfxv
Fri Dec 24 19:00 UTC 2021
Hello world