Kubernetes-in-action (十一)
本节内容:
- 基于CPU使⽤率配置pod的⾃动横向伸缩,了解Cluster Autoscaler
- pod的节点选择:节点污点,节点亲缘性规则,节点⾮亲缘性的功能
基于CPU使⽤率配置pod的⾃动横向伸缩
流程
实践 (一)
- 部署一个deployment并设置其requests:
kubectl apply -f deployment.yaml
- 配置其自动伸缩规则:
kubectl autoscale deployment kubia --cpu-percent=30 --min=1 --max=5
- 查看deployment的HorizontalpodAutoscaler:
kubectl get hpa.v1.autoscaling kubia -o yaml
- 运行一个脚本调用pod来提高cpu:“while true; do curl http://10.42.0.117:8080 && echo
date
; done” - 发现pod的数量增加了。
- 保持cpu在[cpu-percent]30以下,并且pod最少1个,最多5个。
- Autoscaler: 单次扩容有时间和大小限制:pod >2,最多翻倍, 否则最大扩容到4个副本。
时间:3分钟没有任何扩容操作则扩容,5min没有缩容操作则运行缩容。- 使用 kubectl edit hpa 来修改 hpa的属性
- 不会将pod缩容到0.
apiVersion: apps/v1
kind: Deployment
metadata:
name: kubia
spec:
replicas: 3
selector:
matchLabels:
app: kubia
template:
metadata:
name: kubia
labels:
app: kubia
spec:
containers:
- image: luksa/kubia:v1
name: nodejs
resources:
requests:
cpu: 100m
基于自定义指标实现伸缩:https://medium.com/@marko.luksa/kubernetes-autoscaling-based-on-custom-metrics-without-using-a-host-port-b783ed6241ac
Cluster Autoscaler
- 作用:负责在由于节点资源不⾜,⽽⽆法调度某pod到已有节点时,⾃动部署新节点。它也会在节点长时间使⽤率低下的情况下下线节点
集群扩容流程
缩容过程
- 当⼀个节点被选中下线,它⾸先会被标记为不可调度,随后运⾏
其上的pod将被疏散⾄其他节点。因为所有这些pod都属于ReplicaSet或
者其他控制器,它们的替代pod会被创建并调度到其他剩下的节点(这
就是为何正被下线的节点要先标记为不可调度的原因)
只有当Cluster Autoscaler知道节点上运⾏的pod能够重新调度到其他节
点,该节点才会被归还。
设置节点调度策略
- kubectl cordon [node] 标记节点为不可调度(但对其上的pod不做任何事)。
- kubectl drain [node] 标记节点为不可调度,随后疏散其上所有pod。
两种情形下,在你⽤kubectl uncordon 解除节点的不可调度状态之前,不会有新pod被调度到该节点。
问题
为何不能纵向扩展pod
- 纵向既给它们更多CPU和(或)内存,可以通过limits/requests 给予一定范围的缩阔,但是还是不算纵向扩展
- pod的资源请求是通过pod manifest的字段配置的,纵向伸缩pod需要通过改变这些字段来实现。现在暂无办法。
如何确保一个节点在下线时不影响其内正在服务的pod
-
使用一个资源:podDisruptionBudget资源, 来指定下线等操作时需要保持的最少pod数量
-
使用 podDisruptionBudget
- 创建pdb命令:
kubectl create pdb kubia-pdb --selector=app=kubia --min-available=3
- 创建pdb命令:
可以设置 maxUnavailable 来限制可以存在多少个不可用pod
# pdb 基于 yaml创建
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
name: kubia-pdb
spec:
minAvailable: 2 # 可以用%30 来指定min-available
selector:
matchLabels:
app: kubia
pod的节点选择
节点容忍
- 配置节点污点,只有pod能够容忍这些污点,才能被分配到这个node上。
- 查看node的污点:
kubectl describe node node1
# 查看到Taints: <none>
,没有配置污点 - 查看pod上污点容忍度:
kubectl describe pod pod-name
# 查看Tolerations: xxx
Taint
- 格式:
<key>=<value>:<effect>
eg.: # value都是 null
node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
- 不同effect的效果
- NoSchedule: 表⽰如果pod没有容忍这些污点,pod则不能被调度到包含这些污点的节点上
- PreferNoSchedule: 尽量不要分配到该node,实在没有再分配
- NoExecute:如果没有容忍该污点则不能运行pod,包括正在运行的pod
实践
- 配置节点污点:
kubectl taint nodes node1 node-type=production:NoSchedule
- 配置pod污点容忍度并部署
apiVersion: apps/v1
kind: Deployment
metadata:
name: prod
spec:
replicas: 5
selector:
matchLabels:
app: prod
template:
metadata:
labels:
app: prod
spec:
containers:
- args:
- sleep
- "99999"
image: busybox
name: main
tolerations:
- key: node-type
operator: Equal # 污点的value必须等于配置value才行
value: production
effect: NoSchedule
# tolerationSeconds: 3600 # 只有 NoExecute 才有效果,效果是如果不符合污点则可以等待多长时间后继续分配,默认300
节点亲缘性
作用
- 比 node selector功能更多。
- 当调度某⼀个pod时,指定调度器可以优先考虑哪些节点。
- 可以查看 nodeAffinity、podAffinity、podAntiAffinity 下有哪些规则。
- nodeAffinity: node 选择
- podAffinity: pod亲和性选择
- podAntiAffinity: pod调度时不会被分配到与不亲和的pod同样的node
实践
- 给两个node配置lable
kubectl label node node1 availability-zone=zone1 share-type=dedicated
kubectl label node node1 availability-zone=zone2 share-type=shared
- 部署一个配置了节点亲缘性的pod
DuringSchedulingIgnoredDuringExecution: 在调度时候并且不影响已经执行的pod;
效果是可以将pod调度优先到zone1里,多地部署时作用很大。 只有两个node时,会由一个被分到zone2,因为k8s的特性,尽量不然所有pod都在同个node里。
apiVersion: apps/v1
kind: Deployment
metadata:
name: pref
spec:
replicas: 5
selector:
matchLabels:
app: pref
template:
metadata:
labels:
app: pref
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution: # 优先级
- weight: 80
preference:
matchExpressions:
- key: availability-zone
operator: In
values:
- zone1
- weight: 20
preference:
matchExpressions:
- key: share-type
operator: In
values:
- dedicated
containers:
- args:
- sleep
- "99999"
image: busybox
name: main
- podAffinity的Deployment配置 [部分]
...
affinity: # 尽量分配到与backend一个node
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
podAffinityTerm:
topologyKey: kubernetes.io/hostname
labelSelector:
matchLabels:
app: backend
...
- podAntiAffinity的Deployment配置 [部分]
...
affinity: # 尽量不要分配到与frontend一个node
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 如果想剩余没办法分配的pod也成功运行,可以用preferred。 required是强制,不能分配不分配。
- topologyKey: kubernetes.io/hostname
labelSelector:
matchLabels:
app: frontend
...
亲缘性调度是基于node label匹配的,所以要为每个node都配置好label才有效果。