在实际的业务场景中,我们经常会遇到某个服务需要扩容的场景(例如:测试对服务压测、电商平台秒杀、大促活动、或由于资源紧张、工作负载降低等都需要对服务实例数进行扩缩容操作)。
node扩缩容
在使用 kubernetes 集群经常问到的一个问题是,我应该保持多大的节点规模来满足应用需求呢?cluster-autoscaler 的出现解决了这个问题, 可以通过 cluster-autoscaler 实现节点级别的动态添加与删除,动态调整容器资源池,应对峰值流量。
pod层面
我们一般会使用 Deployment 中的 replicas 参数,设置多个副本集来保证服务的高可用,但是这是一个固定的值,比如我们设置 10 个副本,就会启 10 个 pod 同时 running 来提供服务。
如果这个服务平时流量很少的时候,也是 10 个 pod 同时在 running,而流量突然暴增时,又可能出现 10 个 pod 不够用的情况。针对这种情况怎么办?就需要自动扩缩容。
手动模式::通过 kubectl scale 命令,这样需要每次去手工操作一次,而且不确定什么时候业务请求量就很大了,所以如果不能做到自动化的去扩缩容的话,这也是一个很麻烦的事情。
自动模式:
1、kubernetes HPA(Horizontal Pod Autoscaling):根据监控指标(cpu 使用率、磁盘、自定义的等)自动扩容或缩容服务中的pod数量,当业务需求增加时,系统将无缝地自动增加适量 pod 容器,提高系统稳定性。
2、kubernetes KPA(Knative Pod Autoscaler):基于请求数对 Pod 自动扩缩容,KPA 的主要限制在于它不支持基于 CPU 的自动扩缩容。
3、kubernetes VPA(Vertical Pod Autoscaler):基于 Pod 的资源使用情况自动设置 pod 的 CPU 和内存的 requests,从而让集群将 Pod 调度到有足够资源的最佳节点上。
K8S 从 1.8 版本开始,各节点CPU、内存等资源的 metrics 信息可以通过 Metrics API 来获取,用户可以直接获取这些 metrics 信息(例如通过执行 kubect top 命令),HPA 使用这些 metics 信息来实现动态伸缩。
基于1.23.1版kubernetes
HPA官网:https://kubernetes.io/zh/docs/tasks/run-application/horizontal-pod-autoscale/
metrics-server 是一个集群范围内的资源数据集和工具,同样的,metrics-server 也只是显示数据,并不提供数据存储服务,主要关注的是资源度量 API 的实现,比如 CPU、文件描述符、内存、请求延时等指标,metric-server 收集数据给 k8s 集群内使用,如 kubectl,hpa,scheduler 等。
github地址:https://github.com/kubernetes-sigs/metrics-server/
不同k8s版本根据官网安装对应版本的metrics-server
所用镜像可提前自行下载:registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server:v0.6.1
docker load -i metrics-server-0.6.1.tar.gz
注意:会中断业务,生产环境谨慎操作!
这个是 k8s 在 1.17 的新特性,如果是 1.16 版本的可以不用添加,1.17 以后要添加。这个参数的作用是 Aggregation 允许在不修改 Kubernetes 核心代码的同时扩展 Kubernetes API。
vim /etc/kubernetes/manifests/kube-apiserver.yaml
增加如下内容:
- --enable-aggregator-routing=true
systemctl restart kubelet
kubectl apply -f components.yaml
用到的yaml文件到github下载,地址:https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.6.1/components.yaml
kubectl get pods -n kube-system | grep metrics
kubectl top nodes # 查看各节点资源使用情况
kubectl top pods -n kube-system # 查看kube-system名称空间下pod资源使用情况
使用 dockerfile 构建一个新的镜像,在 k8s 的 xuegod63 节点构建
mkdir php
cd php
vim dockerfile
dockerfile内容如下:
FROM php:5-apache
ADD index.php /var/www/html/index.php
RUN chmod a+rx index.php
创建index.php文件,内容如下:
<?php
$x = 0.0001;
for ($i = 0; $i <= 1000000;$i++) {
$x += sqrt($x);
}
echo "OK!";
?>
docker build -t k8s.gcr.io/hpa-example:v1 . # 构建镜像
docker save -o hpa-example.tar.gz k8s.gcr.io/hpa-example:v1 # 打包镜像
scp hpa-example.tar.gz xuegod64:/root/ # 将镜像传到工作节点
在工作节点导入镜像:
docker load -i hpa-example.tar.gz
cat php-apache.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-apache
spec:
selector:
matchLabels:
run: php-apache
replicas: 1
template:
metadata:
labels:
run: php-apache
spec:
containers:
- name: php-apache
image: k8s.gcr.io/hpa-example:v1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
resources:
limits:
cpu: 500m
requests:
cpu: 200m
---
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 # 更新资源清单文件
kubectl get pods # 验证 php 是否部署成功
cat nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-hpa
spec:
selector:
matchLabels:
app: nginx
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.9.1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: http
protocol: TCP
resources:
requests:
cpu: 0.01
memory: 25Mi
limits:
cpu: 0.05
memory: 60Mi
---
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
selector:
app: nginx
type: NodePort
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
nodePort: 30080
注意:nginx 的 pod 里需要有如下字段,否则 hpa 会采集不到内存指标
resources:
requests:
cpu: 0.01
memory: 25Mi
limits:
cpu: 0.05
memory: 60Mi
创建资源并查看:
kubectl apply -f nginx.yaml # 更新资源清单
kubectl get pods # 查看pod
kubectl get svc # 查看service
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 毫核)
创建:
kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
查看:
kubectl get hpa
重新打开一个master节点的终端,进行如下操作:
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
在原master终端查看hpa情况:
kubectl get hpa
kubectl get pods
可以看到平均cpu使用率达到了98%,副本数已经变为5个。
注意:可能需要几分钟来稳定副本数。由于不以任何方式控制负载量,因此最终副本数可能会与此示例不同。
停止向 php-apache 这个服务发送查询请求,在 busybox 镜像创建容器的终端中,通过 Ctrl+ C 把刚才 while 请求停止,然后,我们将验证结果状态(大约一分钟后):
kubectl get hpa
nginx 服务正在运行,使用 kubectl autoscale 创建自动缩放器,实现对 nginx 这个deployment 创建的 pod 自动扩缩容,下面的命令将会创建一个 HPA,HPA 将会根据内存资源指标增加或减少副本数,创建一个可以实现如下目的的 hpa:
(1)让副本数维持在 1-10 个之间(这里副本数指的是通过 deployment 部署的 pod 的副本数)
(2)将所有 Pod 的平均内存使用率维持在 60%
hpa-v1.yaml 内容如下:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-hpa
spec:
maxReplicas: 10
minReplicas: 1
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-hpa
metrics:
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 60
kubectl apply -f hpa-v1.yaml # 更新资源清单
kubectl get hpa nginx-hpa # 查看创建的hpa
可以看到当前内存使用率、目标内存使用率,最大、最小、当前副本数。
使用master节点的终端2登录到上面通过 pod 创建的 nginx,并生成一个文件,增加内存
kubectl exec -it nginx-hpa-7f5d6fbfd9-4d95f -- /bin/bash
dd if=/dev/zero of=/tmp/a
使用终端1查看hpa情况:
kubectl get hpa nginx-hpa
到终端2使用 Ctrl + C 中断dd进程,删除/tmp/a这个文件
rm -rf /tmp/a
在终端1查看hpa的情况:
kubectl get hpa nginx-hpa
可以看到平均内存使用率已经降到5%,副本数也降为1。(需要等几分钟才能看到)
Cluster Autoscaler (CA)是一个独立程序,是用来弹性伸缩 kubernetes 集群的。它可以自动根据部署应用所请求的资源量来动态的伸缩集群。当集群容量不足时,它会自动去 Cloud Provider (支持GCE、GKE 和 AWS)创建新的 Node,而在 Node 长时间资源利用率很低时自动将其删除以节省开支。
项目地址:https://github.com/kubernetes/autoscaler
在以下情况下,集群自动扩容或者缩放:
kubectl annotate node <nodename> cluster-autoscaler.kubernetes.io/scale-down-disabled=true
Horizontal Pod Autoscaler 会根据当前 CPU 负载更改部署或副本集的副本数。如果负载增加,则 HPA 将创建新的副本,集群中可能有足够的空间,也可能没有足够的空间。如果没有足够的资源,CA将尝试启动一些节点,以便 HPA 创建的 Pod 可以运行。如果负载减少,则 HPA 将停止某些副本。结果,某些节点可能变得利用率过低或完全为空,然后 CA 将终止这些不需要的节点。