Pod控制器详解
本章主要介绍Pod控制器的详细使用
1. Pod控制器介绍
在kubernetes中,按照pod的创建方式可以将其分为2类:
- 自主式pod:kubernetes直接创建出来的pod,这种pod删除后就没有了,也不会重建
- 控制器创建的pod:通过控制器创建的pod,这种pod删除后还会自动重建
什么是Pod控制器?
Pod控制器是管理pod的中间层,使用了pod控制器之后,我们只需要告诉pod控制器,需要多少个pod就可以了。他会创建出满足条件的pod,并确保每个pod处于用户期望的状态。如果pod在运行中出现故障,控制器就会基于指定策略重启或重建pod。
在kubernetes中,有很多种类型的pod控制器,每种都有它适合的场景,常见有:
- ReplicationController:比较原始的pod控制器,已经被废弃,由ReplicaSet替代
- ReplicaSet:保证指定数量pod运行,并支持pod数量变更,镜像版本变更
- Deployment:通过ReplicaSet来控制pod,并支持滚动升级、版本回退
- Horizontal Pod Autoscaler:可以根据集群负载自动调整Pod的数量,实现削峰填谷
- DaemonSet:在集群中的指定Node上都运行一个副本,一般用于守护进程类的任务
- Job:它创建出来的pod只要完成任务就立即退出,用于执行一次性任务
- Cronjob:它创建的pod会周期性的执行,用于执行周期性任务
- StatefulSet:管理有状态应用
2. ReplicaSet
ReplicaSet的主要作用是保证一定数量的pod能够正常运行,它会持续监听这些pod运行状态,一旦pod发生故障,就会重启或重建。同时它还支持对pod数量的扩缩容和版本镜像的升降级。
ReplicaSet 如下图所示:
常规配置:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name:
namespace:
labels:
controller: rs
spec:
replicas: 3 #副本数量
selector: #选择器,通过它指定控制器管理哪些 pod
matchLabels:
app: nginx-pod
matchExpressions:
- {key: app, operator: In, values: [nginx-pod]}
template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
这里需要了解的配置就是spec下面的几个选项:
- replicas:
指定副本数量,也就是当前rs创建出来的pod数量,默认为1
- selector:
选择器,它的作用是建立pod控制器和pod之间的关联关系,采用的Label Selector机制。在pod模板上也需要定义label,这样在控制器上定义选择器,就可以表明当前控制器能管理哪些pod了
- template:模板,当前控制器创建pod所使用的模板,里面是pod定义
部署
示例:
$ cat yamls/pc-replicaset.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: pc-replicaset
namespace: dev
labels:
controller: rs
spec:
replicas: 3 #副本数量
selector:
matchLabels:
app: nginx-pod
matchExpressions:
- {key: app, operator: In, values: [nginx-pod]}
template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
查看创建的rs:
$ kubectl get rs -n dev -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
pc-replicaset 3 3 3 115s nginx nginx:1.17.1 app=nginx-pod,app in (nginx-pod)
扩缩容
有2种方法:
1. 直接编辑
$ kubectl edit rs -n dev
replicaset.apps/pc-replicaset edited
2. kubescale rs 命令
$ kubectl scale rs pc-replicaset --replicas=4 -n dev
replicaset.apps/pc-replicaset scaled
镜像版本升降级
同样
1. 直接编辑
$ kubectl edit rs -n dev
replicaset.apps/pc-replicaset edited
$ kubectl get rs pc-replicaset -n dev -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
pc-replicaset 4 4 4 5m39s nginx nginx:1.17.2 app=nginx-pod,app in (nginx-pod)
2. kubect set image 命令
$ kubectl set image rs pc-replicaset nginx=nginx:1.17.1 -n dev
replicaset.apps/pc-replicaset image updated
删除
使用kubectl delete 命令可以删除rs以及它管理的pod。Kubernetes在删除rs前,会将rs的replicascaler调整为0,等待所有pod被删除后,再执行rs对象的删除。
如果希望仅仅删除rs对象(保留pod),可以使用kubectl delete 命令时添加 --cascade=false(不推荐)
当然,删除yaml的形式也是可以的
3. Deployment
为了更好地解决服务编排的问题,kubernetes在V1.2 版本开始,引入了Deployment控制器。这种控制器并不直接管理pod,而是通过管理ReplicaSet来间接管理Pod。即:Deployment管理ReplicaSet,ReplicaSet管理Pod。所以Deployment比ReplicaSet功能更强大。
Deployment主要功能有:
- 支持ReplicaSet的所有功能
- 支持发布的停止、继续
- 支持版本滚动升级和版本回退
Deployment资源主要配置:
apiVersion: apps/v1
kind: Deployment
metadata:
name:
namespace:
labels:
controller: deploy
spec:
replicas: 3
revisionHistoryLimit: 3 # 保留历史版本,默认为10
paused: false # 暂停部署,默认是false
progressDeadlineSeconds: 600 # 部署超时时间(s),默认是600
strategy: # 策略
type: RollingUpdate # 滚动更新策略
rollingUpdate: # 滚动更新
maxSurge: 30% # 最大额外可以存在的副本数,可以为百分比或整数
maxUnavailable: 30% # 最大不可用状态的Pod的最大值,可以为百分比或整数
selector:
matchLabels:
app: nginx-pod
matchExpressions:
- {key: app, operator: In, values: [nginx-pod]}
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
扩缩容
1. kubectl scale deploy pc-deployment --replicas=5 -n dev
2. kubectl edit deploy pc-deployment -n dev
镜像更新
Deployment支持2种镜像更新策略:重建更新和滚动更新(默认),可以通过strategy选项进行配置。
重建更新就是一次性删除所有老版本pod,然后重建。滚动就是先删一部分,启动一部分,中间状态是新版本与老版本pod均存在,最终只有新版本pod存在。
strategy: # 指定新的pod替换旧pod的策略,支持2个属性
type: # 支持2个属性
Recreate: # 在创建出新的Pod之前会kill掉所有已存在的pod
RollingUpdate: # 滚动更新,kill一部分启动一部分,在更新过程中,存在2个版本的pod
rollingUpdate: # 当type为RollingUpdate时生效,用于设置它的参数
maxUnavailable: # 用来指定在升级过程中不可用 Pod 的最大数量,默认为25%
maxSurge: # 用来指定在升级过程中可以超过期望的Pod的最大数量,默认为 25%
1. 重建更新
测试配置项:
$ cat yamls/pc-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: pc-deployment
namespace: dev
labels:
controller: deploy
spec:
replicas: 3
strategy:
type: Recreate
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
变更镜像:
$ kubectl set image deployment pc-deployment nginx=nginx:1.17.2 -n dev
deployment.apps/pc-deployment image updated
$ kubectl get pods -n dev -o wide –w
NAME READY STATUS R
pc-deployment-7d7dd5499b-5wdlc 1/1 Running 0
pc-deployment-7d7dd5499b-czpzs 1/1 Running 0
pc-deployment-7d7dd5499b-dgvp5 1/1 Running 0
…
pc-deployment-7d7dd5499b-5wdlc 1/1 Terminating
pc-deployment-7d7dd5499b-dgvp5 1/1 Terminating
pc-deployment-7d7dd5499b-czpzs 1/1 Terminating
….
pc-deployment-7bbbd589d5-kkdcs 0/1 Pending
pc-deployment-7bbbd589d5-kkdcs 0/1 Pending
pc-deployment-7bbbd589d5-xtw4l 0/1 Pending
…
pc-deployment-7bbbd589d5-kkdcs 0/1 ContainerCreating
pc-deployment-7bbbd589d5-xtw4l 0/1 ContainerCreating
pc-deployment-7bbbd589d5-ztfbw 0/1 ContainerCreating
…
pc-deployment-7bbbd589d5-xtw4l 1/1 Running
pc-deployment-7bbbd589d5-ztfbw 1/1 Running
pc-deployment-7bbbd589d5-kkdcs 1/1 Running
从这个部署记录可以看到,recreate 的策略是一次性全部terminate,然后启动新版本pod。
2. 滚动更新
更改配置:
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 25%
maxSurge: 25%
变更 image 后打印的输出:
$ kubectl get pods -n dev -o wide -w
NAME READY STATUS
pc-deployment-866fdcbd54-9xwrb 0/1 Pending
pc-deployment-866fdcbd54-9xwrb 0/1 Pending
pc-deployment-866fdcbd54-9xwrb 0/1 ContainerCreating
pc-deployment-866fdcbd54-9xwrb 1/1 Running
pc-deployment-7bbbd589d5-xbnmw 1/1 Terminating
pc-deployment-866fdcbd54-wjs8n 0/1 Pending
pc-deployment-866fdcbd54-wjs8n 0/1 Pending
pc-deployment-866fdcbd54-wjs8n 0/1 ContainerCreating
pc-deployment-7bbbd589d5-xbnmw 0/1 Terminating
pc-deployment-7bbbd589d5-xbnmw 0/1 Terminating
pc-deployment-7bbbd589d5-xbnmw 0/1 Terminating
pc-deployment-866fdcbd54-wjs8n 1/1 Running
pc-deployment-7bbbd589d5-2cjvp 1/1 Terminating
pc-deployment-866fdcbd54-ls9b8 0/1 Pending
pc-deployment-866fdcbd54-ls9b8 0/1 Pending
pc-deployment-866fdcbd54-ls9b8 0/1 ContainerCreating
pc-deployment-7bbbd589d5-2cjvp 0/1 Terminating
pc-deployment-866fdcbd54-ls9b8 1/1 Running
pc-deployment-7bbbd589d5-f44sx 1/1 Terminating
pc-deployment-7bbbd589d5-f44sx 0/1 Terminating
pc-deployment-7bbbd589d5-2cjvp 0/1 Terminating
pc-deployment-7bbbd589d5-2cjvp 0/1 Terminating
pc-deployment-7bbbd589d5-f44sx 0/1 Terminating
pc-deployment-7bbbd589d5-f44sx 0/1 Terminating
可以看到在过程中是启动一个停止一个。
滚动更新其实是通过2个ReplicaSet 完成的,新版本pod全在新的rs中启动。旧版本pod在旧rs中陆续关闭。旧版本的ReplicaSet 不会被删掉,这是为版本回退而做的设计。
查看rs数量,可以看到第二次实验有2个rs:
$ kubectl get rs -n dev
NAME DESIRED CURRENT READY AGE
pc-deployment-7bbbd589d5 0 0 0 32m
pc-deployment-7d7dd5499b 0 0 0 32m
pc-deployment-866fdcbd54 3 3 3 30m
3. 版本回退
Deployment支持版本升级过程中的暂停、继续功能以及版本回退等功能。
kubectl rollout 是版本升级相关的功能,支持的选项有:
- status:显示当前升级状态
- history:显示升级历史记录
- pause:暂停版本升级过程
- resume:继续已经暂停的版本升级过程
- restart:重启版本升级过程
- undo:回滚到上一版本(可以使用--to-version回滚到指定版本)
#查看deployment 升级的当前状态
$ kubectl rollout status deploy pc-deployment -n dev
deployment "pc-deployment" successfully rolled out
# 查看版本升级历史
$ kubectl rollout history deploy pc-deployment -n dev
deployment.apps/pc-deployment
REVISION CHANGE-CAUSE
1 <none>
2 <none>
3 <none>
这里change-cause为<none> 是因为我们在部署 deployment的时候未添加--record的选项
加上 kubectl apply -f yamls/pc-deployment.yaml --record 后再次尝试的结果:
$ kubectl rollout history deploy pc-deployment -n dev
deployment.apps/pc-deployment
REVISION CHANGE-CAUSE
1 kubectl apply --filename=yamls/pc-deployment.yaml --record=true
2 kubectl apply --filename=yamls/pc-deployment.yaml --record=true
# 版本回退,若未指定版本号,默认回退到上一版本
$ kubectl rollout undo deploy pc-deployment -n dev
deployment.apps/pc-deployment rolled back
# 其实这个回退版本另一方面又是一个新版本(版本1 现在变为了版本4):
$ kubectl rollout history deploy pc-deployment -n dev
deployment.apps/pc-deployment
REVISION CHANGE-CAUSE
2 kubectl apply --filename=yamls/pc-deployment.yaml --record=true
3 kubectl apply --filename=yamls/pc-deployment.yaml --record=true
金丝雀发布
Deployment支持更新过程中的控制,如“暂停(pause)”或继续(resume)”更新操作。
比如有一批新的Pod资源创建完成后立即暂停更新过程。此时,仅存在一部分新版本的应用,主体部分还是旧版本。然后,再筛选一小部分的用户请求路由到新版本的Pod应用,继续观察能否稳定地按期望方式运行。确定没问题后再继续完成余下Pod资源滚动更新,否则立即回滚更新操作。这就是金丝雀发布。
# 更新deployment版本,并配置暂停deployment
$ kubectl set image deploy pc-deployment nginx=nginx:1.17.4 -n dev && kubectl rollout pause deployment pc-deployment -n dev
deployment.apps/pc-deployment image updated
deployment.apps/pc-deployment paused
# 查看 rs
$ kubectl get rs -n dev
NAME DESIRED CURRENT READY AGE
pc-deployment-56f77b8695 1 1 1 18s
pc-deployment-7d7dd5499b 3 3 3 35m
可以看到老版本是仍有3个,新版本仅有1个
# 查看 deployment status
$ kubectl rollout status deploy pc-deployment -n dev
Waiting for deployment "pc-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
后续可以将部分流量先导入到新的rs中进行测试,最终没有任何问题后,可以继续rollout的流程:
$ kubectl rollout resume deployment pc-deployment -n dev
deployment.apps/pc-deployment resumed
$ kubectl rollout status deploy pc-deployment -n dev
Waiting for deployment "pc-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment spec update to be observed...
Waiting for deployment spec update to be observed...
Waiting for deployment "pc-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "pc-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "pc-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "pc-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "pc-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "pc-deployment" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "pc-deployment" rollout to finish: 1 old replicas are pending termination...
deployment "pc-deployment" successfully rolled out
4. Horizontal Pod Autoscaler(HPA)
前面都是通过kubectl scale进行的手动扩容,在生产中更多的是自动化扩展。通过HPA可以实现此续期。
HPA可以获取每个pod利用率,然后和HPA中定义的指标进行对比,同时计算需要伸缩的具体指,最后实现pod数量调整。
HPA与之前的Deployment一样,也属于一种kubernetes 资源对象,它通过追踪分析目标pod的负载变化情况,来确定是否需要针对性地调整目标pod的副本数。
4.1. 安装metrics-server
metrics-server可以用来收集集群中的资源使用情况。
$ git clone -b v0.3.6 https://github.com/kubernetes-incubator/metrics-server
$ cd metrics-server/deploy/1.8+/
# 修改metrics-server-deployment.yaml 文件以下内容
spec:
hostNetwork: true
serviceAccountName: metrics-server
volumes:
# mount in tmp so we can safely use from-scratch images and/or read-only containers
- name: tmp-dir
emptyDir: {}
containers:
- name: metrics-server
image: registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server-amd64:v0.3.6
imagePullPolicy: Always
volumeMounts:
- name: tmp-dir
mountPath: /tmp
args:
- --kubelet-insecure-tls
- --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP
# 部署
kubectl apply -f ./
# 验证
$ kubectl get pods -n kube-system
metrics-server-5f55b696bd-xmgkp 1/1 Running 0 2m2s
部署完成后即可查看资源使用情况
# 查看资源使用情况
$ kubectl top node
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
ip-10-0-1-217.cn-north-1.compute.internal 51m 2% 657Mi 19%
ip-10-0-2-30.cn-north-1.compute.internal 42m 2% 565Mi 16%
4.2. 准备deployment和service
# 创建deployment
$ kubectl get deploy,pod -n dev
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-dep 1/1 1 1 61s
NAME READY STATUS RESTARTS AGE
pod/nginx-dep-755c49cf64-9hrfn 1/1 Running 0 61s
# 准备service
$ kubectl expose deploy nginx-dep --type=NodePort --port 80 --target-port=80 -n dev
service/nginx-dep exposed
4.3. 部署HPA
$ cat yamls/pc-hpa.yaml
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: pc-hpa
namespace: dev
spec:
minReplicas: 1
maxReplicas: 10
targetCPUUtilizationPercentage: 3 # 此处用3仅是为了测试
scaleTargetRef: # 指定要扩展的target deployment
apiVersion: apps/v1
kind: Deployment
name: nginx-dep
# 部署后
$ kubectl get hpa -n dev
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
pc-hpa Deployment/nginx-dep <unknown>/3% 1 10 0 11s
=> 这里 unknown 表示当前的使用情况,仍在计算中,需要等待一会儿出数据
$ kubectl get hpa -n dev
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
pc-hpa Deployment/nginx-dep 0%/3% 1 10 1 21m
如果hpa一直报invalid metrics (1 invalid out of 1), first error is: failed to get cpu utilization: missing request for cpu,说明 deploy中没有配置 CPU requests。需要执行下面的命令:
kubectl patch deployment nginx-dep -p='{"spec":{"template":{"spec":{"containers":[{"name":"nginx","resources":{"requests":{"cpu":"200m"}}}]}}}}' -n dev
开始压测,并观察hpa与deploy的结果:
$ kubectl get hpa -n dev -o wide -w
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
pc-hpa Deployment/nginx-dep 0%/3% 1 10 1 32m
pc-hpa Deployment/nginx-dep 3%/3% 1 10 1 32m
pc-hpa Deployment/nginx-dep 9%/3% 1 10 1 33m
$ kubectl get deploy -n dev
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-dep 3/3 3 3 51m
# 停掉一段时间后
$ kubectl get deploy -n dev
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-dep 1/1 1 1 63m
5. DaemonSet
DaemonSet类型的控制器可以保证集群中每一台(或指定)节点上都运行一个副本,一般适合于日志收集、节点监控等常见。也就是说,如果一个pod提供的功能是节点级别的(每个节点都需要且仅需要一个),那么这类Pod就适合使用DaemonSet类型的控制器创建。
DaemonSet控制器的特点:
- 每当向集群中添加一个节点时,指定的pod副本也会添加到该节点上
- 每当节点从集群中移除时,pod也就被垃圾回收了
6. Job
Job主要用于负责批量处理(一次处理多个任务)、短暂的、一次性任务。有以下2个特点:
- 当job创建的pod执行成功结束时,job将记录成功结束后的pod数量
- 当成功结束的pod达到指定的数量时,job将完成执行
主要属性有:
spec:
completions: 1 # 指定job需要成功运行Pods的数量。默认为1
parallelism: 1 # 指定job在任一时刻应该并发运行Pods的数量
activeDeadlineSeconds: 30 # job可运行的时间期限,若是超时仍未结束,则系统会尝试终止
backoffLimit: 6 # job失败后重试次数,默认为6
manualSelector: true # 是否使用selector选择器选择pod,默认false
selector:
matchLabels:
app: counter-pod
matchExpressions:
- {key: app, operator: In, values: [counter-pod]}
7. CronJob(CJ)
Cronjob控制器以Job控制器资源为其管控对象,并借助它管理pod资源对象,Job控制器定义的作业任务在其控制器资源创建之后便立即执行。但CronJob可以以类似于Linux操作系统的方式实现周期性地在某时间点运行。
主要属性有:
spec:
schedule: # cron格式的作业调度运行时间点,控制任务什么时间执行
concurrencyPolicy: # 并发执行策略,定义前一次作业未完成时是否运行后一次
failedJobHistoryLimit: # 为失败的任务执行那个保留的历史记录数,默认为1
successfulJobHistoryLimit: # 为成功的任务执行保留的历史记录数,默认为3
startingDeadlineSeconds: # 启动作业错误的超时时长
jobTemplate: # job控制器模板,用于为cronjob控制器生成job对象
metadata:
spec:
completions: 1
parallelism: 1
activeDeadlineSeconds: 30
...
template:
metadata:
labels:
app: counter-pod
spec:
restartPolicy: Never
containers:
- name: counter
...