|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
引言
在当今云原生时代,Kubernetes(简称K8s)已成为容器编排的事实标准。随着业务的快速发展和变化,如何灵活应对负载波动、保证服务稳定性的同时优化资源利用率,成为每个运维和开发团队必须面对的挑战。K8s的扩容缩容能力正是解决这一问题的关键特性。
本文将从基础概念入手,逐步深入到高级实践,全面解析K8s集群扩容缩容的完整解决方案。无论您是刚接触K8s的新手,还是寻求优化经验的老手,都能从本文中获得有价值的知识和技巧。
一、K8s扩容缩容基础概念
1.1 什么是K8s扩容缩容
K8s扩容缩容是指根据业务负载情况,动态调整集群资源或应用实例数量的过程。扩容(Scale-out/Scale-up)指增加资源以应对高负载,缩容(Scale-in/Scale-down)则指减少资源以节省成本。
• 横向扩容缩容(Scale-out/Scale-in):增加或减少Pod/节点数量
• 纵向扩容缩容(Scale-up/Scale-down):增加或减少单个Pod/节点的资源配额
1.2 为什么需要扩容缩容
1. 应对流量波动:业务高峰期增加资源,低谷期减少资源
2. 优化成本:避免资源闲置,提高资源利用率
3. 保证服务质量:防止因资源不足导致服务降级或中断
4. 提升系统弹性:增强系统应对突发负载的能力
1.3 扩容缩容的层次
K8s中的扩容缩容可分为两个层次:
1. Pod级别:调整Deployment、ReplicaSet、StatefulSet等控制器管理的Pod数量
2. 节点级别:调整集群中节点的数量,通常结合云平台的弹性能力
二、手动扩容缩容
2.1 手动调整Pod数量
手动扩容缩容是最基础的方式,通过直接修改控制器副本数实现。
- # 查看当前deployment的副本数
- kubectl get deployment <deployment-name>
- # 将deployment的副本数调整为5
- kubectl scale deployment <deployment-name> --replicas=5
- # 验证扩容结果
- kubectl get pods -l app=<app-label>
复制代码- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: nginx-deployment
- spec:
- replicas: 3 # 修改此值来调整Pod数量
- selector:
- matchLabels:
- app: nginx
- template:
- metadata:
- labels:
- app: nginx
- spec:
- containers:
- - name: nginx
- image: nginx:1.14.2
- ports:
- - containerPort: 80
复制代码
应用修改:
- kubectl apply -f deployment.yaml
复制代码
2.2 手动调整节点数量
手动调整节点数量通常需要结合云平台的API或控制台操作。
以AWS EKS为例:
- # 使用AWS CLI调整节点组大小
- aws eks update-nodegroup-config \
- --cluster-name <cluster-name> \
- --nodegroup-name <nodegroup-name> \
- --scaling-config "{minSize=3,desiredSize=5,maxSize=10}"
复制代码- # 查看集群节点
- kubectl get nodes
- # 标记节点为不可调度(准备移除)
- kubectl cordon <node-name>
- # 驱逐节点上的Pod
- kubectl drain <node-name> --ignore-daemonsets --delete-local-data
- # 删除节点(从云平台或物理机层面操作)
- # ...
复制代码
三、自动扩容缩容
3.1 HPA(Horizontal Pod Autoscaler)
HPA是K8s中最常用的自动扩容缩容机制,根据CPU、内存或自定义指标自动调整Pod数量。
HPA通过Metrics Server收集资源使用数据,根据设定的阈值和算法计算所需的副本数,然后调整目标控制器的副本数。
- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: nginx-hpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: nginx-deployment
- minReplicas: 2
- maxReplicas: 10
- metrics:
- - type: Resource
- resource:
- name: cpu
- target:
- type: Utilization
- averageUtilization: 50
- - type: Resource
- resource:
- name: memory
- target:
- type: Utilization
- averageUtilization: 70
复制代码
应用HPA:
- kubectl apply -f hpa.yaml
复制代码
查看HPA状态:
- # 基于CPU利用率创建HPA
- kubectl autoscale deployment nginx-deployment --cpu-percent=50 --min=2 --max=10
- # 查看HPA详细状态
- kubectl describe hpa nginx-deployment
复制代码
HPA计算目标副本数的公式:
- desiredReplicas = ceil[currentReplicas * (currentMetricValue / desiredMetricValue)]
复制代码
例如,当前有4个副本,CPU利用率为80%(目标为50%),则计算结果为:
- desiredReplicas = ceil[4 * (80 / 50)] = ceil[6.4] = 7
复制代码
HPA还考虑了多个指标,会取所有指标计算结果中的最大值。
除了CPU和内存,HPA还可以基于自定义指标进行扩容缩容。
首先,确保安装了Prometheus Adapter或自定义指标API:
- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: custom-metrics-hpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: my-app
- minReplicas: 2
- maxReplicas: 10
- metrics:
- - type: Pods
- pods:
- metric:
- name: http_requests_per_second
- target:
- type: AverageValue
- averageValue: 500m # 0.5 requests per second
复制代码
3.2 VPA(Vertical Pod Autoscaler)
VPA自动调整Pod的资源请求和限制,实现纵向扩容缩容。
VPA监控Pod的资源使用情况,推荐并应用更合适的资源请求和限制值。
- # 下载VPA发布包
- git clone https://github.com/kubernetes/autoscaler.git
- cd autoscaler/vertical-pod-autoscaler
- # 安装VPA
- ./hack/vpa-up.sh
复制代码- apiVersion: autoscaling.k8s.io/v1
- kind: VerticalPodAutoscaler
- metadata:
- name: my-app-vpa
- spec:
- targetRef:
- apiVersion: "apps/v1"
- kind: Deployment
- name: my-app
- updatePolicy:
- updateMode: "Auto" # 或"Off"、"Initial"
- resourcePolicy:
- containerPolicies:
- - containerName: "*"
- minAllowed:
- cpu: "100m"
- memory: "50Mi"
- maxAllowed:
- cpu: "1"
- memory: "500Mi"
- controlledResources: ["cpu", "memory"]
复制代码
应用VPA:
- kubectl apply -f vpa.yaml
复制代码
查看VPA状态和推荐值:
- kubectl describe vpa my-app-vpa
复制代码
VPA和HPA可以结合使用,但需要注意:
1. 如果HPA使用CPU/内存指标,VPA可能会干扰HPA的工作
2. 建议HPA使用自定义指标,VPA负责CPU/内存调整
- # HPA使用自定义指标
- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: my-app-hpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: my-app
- minReplicas: 2
- maxReplicas: 10
- metrics:
- - type: Pods
- pods:
- metric:
- name: http_requests_per_second
- target:
- type: AverageValue
- averageValue: 500m
- # VPA负责CPU/内存调整
- apiVersion: autoscaling.k8s.io/v1
- kind: VerticalPodAutoscaler
- metadata:
- name: my-app-vpa
- spec:
- targetRef:
- apiVersion: "apps/v1"
- kind: Deployment
- name: my-app
- updatePolicy:
- updateMode: "Auto"
复制代码
3.3 Cluster Autoscaler
Cluster Autoscaler负责自动调整集群节点数量,以满足Pod的调度需求。
1. 监控集群中无法调度的Pod
2. 当发现因资源不足而无法调度的Pod时,请求云平台增加节点
3. 监控节点资源利用率,当节点利用率低且其上的Pod可以安全迁移时,减少节点
以AWS EKS为例:
- # 下载Cluster Autoscaler清单
- wget https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml
- # 修改配置,设置集群名称和适当的参数
- # ...
- # 应用Cluster Autoscaler
- kubectl apply -f cluster-autoscaler-autodiscover.yaml
复制代码- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: cluster-autoscaler
- namespace: kube-system
- spec:
- template:
- spec:
- containers:
- - name: cluster-autoscaler
- image: k8s.gcr.io/autoscaling/cluster-autoscaler:v1.22.2
- command:
- - ./cluster-autoscaler
- - --cloud-provider=aws
- - --namespace=kube-system
- - --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/<cluster-name>
- - --balance-similar-node-groups
- - --skip-nodes-with-system-pods=false
- - --expander=priority # 或"random", "least-waste"
- env:
- - name: AWS_REGION
- value: <aws-region>
复制代码
HPA负责Pod级别的扩容缩容,Cluster Autoscaler负责节点级别的扩容缩容,两者协同工作:
1. HPA根据负载增加Pod数量
2. 当集群资源不足,新Pod无法调度时,Cluster Autoscaler增加节点
3. 当负载下降,HPA减少Pod数量
4. 当节点资源利用率低且Pod可以安全迁移时,Cluster Autoscaler减少节点
3.4 KEDA(Kubernetes Event-driven Autoscaling)
KEDA是一个基于事件的自动扩容缩容组件,可以根据外部事件(如消息队列长度、数据库连接数等)驱动K8s工作负载的扩容缩容。
- # 使用Helm安装KEDA
- helm repo add kedacore https://kedacore.github.io/charts
- helm repo update
- helm install keda kedacore/keda
复制代码- apiVersion: keda.sh/v1alpha1
- kind: ScaledObject
- metadata:
- name: redis-scaledobject
- namespace: default
- spec:
- scaleTargetRef:
- name: redis-consumer-deployment
- minReplicaCount: 0
- maxReplicaCount: 10
- pollingInterval: 30
- cooldownPeriod: 300
- triggers:
- - type: redis
- metadata:
- address: redis-master.default.svc.cluster.local:6379
- password: ""
- listName: mylist
- listLength: "5"
复制代码
KEDA支持多种触发器类型,包括:
• 消息队列:RabbitMQ, Kafka, NATS, Redis Streams等
• 数据库:PostgreSQL, MySQL, MongoDB等
• 云服务:AWS SQS, Azure Service Bus, GCP Pub/Sub等
• 指标:Prometheus, CPU, Memory等
• 自定义:通过外部API或自定义触发器
四、高级扩容缩容策略
4.1 基于预测的扩容缩容
传统的扩容缩容是反应式的,基于预测的扩容缩容则可以提前应对预期的负载变化。
- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: predictive-hpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: my-app
- minReplicas: 2
- maxReplicas: 10
- metrics:
- - type: External
- external:
- metric:
- name: predicted_cpu_usage
- selector:
- matchLabels:
- app: my-app
- target:
- type: Value
- value: 500m
复制代码
可以使用Prometheus的预测函数或外部预测服务生成预测指标:
- # 使用Prometheus的predict_linear函数预测1小时后的CPU使用率
- predict_linear(cpu_usage{app="my-app"}[1h], 3600)
复制代码
4.2 多维度扩容缩容策略
结合多种指标和策略,实现更智能的扩容缩容决策。
- package main
- import (
- "context"
- "fmt"
- "time"
-
- autoscalingv2 "k8s.io/api/autoscaling/v2"
- corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/api/resource"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/client-go/kubernetes"
- "k8s.io/client-go/rest"
- )
- type MultiDimScaler struct {
- clientset *kubernetes.Clientset
- }
- func NewMultiDimScaler() (*MultiDimScaler, error) {
- config, err := rest.InClusterConfig()
- if err != nil {
- return nil, err
- }
-
- clientset, err := kubernetes.NewForConfig(config)
- if err != nil {
- return nil, err
- }
-
- return &MultiDimScaler{clientset: clientset}, nil
- }
- func (s *MultiDimScaler) ScaleDeployment(ctx context.Context, namespace, name string) error {
- // 获取当前部署
- deployment, err := s.clientset.AppsV1().Deployments(namespace).Get(ctx, name, metav1.GetOptions{})
- if err != nil {
- return fmt.Errorf("failed to get deployment: %v", err)
- }
-
- currentReplicas := *deployment.Spec.Replicas
-
- // 获取Pod的CPU和内存使用情况
- podMetrics, err := s.clientset.MetricsV1beta1().PodMetricses(namespace).List(ctx, metav1.ListOptions{
- LabelSelector: metav1.FormatLabelSelector(deployment.Spec.Selector),
- })
- if err != nil {
- return fmt.Errorf("failed to get pod metrics: %v", err)
- }
-
- // 计算平均资源使用率
- var totalCPU, totalMem int64
- for _, podMetric := range podMetrics.Items {
- for _, container := range podMetric.Containers {
- cpu := container.Usage[corev1.ResourceCPU]
- mem := container.Usage[corev1.ResourceMemory]
-
- totalCPU += cpu.MilliValue()
- totalMem += mem.Value()
- }
- }
-
- avgCPU := totalCPU / int64(len(podMetrics.Items))
- avgMem := totalMem / int64(len(podMetrics.Items))
-
- // 获取请求的资源
- var requestedCPU, requestedMem int64
- for _, container := range deployment.Spec.Template.Spec.Containers {
- if container.Resources.Requests != nil {
- if cpu, ok := container.Resources.Requests[corev1.ResourceCPU]; ok {
- requestedCPU += cpu.MilliValue()
- }
- if mem, ok := container.Resources.Requests[corev1.ResourceMemory]; ok {
- requestedMem += mem.Value()
- }
- }
- }
-
- // 计算使用率
- cpuUtilization := float64(avgCPU) / float64(requestedCPU) * 100
- memUtilization := float64(avgMem) / float64(requestedMem) * 100
-
- // 多维度决策逻辑
- var desiredReplicas int32
- if cpuUtilization > 70 || memUtilization > 80 {
- // 高负载,扩容
- desiredReplicas = currentReplicas + 1
- } else if cpuUtilization < 30 && memUtilization < 40 && currentReplicas > 2 {
- // 低负载,缩容
- desiredReplicas = currentReplicas - 1
- } else {
- // 保持当前副本数
- desiredReplicas = currentReplicas
- }
-
- // 应用扩容缩容
- if desiredReplicas != currentReplicas {
- deployment.Spec.Replicas = &desiredReplicas
- _, err = s.clientset.AppsV1().Deployments(namespace).Update(ctx, deployment, metav1.UpdateOptions{})
- if err != nil {
- return fmt.Errorf("failed to update deployment: %v", err)
- }
- }
-
- return nil
- }
- func main() {
- scaler, err := NewMultiDimScaler()
- if err != nil {
- panic(err)
- }
-
- ctx := context.Background()
- for {
- err = scaler.ScaleDeployment(ctx, "default", "my-app")
- if err != nil {
- fmt.Printf("Error scaling deployment: %v\n", err)
- }
-
- time.Sleep(30 * time.Second)
- }
- }
复制代码
4.3 分层扩容缩容策略
根据应用的不同层次(如接入层、业务层、数据层)采用不同的扩容缩容策略。
- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: gateway-hpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: api-gateway
- minReplicas: 3
- maxReplicas: 20
- metrics:
- - type: Resource
- resource:
- name: cpu
- target:
- type: Utilization
- averageUtilization: 60
- - type: Pods
- pods:
- metric:
- name: requests_per_second
- target:
- type: AverageValue
- averageValue: 1k
- behavior:
- scaleUp:
- stabilizationWindowSeconds: 30
- policies:
- - type: Percent
- value: 100
- periodSeconds: 60
- - type: Pods
- value: 5
- periodSeconds: 60
- selectPolicy: Max
- scaleDown:
- stabilizationWindowSeconds: 300
- policies:
- - type: Percent
- value: 10
- periodSeconds: 60
复制代码- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: business-hpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: business-service
- minReplicas: 2
- maxReplicas: 15
- metrics:
- - type: Resource
- resource:
- name: cpu
- target:
- type: Utilization
- averageUtilization: 70
- - type: External
- external:
- metric:
- name: queue_length
- selector:
- matchLabels:
- service: business-service
- target:
- type: AverageValue
- averageValue: 10
复制代码- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: data-hpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: StatefulSet
- name: database
- minReplicas: 3
- maxReplicas: 7
- metrics:
- - type: Resource
- resource:
- name: cpu
- target:
- type: Utilization
- averageUtilization: 65
- - type: Resource
- resource:
- name: memory
- target:
- type: Utilization
- averageUtilization: 75
- - type: Pods
- pods:
- metric:
- name: active_connections
- target:
- type: AverageValue
- averageValue: 100
复制代码
五、专家经验分享
5.1 设置合理的资源请求和限制
资源请求和限制的设置对扩容缩容效果至关重要。
1. 准确评估资源需求:
- # 使用kubectl top命令查看当前资源使用情况
- kubectl top pods
- # 使用Metrics Server收集历史数据
- kubectl get --raw "/apis/metrics.k8s.io/v1beta1/pods" | jq '.items[] | {name: .metadata.name, cpu: .containers[0].usage.cpu, memory: .containers[0].usage.memory}'
复制代码
1. 设置合理的请求和限制比例:
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: optimized-app
- spec:
- template:
- spec:
- containers:
- - name: app
- image: myapp:latest
- resources:
- requests:
- cpu: "200m" # 基于P95历史数据
- memory: "256Mi" # 基于P95历史数据
- limits:
- cpu: "500m" # 请求的2-3倍
- memory: "512Mi" # 请求的1.5-2倍
复制代码
1. 使用VPA辅助优化:
- apiVersion: autoscaling.k8s.io/v1
- kind: VerticalPodAutoscaler
- metadata:
- name: app-vpa
- spec:
- targetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: app
- updatePolicy:
- updateMode: "Recommend" # 仅提供推荐值,不自动更新
复制代码
5.2 优化HPA配置
HPA配置的优化直接影响扩容缩容的效果和稳定性。
- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: optimized-hpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: app
- minReplicas: 3
- maxReplicas: 15
- metrics:
- - type: Resource
- resource:
- name: cpu
- target:
- type: Utilization
- averageUtilization: 65 # 不是70%或80%,留有一定缓冲
复制代码- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: behavior-hpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: app
- minReplicas: 3
- maxReplicas: 15
- metrics:
- - type: Resource
- resource:
- name: cpu
- target:
- type: Utilization
- averageUtilization: 65
- behavior:
- scaleUp:
- stabilizationWindowSeconds: 30 # 快速扩容
- policies:
- - type: Percent
- value: 50
- periodSeconds: 60
- - type: Pods
- value: 3
- periodSeconds: 60
- selectPolicy: Max # 使用更激进的扩容策略
- scaleDown:
- stabilizationWindowSeconds: 300 # 缓慢缩容,防止抖动
- policies:
- - type: Percent
- value: 10
- periodSeconds: 60
复制代码
5.3 避免扩容缩容抖动
扩容缩容抖动是指系统在短时间内频繁进行扩容和缩容操作,可能导致不稳定和资源浪费。
- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: stable-hpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: app
- minReplicas: 3
- maxReplicas: 15
- behavior:
- scaleUp:
- stabilizationWindowSeconds: 60 # 扩容后至少等待60秒
- scaleDown:
- stabilizationWindowSeconds: 300 # 缩容后至少等待300秒
复制代码- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: predictive-hpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: app
- minReplicas: 3
- maxReplicas: 15
- metrics:
- - type: External
- external:
- metric:
- name: predicted_cpu_usage
- target:
- type: Value
- value: "500m"
- behavior:
- scaleUp:
- stabilizationWindowSeconds: 300 # 预测性扩容,更长的稳定窗口
复制代码
5.4 优化节点池配置
合理的节点池配置可以提高Cluster Autoscaler的效率。
- # 示例:AWS EKS节点组配置
- apiVersion: eksctl.io/v1alpha5
- kind: ClusterConfig
- metadata:
- name: optimized-cluster
- region: us-west-2
- nodeGroups:
- - name: critical-ng
- instanceType: m5.xlarge
- desiredCapacity: 3
- minSize: 2
- maxSize: 10
- labels:
- workload: critical
- taints:
- - key: workload
- value: critical
- effect: NoSchedule
- tags:
- k8s.io/cluster-autoscaler/node-template/label/workload: critical
- k8s.io/cluster-autoscaler/node-template/taint/workload: critical:NoSchedule
- - name: general-ng
- instanceType: m5.large
- desiredCapacity: 5
- minSize: 3
- maxSize: 20
- labels:
- workload: general
- tags:
- k8s.io/cluster-autoscaler/node-template/label/workload: general
- - name: spot-ng
- instanceType: m5.large
- desiredCapacity: 2
- minSize: 0
- maxSize: 10
- spot: true
- labels:
- workload: spot
- tags:
- k8s.io/cluster-autoscaler/node-template/label/workload: spot
复制代码- apiVersion: scheduling.k8s.io/v1
- kind: PriorityClass
- metadata:
- name: high-priority
- value: 1000000
- globalDefault: false
- description: "High priority class for critical services"
- ---
- apiVersion: scheduling.k8s.io/v1
- kind: PriorityClass
- metadata:
- name: medium-priority
- value: 500000
- globalDefault: true
- description: "Medium priority class for general services"
- ---
- apiVersion: scheduling.k8s.io/v1
- kind: PriorityClass
- metadata:
- name: low-priority
- value: 1000
- globalDefault: false
- description: "Low priority class for batch jobs"
复制代码
在Pod中使用优先级:
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: critical-app
- spec:
- template:
- spec:
- priorityClassName: high-priority
- containers:
- - name: app
- image: myapp:latest
复制代码
六、避坑技巧
6.1 HPA常见问题及解决方案
可能原因:
• Metrics Server未安装或运行异常
• 未设置资源请求(requests)
• 当前指标值未达到阈值
解决方案:
- # 检查Metrics Server状态
- kubectl get pods -n kube-system | grep metrics-server
- kubectl logs -n kube-system <metrics-server-pod-name>
- # 检查资源请求设置
- kubectl get deployment <deployment-name> -o yaml | grep requests
- # 检查当前指标值
- kubectl get hpa
- kubectl describe hpa <hpa-name>
复制代码
可能原因:
• 扩容缩容阈值设置不合理
• 缺乏冷却期设置
• 负载变化频繁
解决方案:
- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: stable-hpa
- spec:
- behavior:
- scaleUp:
- stabilizationWindowSeconds: 60 # 扩容冷却期
- scaleDown:
- stabilizationWindowSeconds: 300 # 缩容冷却期
复制代码
可能原因:
• 新Pod启动后增加了总资源,但负载被平均分配
• 应用启动过程消耗大量资源
解决方案:
- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: adjusted-hpa
- spec:
- metrics:
- - type: Resource
- resource:
- name: cpu
- target:
- type: Utilization
- averageUtilization: 50 # 降低目标利用率,留更多缓冲
- behavior:
- scaleUp:
- policies:
- - type: Pods
- value: 2 # 每次最多增加2个Pod,避免一次性增加过多
- periodSeconds: 60
复制代码
6.2 Cluster Autoscaler常见问题及解决方案
可能原因:
• 云平台配额不足
• 节点模板配置错误
• Pod有特殊调度约束
解决方案:
- # 检查Cluster Autoscaler日志
- kubectl logs -n kube-system <cluster-autoscaler-pod-name>
- # 检查云平台配额
- # AWS示例
- aws service-quotas list-service-quotas --service-code ec2
- # 检查无法调度的Pod
- kubectl get pods --all-namespaces --field-selector spec.nodeName="" --output wide
复制代码
可能原因:
• 节点上有Pod设置了PodDisruptionBudget
• 节点上有系统Pod(如kube-proxy)
• 节点资源利用率未达到缩容阈值
解决方案:
- # 检查节点上的Pod
- kubectl get pods --all-namespaces --field-selector spec.nodeName=<node-name>
- # 检查PodDisruptionBudget
- kubectl get poddisruptionbudgets --all-namespaces
- # 检查Cluster Autoscaler日志
- kubectl logs -n kube-system <cluster-autoscaler-pod-name> | grep scale-down
复制代码
可能原因:
• 扩容缩容阈值设置不合理
• 负载波动大
• 节点池配置不合理
解决方案:
- # Cluster Autoscaler配置示例
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: cluster-autoscaler
- namespace: kube-system
- spec:
- template:
- spec:
- containers:
- - name: cluster-autoscaler
- command:
- - ./cluster-autoscaler
- - --balance-similar-node-groups
- - --expander=priority
- - --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/<cluster-name>
- - --scale-down-utilization-threshold=0.5 # 节点资源利用率低于50%时考虑缩容
- - --scale-down-unneeded-time=10m # 节点连续10分钟不需要时才缩容
- - --scale-down-delay-after-add=1h # 扩容后1小时内不缩容
- - --scale-down-delay-after-delete=0s
- - --scale-down-delay-after-failure=3m # 缩容失败后3分钟内不重试
复制代码
6.3 VPA常见问题及解决方案
可能原因:
• VPA组件未正确安装
• 目标控制器不支持VPA
• VPA配置错误
解决方案:
- # 检查VPA组件状态
- kubectl get pods -n kube-system | grep vpa
- # 检查VPA对象
- kubectl get vpa
- kubectl describe vpa <vpa-name>
- # 检查VPA推荐值
- kubectl describe vpa <vpa-name> | grep -A 20 "Recommendation"
复制代码
可能原因:
• VPA和HPA同时管理CPU/内存资源
• 资源调整相互干扰
解决方案:
- # HPA配置:使用自定义指标
- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: hpa-with-vpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: app
- minReplicas: 2
- maxReplicas: 10
- metrics:
- - type: Pods
- pods:
- metric:
- name: http_requests_per_second
- target:
- type: AverageValue
- averageValue: 500m
- # VPA配置:管理CPU/内存
- apiVersion: autoscaling.k8s.io/v1
- kind: VerticalPodAutoscaler
- metadata:
- name: vpa-with-hpa
- spec:
- targetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: app
- updatePolicy:
- updateMode: "Auto"
- resourcePolicy:
- containerPolicies:
- - containerName: "*"
- controlledResources: ["cpu", "memory"]
复制代码
七、案例分析
7.1 电商平台大促活动扩容缩容实践
某电商平台计划进行一次大型促销活动,预计流量会是平时的10倍。平台使用K8s管理微服务架构,需要设计一套完整的扩容缩容方案来应对流量高峰。
电商平台的微服务架构包括:
• 接入层:API网关、负载均衡
• 业务层:用户服务、商品服务、订单服务、支付服务等
• 数据层:数据库、缓存、消息队列
- # API网关HPA配置
- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: gateway-hpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: api-gateway
- minReplicas: 5
- maxReplicas: 50
- metrics:
- - type: Resource
- resource:
- name: cpu
- target:
- type: Utilization
- averageUtilization: 60
- - type: Pods
- pods:
- metric:
- name: requests_per_second
- target:
- type: AverageValue
- averageValue: 2k
- behavior:
- scaleUp:
- stabilizationWindowSeconds: 30
- policies:
- - type: Percent
- value: 100
- periodSeconds: 60
- - type: Pods
- value: 10
- periodSeconds: 60
- selectPolicy: Max
- scaleDown:
- stabilizationWindowSeconds: 600
复制代码- # 核心业务服务HPA配置
- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: order-service-hpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: order-service
- minReplicas: 10
- maxReplicas: 100
- metrics:
- - type: Resource
- resource:
- name: cpu
- target:
- type: Utilization
- averageUtilization: 65
- - type: External
- external:
- metric:
- name: queue_length
- selector:
- matchLabels:
- queue: order-queue
- target:
- type: AverageValue
- averageValue: 50
- behavior:
- scaleUp:
- stabilizationWindowSeconds: 60
- policies:
- - type: Percent
- value: 50
- periodSeconds: 60
- - type: Pods
- value: 20
- periodSeconds: 60
- selectPolicy: Max
- scaleDown:
- stabilizationWindowSeconds: 1200
复制代码- # 数据库StatefulSet配置
- apiVersion: apps/v1
- kind: StatefulSet
- metadata:
- name: mysql
- spec:
- serviceName: mysql
- replicas: 3 # 基础副本数
- template:
- spec:
- containers:
- - name: mysql
- image: mysql:8.0
- resources:
- requests:
- cpu: "2"
- memory: "8Gi"
- limits:
- cpu: "4"
- memory: "16Gi"
- ---
- # 数据库HPA配置
- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: mysql-hpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: StatefulSet
- name: mysql
- minReplicas: 3
- maxReplicas: 10
- metrics:
- - type: Resource
- resource:
- name: cpu
- target:
- type: Utilization
- averageUtilization: 70
- - type: Resource
- resource:
- name: memory
- target:
- type: Utilization
- averageUtilization: 80
- behavior:
- scaleUp:
- stabilizationWindowSeconds: 300 # 数据库扩容需要更长时间
- scaleDown:
- stabilizationWindowSeconds: 3600 # 数据库缩容要更谨慎
复制代码- # 预测性扩容CronJob
- apiVersion: batch/v1beta1
- kind: CronJob
- metadata:
- name: predictive-scaling
- spec:
- schedule: "0 8,12,18 * * *" # 在流量高峰前执行
- jobTemplate:
- spec:
- template:
- spec:
- containers:
- - name: scaler
- image: curlimages/curl
- command:
- - /bin/sh
- - -c
- - |
- # 在活动开始前2小时扩容
- curl -X PATCH -H "Content-Type: application/merge-patch+json" \
- -d '{"spec":{"replicas":50}}' \
- http://kubernetes.default.svc/apis/apps/v1/namespaces/default/deployments/api-gateway
-
- curl -X PATCH -H "Content-Type: application/merge-patch+json" \
- -d '{"spec":{"replicas":80}}' \
- http://kubernetes.default.svc/apis/apps/v1/namespaces/default/deployments/order-service
- restartPolicy: OnFailure
复制代码- # Cluster Autoscaler配置
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: cluster-autoscaler
- namespace: kube-system
- spec:
- template:
- spec:
- containers:
- - name: cluster-autoscaler
- image: k8s.gcr.io/autoscaling/cluster-autoscaler:v1.22.2
- command:
- - ./cluster-autoscaler
- - --cloud-provider=aws
- - --namespace=kube-system
- - --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/ecommerce-cluster
- - --balance-similar-node-groups
- - --expander=least-waste
- - --scale-down-utilization-threshold=0.5
- - --scale-down-unneeded-time=10m
- - --skip-nodes-with-local-storage=false
- - --skip-nodes-with-system-pods=false
复制代码
1. 活动前准备:通过预测性扩容,在活动开始前2小时将关键服务扩容到预期容量集群节点数从20个增加到80个
2. 通过预测性扩容,在活动开始前2小时将关键服务扩容到预期容量
3. 集群节点数从20个增加到80个
4. 活动期间:HPA根据实际负载自动调整Pod数量,API网关峰值达到45个副本,订单服务峰值达到85个副本Cluster Autoscaler根据Pod调度需求自动增加节点,峰值达到120个节点系统响应时间保持在200ms以内,无服务中断
5. HPA根据实际负载自动调整Pod数量,API网关峰值达到45个副本,订单服务峰值达到85个副本
6. Cluster Autoscaler根据Pod调度需求自动增加节点,峰值达到120个节点
7. 系统响应时间保持在200ms以内,无服务中断
8. 活动后:流量逐渐下降,HPA开始缩容Pod数量2小时后,Cluster Autoscaler开始缩容节点6小时后,系统恢复到正常规模,节点数降至25个
9. 流量逐渐下降,HPA开始缩容Pod数量
10. 2小时后,Cluster Autoscaler开始缩容节点
11. 6小时后,系统恢复到正常规模,节点数降至25个
活动前准备:
• 通过预测性扩容,在活动开始前2小时将关键服务扩容到预期容量
• 集群节点数从20个增加到80个
活动期间:
• HPA根据实际负载自动调整Pod数量,API网关峰值达到45个副本,订单服务峰值达到85个副本
• Cluster Autoscaler根据Pod调度需求自动增加节点,峰值达到120个节点
• 系统响应时间保持在200ms以内,无服务中断
活动后:
• 流量逐渐下降,HPA开始缩容Pod数量
• 2小时后,Cluster Autoscaler开始缩容节点
• 6小时后,系统恢复到正常规模,节点数降至25个
1. 预测性扩容与反应性扩容结合:预测性扩容可以提前应对已知的高峰,反应性扩容处理突发流量。
2. 分层扩容策略:不同层次的服务采用不同的扩容策略,接入层需要快速响应,数据层需要稳定变化。
3. 合理的冷却期设置:活动期间使用较短的扩容冷却期和较长的缩容冷却期,避免抖动。
4. 资源预留:为关键服务预留足够的资源缓冲,确保系统稳定性。
5. 监控和告警:设置全面的监控和告警,及时发现和处理异常情况。
预测性扩容与反应性扩容结合:预测性扩容可以提前应对已知的高峰,反应性扩容处理突发流量。
分层扩容策略:不同层次的服务采用不同的扩容策略,接入层需要快速响应,数据层需要稳定变化。
合理的冷却期设置:活动期间使用较短的扩容冷却期和较长的缩容冷却期,避免抖动。
资源预留:为关键服务预留足够的资源缓冲,确保系统稳定性。
监控和告警:设置全面的监控和告警,及时发现和处理异常情况。
7.2 流媒体服务负载波动应对案例
某流媒体平台提供视频点播和直播服务,用户访问模式呈现明显的峰谷特征(晚间高峰、凌晨低谷)。平台需要在保证服务质量的同时,优化资源成本。
1. 负载波动大:高峰期流量是低谷期的10倍以上
2. 实时性要求高:视频流需要低延迟,不能有缓冲
3. 成本敏感:需要优化资源使用,降低运营成本
4. 服务多样:点播、直播、转码等不同服务有不同的负载特征
- # 点播服务HPA配置
- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: vod-hpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: vod-service
- minReplicas: 2
- maxReplicas: 50
- metrics:
- - type: Resource
- resource:
- name: cpu
- target:
- type: Utilization
- averageUtilization: 70
- - type: External
- external:
- metric:
- name: active_streams
- target:
- type: AverageValue
- averageValue: 100
- behavior:
- scaleUp:
- stabilizationWindowSeconds: 60
- policies:
- - type: Percent
- value: 50
- periodSeconds: 60
- - type: Pods
- value: 5
- periodSeconds: 60
- selectPolicy: Max
- scaleDown:
- stabilizationWindowSeconds: 600
复制代码- # 直播服务HPA配置
- apiVersion: autoscaling/v2
- kind: HorizontalPodAutoscaler
- metadata:
- name: live-hpa
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: live-service
- minReplicas: 3
- maxReplicas: 100
- metrics:
- - type: Resource
- resource:
- name: cpu
- target:
- type: Utilization
- averageUtilization: 60
- - type: External
- external:
- metric:
- name: concurrent_viewers
- target:
- type: AverageValue
- averageValue: 500
- behavior:
- scaleUp:
- stabilizationWindowSeconds: 30 # 直播需要更快的响应
- policies:
- - type: Percent
- value: 100
- periodSeconds: 30
- - type: Pods
- value: 10
- periodSeconds: 30
- selectPolicy: Max
- scaleDown:
- stabilizationWindowSeconds: 1800 # 直播结束后缓慢缩容
复制代码- # 转码服务ScaledObject配置
- apiVersion: keda.sh/v1alpha1
- kind: ScaledObject
- metadata:
- name: video-transcoder
- namespace: default
- spec:
- scaleTargetRef:
- name: transcoder-deployment
- minReplicaCount: 0 # 无任务时缩容到0
- maxReplicaCount: 50
- pollingInterval: 30
- cooldownPeriod: 300
- triggers:
- - type: kafka
- metadata:
- bootstrapServers: kafka-cluster:9092
- topic: video-transcode-jobs
- consumerGroup: transcoder-group
- lagThreshold: "10"
复制代码- # 基于CronJob的预测性扩容
- apiVersion: batch/v1beta1
- kind: CronJob
- metadata:
- name: evening-scale-up
- spec:
- schedule: "0 18 * * *" # 每天18:00执行
- jobTemplate:
- spec:
- template:
- spec:
- containers:
- - name: scaler
- image: bitnami/kubectl
- command:
- - /bin/sh
- - -c
- - |
- # 晚间高峰前扩容
- kubectl scale --replicas=20 deployment/vod-service
- kubectl scale --replicas=30 deployment/live-service
- restartPolicy: OnFailure
- ---
- apiVersion: batch/v1beta1
- kind: CronJob
- metadata:
- name: morning-scale-down
- spec:
- schedule: "0 6 * * *" # 每天6:00执行
- jobTemplate:
- spec:
- template:
- spec:
- containers:
- - name: scaler
- image: bitnami/kubectl
- command:
- - /bin/sh
- - -c
- - |
- # 早间低峰期缩容
- kubectl scale --replicas=5 deployment/vod-service
- kubectl scale --replicas=8 deployment/live-service
- restartPolicy: OnFailure
复制代码- # 混合节点池配置
- apiVersion: eksctl.io/v1alpha5
- kind: ClusterConfig
- metadata:
- name: streaming-cluster
- region: us-west-2
- nodeGroups:
- - name: on-demand-ng
- instanceType: c5.2xlarge
- desiredCapacity: 5
- minSize: 3
- maxSize: 20
- labels:
- node-type: on-demand
- tags:
- k8s.io/cluster-autoscaler/node-template/label/node-type: on-demand
- - name: spot-ng
- instanceType: c5.2xlarge
- desiredCapacity: 2
- minSize: 0
- maxSize: 30
- spot: true
- labels:
- node-type: spot
- taints:
- - key: node-type
- value: spot
- effect: PreferNoSchedule
- tags:
- k8s.io/cluster-autoscaler/node-template/label/node-type: spot
- k8s.io/cluster-autoscaler/node-template/taint/node-type: spot:PreferNoSchedule
复制代码
1. 资源使用优化:通过混合节点池策略,使用60%的Spot实例,节省了40%的计算成本转码服务在无任务时缩容到0,进一步节省资源
2. 通过混合节点池策略,使用60%的Spot实例,节省了40%的计算成本
3. 转码服务在无任务时缩容到0,进一步节省资源
4. 服务质量提升:直播服务通过快速扩容,能够应对突发的流量高峰点播服务通过预测性扩容,在晚间高峰前提前准备资源
5. 直播服务通过快速扩容,能够应对突发的流量高峰
6. 点播服务通过预测性扩容,在晚间高峰前提前准备资源
7. 运维效率提升:自动化扩容缩容减少了人工干预基于时间的预测性扩容与基于负载的反应性扩容相结合,提高了系统响应速度
8. 自动化扩容缩容减少了人工干预
9. 基于时间的预测性扩容与基于负载的反应性扩容相结合,提高了系统响应速度
资源使用优化:
• 通过混合节点池策略,使用60%的Spot实例,节省了40%的计算成本
• 转码服务在无任务时缩容到0,进一步节省资源
服务质量提升:
• 直播服务通过快速扩容,能够应对突发的流量高峰
• 点播服务通过预测性扩容,在晚间高峰前提前准备资源
运维效率提升:
• 自动化扩容缩容减少了人工干预
• 基于时间的预测性扩容与基于负载的反应性扩容相结合,提高了系统响应速度
1. 差异化扩容策略:不同类型的服务采用不同的扩容策略,直播服务需要快速响应,转码服务可以延迟响应。
2. 混合资源池:结合按需实例和Spot实例,在保证服务稳定性的同时降低成本。
3. 多指标触发:结合资源指标和业务指标(如并发用户数、活跃流数)进行扩容决策。
4. 预测与反应结合:基于时间的预测性扩容应对规律性高峰,基于负载的反应性扩容应对突发流量。
5. 零副本缩容:对于批处理任务(如转码),使用KEDA实现无任务时缩容到0,最大化资源利用率。
差异化扩容策略:不同类型的服务采用不同的扩容策略,直播服务需要快速响应,转码服务可以延迟响应。
混合资源池:结合按需实例和Spot实例,在保证服务稳定性的同时降低成本。
多指标触发:结合资源指标和业务指标(如并发用户数、活跃流数)进行扩容决策。
预测与反应结合:基于时间的预测性扩容应对规律性高峰,基于负载的反应性扩容应对突发流量。
零副本缩容:对于批处理任务(如转码),使用KEDA实现无任务时缩容到0,最大化资源利用率。
八、总结与展望
8.1 最佳实践总结
通过本文的详细分析,我们可以总结出K8s集群扩容缩容的最佳实践:
1. 合理的资源设置:准确评估资源需求,设置合理的requests和limits使用VPA辅助优化资源配置
2. 准确评估资源需求,设置合理的requests和limits
3. 使用VPA辅助优化资源配置
4. 多层次的扩容缩容策略:Pod级别:使用HPA、VPA和KEDA节点级别:使用Cluster Autoscaler根据服务特点选择合适的扩容缩容方式
5. Pod级别:使用HPA、VPA和KEDA
6. 节点级别:使用Cluster Autoscaler
7. 根据服务特点选择合适的扩容缩容方式
8. 避免扩容缩容抖动:设置合理的冷却期使用预测性扩容应对已知高峰避免过于敏感的阈值设置
9. 设置合理的冷却期
10. 使用预测性扩容应对已知高峰
11. 避免过于敏感的阈值设置
12. 混合扩容缩容策略:预测性扩容与反应性扩容结合基于时间、基于负载、基于事件的多种触发方式
13. 预测性扩容与反应性扩容结合
14. 基于时间、基于负载、基于事件的多种触发方式
15. 监控和优化:全面监控扩容缩容行为持续优化配置参数建立完善的告警机制
16. 全面监控扩容缩容行为
17. 持续优化配置参数
18. 建立完善的告警机制
合理的资源设置:
• 准确评估资源需求,设置合理的requests和limits
• 使用VPA辅助优化资源配置
多层次的扩容缩容策略:
• Pod级别:使用HPA、VPA和KEDA
• 节点级别:使用Cluster Autoscaler
• 根据服务特点选择合适的扩容缩容方式
避免扩容缩容抖动:
• 设置合理的冷却期
• 使用预测性扩容应对已知高峰
• 避免过于敏感的阈值设置
混合扩容缩容策略:
• 预测性扩容与反应性扩容结合
• 基于时间、基于负载、基于事件的多种触发方式
监控和优化:
• 全面监控扩容缩容行为
• 持续优化配置参数
• 建立完善的告警机制
8.2 未来发展趋势
K8s扩容缩容技术仍在不断发展,未来可能出现以下趋势:
1. AI驱动的智能扩容缩容:使用机器学习算法预测负载变化自动优化扩容缩容参数基于历史数据调整策略
2. 使用机器学习算法预测负载变化
3. 自动优化扩容缩容参数
4. 基于历史数据调整策略
5. 更精细的资源控制:细粒度的资源分配和调整支持更多类型的资源指标更智能的资源调度算法
6. 细粒度的资源分配和调整
7. 支持更多类型的资源指标
8. 更智能的资源调度算法
9. 多云和混合云环境下的统一扩容缩容:跨云平台的资源调度和扩容缩容混合云环境下的资源优化边缘计算场景下的扩容缩容
10. 跨云平台的资源调度和扩容缩容
11. 混合云环境下的资源优化
12. 边缘计算场景下的扩容缩容
13. 更高级的自动化:完全自动化的扩容缩容策略优化自适应的扩容缩容算法基于意图的资源管理
14. 完全自动化的扩容缩容策略优化
15. 自适应的扩容缩容算法
16. 基于意图的资源管理
AI驱动的智能扩容缩容:
• 使用机器学习算法预测负载变化
• 自动优化扩容缩容参数
• 基于历史数据调整策略
更精细的资源控制:
• 细粒度的资源分配和调整
• 支持更多类型的资源指标
• 更智能的资源调度算法
多云和混合云环境下的统一扩容缩容:
• 跨云平台的资源调度和扩容缩容
• 混合云环境下的资源优化
• 边缘计算场景下的扩容缩容
更高级的自动化:
• 完全自动化的扩容缩容策略优化
• 自适应的扩容缩容算法
• 基于意图的资源管理
8.3 结语
K8s集群扩容缩容是云原生应用运维的核心能力,通过合理的策略和配置,可以有效应对业务负载变化,保证服务质量的同时优化资源成本。本文从基础概念到高级实践,全面解析了K8s集群扩容缩容的完整解决方案,希望能为读者提供有价值的参考和指导。
在实际应用中,需要根据具体的业务场景和需求,选择合适的扩容缩容策略,并通过持续的监控和优化,不断提升系统的弹性和效率。随着技术的不断发展,K8s扩容缩容能力也将不断进化,为云原生应用提供更强大的支持。 |
|