目录
为什么要自动扩缩容?
再K8S中扩容分为两种:
一、Node层面:
二、Pods层面:
自动扩缩容的方案有哪些
Kubernetes HPA (Horizontal Pod Autoscaling)
Kubernetes KPA (Knative Pod Autoscaler)
Kubernetes VPA (Vertical Pod Autoscaler)
基于HPA进行POD的扩缩容
kube-apiserver 配置:
安装metrcs-server与addon-resizer
创建一个用于测试hpa的镜像 Dockerfile
使用Deployment部署一个 php-apache 服务
创建HPA-基于CPU
测试扩容-CPU
创建HPA-基于内存
同时基于内存与CPU
HPA官方文档地址:官方文档地址
在实际的业务场景中,我们经常会遇到某个服务需要扩容的场景(例如:测试对服务器压测,电商平台秒杀、大促活动、或由于资源紧张、工作负载降低等都需要对服务实例数量扩容操作)。
再使用kubenetes 集群经常问道的一个问题是,我应该保持多大的节点规模来满足应用需求呢?cluster-autoscaler 的出现解决了这个问题,可以通过cluster-autoscaler 实现节点级别的动态添加与删除,动态调整容器资源池,应对峰值流量
一般会使用Deployment中的 replicas参数,设置多个副本集来保证服务的高可用,但是这是一个固定的值,比如我们设置10个副本,就会启动10个pod 同时 running 来提供服务。
如果这个服务平时流量很少的时候,也是10个pod同时running,就会造成资源浪费,而流量突然暴增时,又出现了10个pod 不够用的情况。针对这种情况怎么办》 就需要自动扩缩容。
通过此功能,只需要简单的配置,便可以利用监控指标(CPU、内存、磁盘、自定义等) 自动的扩容或者缩容服务中的POD数量,当业务需求增加时,系统将无缝地自动增加适量的pod容器,提升系统稳定性。
基于请求数对POD自动扩缩容,KPA的主要限制在于它不支持基于CPU的自动扩缩容。
垂直 Pod 自动扩缩容,VPA会基于Pod的资源使用情况自动为集群设置资源占用的限制,从而让集群将Pod 调度到有足够资源的最佳节点上。VPA也会保持最初容器定义中资源request 和 limit的占比。
它会根据容器资源使用率自动设置POD 的CPU 和内存的 requests,从而允许再节点上进行适当的调度,以便为每个Pod 提供适当的可用的节点。它既可以缩小过度请求资源的容器,也可以根据其使用情况随时提升资源的容量。
K8S的HPA controller 已经实现了一套简单的自动扩缩容逻辑,默认情况下,每30s检测一次指标,只要检测到了配置HPA的目标值,则会计算出预期的工作负载的副本数,再进行扩容操作。同时为了避免过于频繁的扩缩容,默认再 5min 内没有重新扩缩容的情况下,才会触发扩缩容。
HPA 本身的算法相对比较保守,可能并使用与很多场景。例如,一个快速流量突发场景,如果正处在5min内的HPA稳定器,这个时候很具HPA的策略,会导致无法扩容(通过实验扩容是很快速的,并非等了5分钟,但是缩容等了5分钟,这个时间是可以更改的)
注意:这个是 k8s 在 1.17 的新特性,如果是 1.16 版本的可以不用添加,1.17 以后要添加。这个参 数的作用是 Aggregation 允许在不修改 Kubernetes 核心代码的同时扩展 Kubernetes API。
vim kube-apiserver.yaml
- --enable-aggregator-routing=true #添加该行内容
重新更新ApiServer 配置(!!!):
#查看下配置
ps -ef |grep enable-aggregator-routing
#不存在则更新下
kubectl apply -f /etc/kubernetes/manifests/kube-apiserver.yaml
kubectl delete pods kube-apiserver -n kube-system
#再次查看配置
ps -ef |grep enable-aggregator-routing
kubectl apply -f metrics.yaml
kubectl get pod -n kube-system
metrics-server-7f546bc689-7m2zm 2/2 Running 0
metrics.yaml:
#RBAC授权
#集群绑定角色到SA账号
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: metrics-server:system:auth-delegator
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- kind: ServiceAccount
name: metrics-server
namespace: kube-system
---
#角色绑定SA账号
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: metrics-server-auth-reader
namespace: kube-system
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: extension-apiserver-authentication-reader
subjects:
- kind: ServiceAccount
name: metrics-server
namespace: kube-system
---
#定义SA账号
apiVersion: v1
kind: ServiceAccount
metadata:
name: metrics-server
namespace: kube-system
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
---
#定义集群权限
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: system:metrics-server
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
rules:
- apiGroups:
- ""
resources:
- pods
- nodes
- nodes/stats
- namespaces
verbs:
- get
- list
- watch
- apiGroups:
- "extensions"
resources:
- deployments
verbs:
- get
- list
- update
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: system:metrics-server
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:metrics-server
subjects:
- kind: ServiceAccount
name: metrics-server
namespace: kube-system
---
#ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: metrics-server-config
namespace: kube-system
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: EnsureExists
data:
NannyConfiguration: |-
apiVersion: nannyconfig/v1alpha1
kind: NannyConfiguration
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: metrics-server
namespace: kube-system
labels:
k8s-app: metrics-server
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
version: v0.4.1
spec:
selector:
matchLabels:
k8s-app: metrics-server
version: v0.4.1
template:
metadata:
name: metrics-server
labels:
k8s-app: metrics-server
version: v0.4.1
spec:
priorityClassName: system-cluster-critical
serviceAccountName: metrics-server
containers:
- name: metrics-server
image: rancher/metrics-server:v0.4.1-amd64 #dockerhub镜像
imagePullPolicy: IfNotPresent
command:
- /metrics-server
- --metric-resolution=30s
- --kubelet-preferred-address-types=InternalIP
- --kubelet-insecure-tls
- --cert-dir=/tmp
- --secure-port=4443
ports:
- containerPort: 4443
name: https
protocol: TCP
- name: metrics-server-nanny
image: k8s.gcr.io/addon-resizer:1.8.4 #
imagePullPolicy: IfNotPresent
resources:
limits:
cpu: 100m
memory: 300Mi
requests:
cpu: 5m
memory: 50Mi
env:
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: MY_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
volumeMounts:
- name: metrics-server-config-volume
mountPath: /etc/config
command:
- /pod_nanny
- --config-dir=/etc/config
- --cpu=300m
- --extra-cpu=20m
- --memory=200Mi
- --extra-memory=10Mi
- --threshold=5
- --deployment=metrics-server
- --container=metrics-server
- --poll-period=300000
- --estimator=exponential
- --minClusterSize=2
volumes:
- name: metrics-server-config-volume
configMap:
name: metrics-server-config
tolerations:
- key: "CriticalAddonsOnly"
operator: "Exists"
- key: node-role.kubernetes.io/master
effect: NoSchedule
---
apiVersion: v1
kind: Service
metadata:
name: metrics-server
namespace: kube-system
labels:
addonmanager.kubernetes.io/mode: Reconcile
kubernetes.io/cluster-service: "true"
kubernetes.io/name: "Metrics-server"
spec:
selector:
k8s-app: metrics-server
ports:
- port: 443
protocol: TCP
targetPort: https
---
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
name: v1beta1.metrics.k8s.io
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
spec:
service:
name: metrics-server
namespace: kube-system
group: metrics.k8s.io
version: v1beta1
insecureSkipTLSVerify: true
groupPriorityMinimum: 100
versionPriority: 100
查看POD与Node资源使用情况
#查看ingress-nginx名称空间下的pod资源使用
kubectl top pod -n ingress-nginx
NAME CPU(cores) MEMORY(bytes)
ingress-nginx-controller-5cd767794b-qqrms 3m 91Mi
#查看node节点的资源使用
kubectl top node
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
test-master 207m 5% 3923Mi 53%
test-slave-1 187m 4% 5096Mi 69%
FROM php:5-apache
ADD index.php /var/www/html/index.php
RUN chmod a+rx index.php
# index.php 文件内容
#构建Docker 镜像
docker build -t k8s.gcr.io/hpa-example:v1 .
docker save -o hpa-example.tar.gz k8s.gcr.io/hpa-example:v1
可以把镜像传到 k8s 的工作节点,通过 docker load -i hpa-example.tar.gz 进行解压:
docker load -i hpa-example.tar.gz
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-apache
spec:
selector:
matchLabels:
run: php-apache
replicas: 1
template:
metadata:
labels:
run: php-apache
spec:
nodeName: test-slave-1 #再指定节点上创建Pod
containers:
- name: php-apache
image: k8s.gcr.io/hpa-example:v1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
resources:
limits:
cpu: 500m #最大使用0.5核CPU
memory: 200Mi
requests:
cpu: 200m #调用节点最小要有 0.2核CPU
memory: 200Mi
---
apiVersion: v1
kind: Service
metadata:
name: php-apache
labels:
run: php-apache
spec:
ports:
- port: 80
selector:
run: php-apache
更新资源清单文件
kubectl apply -f php-apache.yaml
#查看pod状态
kubectl get pod |grep php-apache
NAME READY STATUS RESTARTS AGE
php-apache-5cbf8c9567-cfq6q 1/1 Running 0 5s
php-apache 服务正在运行,使用 kubectl autoscale 创建自动缩放器,实现对 php-apache 这个Deployment创建的Pod 自动扩缩容下面的命令将会创建一个HPA,HPA将会根据CPU。内存等资源指标增加或者减少副本数,创建一个可以实现如下目的的HPA:
1) 让副本数维持再1-10 个之间 (这里副本数指的是通过Deployment 部署 pod 的副本数)
2) 将所有 pod 的平均CPU 使用率位置在 50% (通过 kubectl run 运行的Pod 如果是200毫核,这意味着平均CPU利用率为100毫核)
为 php-apache 这个 deployment 创建一个HPA
#基于CPU
kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
参数解析:
--cpu-percent=50 标识CPU使用率不超过50%
--min=1 最少一个pod
--max=10 最多是个pod
验证HPA是否创建成功
kubectl get hpa
注:由于我们没有向服务器发送任何请求,因此当前 CPU 消耗为 0%(TARGET 列显示了由相应 的 deployment 控制的所有 Pod 的平均值)
#运行一个pod
kubectl run v1 -it --image=busybox --image-pull-policy=IfNotPresent /bin/sh
#登录到容器之后,执行如下命令
while true; do wget -q -O- http://php-apache.default.svc.cluster.local; done
#在一分钟左右的时间内,我们通过执行以下命令来看到更高的 CPU 负载
kubectl top pod
NAME CPU(cores) MEMORY(bytes)
php-apache-5cbf8c9567-cfq6q 502m 8Mi
v1 6m 0Mi
#查看hpa
kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache 251%/50% 1 10 1 6m39s
#查看POD数量
[root@test-master ~]# kubectl top pod
NAME CPU(cores) MEMORY(bytes)
php-apache-5cbf8c9567-2g9rh 111m 9Mi
php-apache-5cbf8c9567-c46mw 102m 8Mi
php-apache-5cbf8c9567-cfq6q 105m 8Mi
php-apache-5cbf8c9567-d7clq 106m 8Mi
php-apache-5cbf8c9567-hcjqt 112m 8Mi
php-apache-5cbf8c9567-jhmx7 105m 8Mi
php-apache-5cbf8c9567-rnkxf 112m 8Mi
php-apache-5cbf8c9567-tkhfr 108m 8Mi
#停止压测观察5分钟后pod是否缩容
[root@test-master ~]# kubectl top pod
NAME CPU(cores) MEMORY(bytes)
php-apache-5cbf8c9567-cfq6q 1m 8Mi
v1 0m 0Mi
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: hpa-v2
spec:
minReplicas: 1
maxReplicas: 10
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
metrics:
- resource:
name: memory
target:
type: Utilization
averageUtilization: 50
type: Resource
kubectl exec -it php-apache-7d8fdb687c-b78m9 -- /bin/bash
#进行压测
dd if=/dev/zero of=/tmp/a
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: hpa-v2
spec:
minReplicas: 1
maxReplicas: 10
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
metrics:
- resource:
name: memory
target:
type: Utilization
averageUtilization: 50
type: Resource
- resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
type: Resource
#定义扩缩容策略
behavior:
#缩容策略(缩容是每5分钟缩容1个pods)
scaleDown:
policies:
- type: pods
value: 1
periodSeconds: 300 #单位是秒
#扩容策略(触发扩容时,立即新增9(900%*100%)倍的副本数,即立即扩容pod到当前的10倍的pod数量)
scaleUp:
policies:
- type: percent
value: 900%
扩展:
其他参数参考官方文档: controller-manager启动文件hpa参数
--horizontal-pod-autoscaler-initial-readiness-delay=30s,这是首次探测Pod是否Ready的延时时间,默认30s
--horizontal-pod-autoscaler-cpu-initialization-period=10s,设置首次采集pod的CPU使用率延迟时间,默认5分钟
--horizontal-pod-autoscaler-downscale-stabilization=1m0s,这个配置可以让系统更平滑的进行缩容操作,默认值5min