Kubernetes 弹性伸缩完全指南:HPA 与 VPA 实战教程
·
文章目录
- Kubernetes 弹性伸缩完全指南:HPA 与 VPA 实战教程
-
- 前言
- 一、水平自动伸缩(HPA)
-
- 1.1 HPA 介绍
- 1.2 依赖组件:metrics-server 部署
- 1.3 HPA 基础案例实战
- 1.4 进阶案例:基于 Prometheus 的自定义指标 HPA
- 二、垂直自动伸缩(VPA)
- 三、总结
Kubernetes 弹性伸缩完全指南:HPA 与 VPA 实战教程
前言
在 Kubernetes 集群中,弹性伸缩是应对业务流量波动的核心能力,能实现资源利用率与服务可用性的动态平衡。本文基于原 PDF 的逻辑结构,详细拆解水平自动伸缩(HPA)和垂直自动伸缩(VPA)的原理、部署流程及实战案例,所有操作均提供完整命令和配置示例,便于直接落地实践。
一、水平自动伸缩(HPA)
1.1 HPA 介绍
HPA(Horizontal Pod Autoscaler)通过监控指标自动调整 Deployment、ReplicaSet 等资源的 Pod 副本数,适配业务负载变化。
- 适用场景:无状态服务的动态扩缩容,支持多类指标驱动
- 不适用对象:DaemonSet 等无法扩缩的资源
- 核心指标类型:
- Resource metrics:CPU、内存利用率(基础指标)
- Pod metrics:网络利用率、流量等 Pod 级指标
- Object metrics:Ingress 每秒请求数等对象指标
- Custom metrics:服务响应时间等自定义业务指标
1.2 依赖组件:metrics-server 部署
metrics-server 是 K8s 集群资源监控的核心组件,为 HPA 提供 CPU、内存等指标数据,部署步骤如下:
1.2.1 下载并修改配置文件
# 下载组件配置文件
wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml -O metrics-server-components.yaml
# 替换镜像源为阿里云(加速下载)
sed -i 's/registry.k8s.io\/metrics-server/registry.cn-hangzhou.aliyuncs.com\/google_containers/g' metrics-server-components.yaml
# 编辑配置文件,添加 insecure-tls 参数(v0.8.0+版本必需)
vim metrics-server-components.yaml
1.2.2 关键配置修改
在containers.args中添加--kubelet-insecure-tls,完整配置片段如下:
containers:
- args:
- --cert-dir=/tmp
- --secure-port=10250
- --kubelet-insecure-tls # 新增:跳过kubelet证书验证
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --kubelet-use-node-status-port
- --metric-resolution=15s
image: registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server:v0.8.0
1.2.3 部署并验证
# 应用配置
kubectl apply -f metrics-server-components.yaml
# 查看部署状态(需等待Pod就绪)
kubectl get pods -n kube-system | grep metrics-server
# 强制删除异常Pod(如有Terminating状态)
kubectl delete pod <异常Pod名称> -n kube-system --grace-period=0 --force
# 验证指标采集功能
kubectl top node # 查看节点资源使用
kubectl top pod -n kube-system # 查看Pod资源使用
1.3 HPA 基础案例实战
以 Nginx 服务为例,实现基于 CPU 利用率的自动扩缩容。
1.3.1 部署 Nginx 应用及服务
创建nginx01-svc.yaml配置文件:
# Deployment配置
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
resources:
requests:
cpu: 200m # CPU请求值(HPA计算利用率的基准)
memory: 100Mi
---
# Service配置(NodePort类型)
apiVersion: v1
kind: Service
metadata:
name: nginx
namespace: default
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
selector:
app: nginx
应用配置并验证:
# 部署应用
kubectl apply -f nginx01-svc.yaml
# 查看Pod和Service状态
kubectl get pods,svc
# 预期输出:2个Nginx Pod运行,Service暴露NodePort(如80:30699/TCP)
# 访问验证(替换为实际NodeIP和NodePort)
curl http://192.168.18.129:30699
1.3.2 创建 HPA 规则
创建nginx-hpa.yaml配置文件:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-hpa
namespace: default
spec:
scaleTargetRef: # 关联目标Deployment
apiVersion: apps/v1
kind: Deployment
name: nginx # 必须与Deployment名称一致
minReplicas: 1 # 最小副本数
maxReplicas: 10 # 最大副本数
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50 # CPU利用率阈值:超过50%扩容
应用 HPA 配置并验证:
# 部署HPA
kubectl apply -f nginx-hpa.yaml
# 查看HPA状态
kubectl get hpa
# 预期输出:TARGETS显示当前CPU利用率/目标值(如0%/50%)
1.3.3 压测验证自动扩容
# 安装压测工具
yum install -y httpd-tools
# 执行压测(并发10000,总请求100亿,替换为实际Service地址)
ab -c 10000 -n 10000000000 http://192.168.18.129:30699/
# 实时观测Pod数量变化
watch kubectl get pods
# 预期结果:Pod数量从2个扩容至9个左右
1.3.4 验证自动缩容
停止压测后,等待 5 分钟左右,HPA 会自动缩减副本数至最小阈值:
# 查看最终Pod状态
kubectl get pods
# 预期结果:Pod数量恢复至1个
1.4 进阶案例:基于 Prometheus 的自定义指标 HPA
通过 Prometheus 采集 Nginx 请求指标,实现基于 QPS 的自动扩缩容。
1.4.1 环境准备:部署 metallb(负载均衡)
# 部署metallb
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.15.2/config/manifests/metallb-native.yaml
# 创建IP地址池配置(ippool.yaml)
cat > ippool.yaml << EOF
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- 192.168.18.240-192.168.18.250
EOF
# 创建二层通告配置(l2.yaml)
cat > l2.yaml << EOF
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example
namespace: metallb-system
EOF
# 应用配置
kubectl apply -f ippool.yaml -f l2.yaml
# 验证metallb状态
kubectl get pods -n metallb-system
1.4.2 部署 Ingress Nginx
# 下载部署文件(v1.13.2版本)
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.13.2/deploy/static/provider/cloud/deploy.yaml
# 编辑配置,修改externalTrafficPolicy为Cluster
vim deploy.yaml
# 找到347行左右,将Local改为Cluster:
# externalTrafficPolicy: Cluster
# 应用配置
kubectl apply -f deploy.yaml
# 验证部署(需等待5分钟左右)
kubectl get pods,svc -n ingress-nginx
# 预期输出:Ingress Controller Pod运行,Service分配IP(如192.168.18.240)
1.4.3 部署 Prometheus(Helm 方式)
1.4.3.1 安装 Helm
# 下载Helm二进制包(v3.19.0)
wget https://get.helm.sh/helm-v3.19.0-linux-amd64.tar.gz
# 解压并安装
tar zxvf helm-v3.19.0-linux-amd64.tar.gz
mv linux-amd64/helm /usr/bin/
# 验证Helm版本
helm version
1.4.3.2 部署 Prometheus Stack
# 添加Prometheus仓库
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
# 创建配置文件目录
mkdir promedir && cd promedir
# 导出默认配置并修改
helm show values prometheus-community/kube-prometheus-stack --version 77.6.2 > kube-prometheus-stack.yaml
# 启用全量服务发现(4138行左右)
vim kube-prometheus-stack.yaml
# 修改:serviceMonitorSelectorNilUsesHelmValues: false
# 部署Prometheus(命名为kps,创建monitoring命名空间)
helm install kps prometheus-community/kube-prometheus-stack --version 77.6.2 -f ./kube-prometheus-stack.yaml -n monitoring --create-namespace --debug
# 验证部署
kubectl get pods -n monitoring -l "release=kps"
1.4.4 配置 Prometheus 访问(Ingress)
# 创建Prometheus Ingress配置
cat > prometheus-ingress.yaml << EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-prometheus
namespace: monitoring
spec:
ingressClassName: nginx
rules:
- host: prometheus.abner.com
http:
paths:
- path: "/"
pathType: Prefix
backend:
service:
name: kps-kube-prometheus-stack-prometheus
port:
number: 9090
EOF
# 创建Grafana Ingress配置
cat > grafana-ingress.yaml << EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-grafana
namespace: monitoring
spec:
ingressClassName: nginx
rules:
- host: grafana.abner.com
http:
paths:
- path: "/"
pathType: Prefix
backend:
service:
name: kps-grafana
port:
number: 80
EOF
# 应用配置
kubectl apply -f prometheus-ingress.yaml -f grafana-ingress.yaml
# 配置本地DNS(Windows修改hosts文件)
# 编辑 C:\Windows\System32\drivers\etc\hosts,添加:
# 192.168.18.240 prometheus.abner.com
# 192.168.18.240 grafana.abner.com
1.4.5 部署带监控的 Nginx 应用
1.4.5.1 配置 Nginx 监控
# 创建Nginx配置文件(启用status模块)
mkdir nginxdir && cd nginxdir
cat > nginx.conf << EOF
worker_processes 1;
events { worker_connections 1024; }
http {
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html;
}
location /basic_status {
stub_status;
allow 127.0.0.1;
deny all;
}
}
}
EOF
# 创建ConfigMap
kubectl create configmap nginx-config --from-file=nginx.conf
1.4.5.2 部署 Nginx 及 Exporter
创建nginx.yaml配置文件:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-with-exporter
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.26-alpine
ports:
- containerPort: 80
volumeMounts:
- mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
name: nginx-config-volume
resources:
requests:
cpu: 100m
memory: 100Mi
- name: nginx-prometheus-exporter
image: nginx/nginx-prometheus-exporter:latest
args: ["-nginx.scrape-uri=http://localhost/basic_status"]
ports:
- containerPort: 9113
name: exporter-port
resources:
requests:
cpu: 50m
memory: 100Mi
volumes:
- name: nginx-config-volume
configMap:
name: nginx-config
---
apiVersion: v1
kind: Service
metadata:
name: nginx
namespace: default
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
selector:
app: nginx
应用配置并验证:
kubectl apply -f nginx.yaml
kubectl get pods # 预期:2个双容器Pod运行(nginx + exporter)
1.4.6 配置 Prometheus 采集 Nginx 指标
# 编辑Prometheus配置文件
vim kube-prometheus-stack.yaml
# 添加额外采集规则(注意对齐格式)
additionalScrapeConfigs:
- job_name: 'nginx'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_container_port_name]
action: keep
regex: exporter-port
- source_labels: [__meta_kubernetes_namespace]
target_label: namespace
- source_labels: [__meta_kubernetes_pod_name]
target_label: pod
# 更新Prometheus配置
helm upgrade kps prometheus-community/kube-prometheus-stack --version 77.6.2 -f ./kube-prometheus-stack.yaml -n monitoring
# 验证采集状态(浏览器访问http://prometheus.abner.com,查看Status->Targets)
1.4.7 部署 Prometheus-adapter(自定义指标桥接)
# 下载适配器配置
helm show values prometheus-community/prometheus-adapter --version 5.1.0 > prometheus-adapter.yaml
# 编辑配置文件
vim prometheus-adapter.yaml
# 修改Prometheus地址(37行左右)
prometheus:
url: http://kps-kube-prometheus-stack-prometheus.monitoring.svc.cluster.local
port: 9090
# 添加自定义指标规则(129行左右)
rules:
default: true
custom:
- seriesQuery: 'nginx_http_requests_total{namespace!="",pod!=""}'
resources:
overrides:
namespace: {resource: "namespace"}
pod: {resource: "pod"}
name:
as: "nginx_http_requests"
metricsQuery: 'sum(rate(nginx_http_requests_total{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)'
# 部署适配器
helm install prometheus-adapter prometheus-community/prometheus-adapter --namespace monitoring --version 5.1.0 -f ./prometheus-adapter.yaml
# 验证自定义指标
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/nginx_http_requests" | jq .
1.4.8 创建基于多指标的 HPA
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-hpa
namespace: default
spec:
maxReplicas: 5
minReplicas: 1
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-with-exporter
metrics:
# CPU利用率指标
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
# 内存使用指标
- type: Resource
resource:
name: memory
target:
type: AverageValue
averageValue: 150Mi
# 自定义QPS指标
- type: Pods
pods:
metric:
name: nginx_http_requests
target:
type: AverageValue
averageValue: 50
应用并验证:
# 部署HPA
kubectl apply -f hpa.yaml
# 查看HPA状态
kubectl get hpa
# 压测验证(并发1000,总请求100万)
ab -c 1000 -n 1000000 http://10.96.221.125/ # 替换为实际Service ClusterIP
# 实时观测Pod扩容
watch kubectl get pods
# 预期结果:Pod从2个扩容至5个,12分钟后自动缩容至1个
二、垂直自动伸缩(VPA)
2.1 VPA 介绍
VPA(Vertical Pod Autoscaler)通过调整 Pod 的 CPU、内存请求值实现垂直扩缩容,适用于数据库等无法水平扩容的有状态服务。
-
核心特性:自动优化资源配置,避免资源浪费或不足
-
优缺点
:
- 优点:提高节点资源利用率,无需手动设置资源阈值
- 缺点:不支持与 HPA 同时使用,扩缩容可能重启 Pod(服务短暂中断)
-
更新模式(updateMode)
:
- Off:仅显示资源推荐,不执行更新
- Initial:仅在 Pod 创建时应用推荐
- Recreate:删除旧 Pod 并创建新 Pod 应用推荐
- Auto:优先在线更新,失败则重建 Pod(默认模式)
2.2 VPA 部署
2.2.1 环境准备:升级依赖组件
# 升级openssl(所有节点执行)
wget -O /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo
yum install -y openssl-devel openssl11 openssl11-devel
rm -rf `which openssl`
ln -s /usr/bin/openssl11 /usr/bin/openssl
openssl version # 验证版本(需为1.1.1+)
# 升级git(需2.23+版本)
yum remove git -y
yum groupinstall "Development Tools" -y
yum install gettext-devel perl-CPAN perl-devel zlib-devel curl-devel expat-devel -y
wget https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.28.0.tar.gz
tar zxvf git-2.28.0.tar.gz
cd git-2.28.0/
make prefix=/usr/local all
make prefix=/usr/local install
ln -s /usr/local/bin/git /usr/bin/git
git --version # 验证版本
2.2.2 部署 VPA 组件
# 克隆VPA源码
mkdir vpa && cd vpa
git clone https://github.com/kubernetes/autoscaler.git
cd autoscaler/vertical-pod-autoscaler/
# 部署VPA
bash ./hack/vpa-up.sh
# 验证部署状态
kubectl get pods -n kube-system | grep vpa
# 预期输出:vpa-admission-controller、vpa-recommender、vpa-updater三个Pod运行
2.3 VPA 实战案例
2.3.1 案例 1:updateMode=“Off”(仅查看推荐)
# 创建Nginx应用(nginx01.yaml)
cat > nginx01.yaml << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep-nginx01
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.26-alpine
resources:
requests:
cpu: 100m
memory: 250Mi
---
apiVersion: v1
kind: Service
metadata:
name: nginx01-svc
namespace: default
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
selector:
app: nginx
EOF
# 部署应用
kubectl apply -f nginx01.yaml
# 创建VPA配置(nginx-vpa-off.yaml)
cat > nginx-vpa-off.yaml << EOF
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: nginx-vpa-off
namespace: default
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: dep-nginx01
updatePolicy:
updateMode: "Off"
resourcePolicy:
containerPolicies:
- containerName: "nginx"
minAllowed:
cpu: "250m"
memory: "100Mi"
maxAllowed:
cpu: "2000m"
memory: "2048Mi"
EOF
# 应用VPA配置
kubectl apply -f nginx-vpa-off.yaml
# 查看资源推荐
kubectl get vpa
# 预期输出:CPU推荐250m,内存推荐131072k
# 压测后验证推荐值(无变化)
ab -c 1000 -n 1000000 http://10.106.168.28/ # 替换为Service ClusterIP
kubectl get vpa
2.3.2 案例 2:updateMode=“Auto”(自动更新资源)
# 创建Nginx应用(nginx02.yaml)
cat > nginx02.yaml << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep-nginx02
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.26-alpine
resources:
requests:
cpu: 100m
memory: 50Mi
---
apiVersion: v1
kind: Service
metadata:
name: nginx02-svc
namespace: default
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
selector:
app: nginx
EOF
# 部署应用
kubectl apply -f nginx02.yaml
# 创建VPA配置(nginx-vpa-auto.yaml)
cat > nginx-vpa-auto.yaml << EOF
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: nginx-vpa-auto
namespace: default
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: dep-nginx02
updatePolicy:
updateMode: "Auto"
resourcePolicy:
containerPolicies:
- containerName: "nginx"
minAllowed:
cpu: "250m"
memory: "100Mi"
maxAllowed:
cpu: "2000m"
memory: "2048Mi"
EOF
# 应用VPA配置
kubectl apply -f nginx-vpa-auto.yaml
# 查看VPA状态
kubectl get vpa
# 验证Pod重建及资源更新
watch kubectl get pods # 观察Pod重建过程
kubectl describe pod <新Pod名称> | grep Requests # 验证CPU/内存已更新为推荐值
三、总结
- HPA:适合无状态服务,通过增加 Pod 副本数应对流量波动,支持多指标组合,无服务中断风险。
- VPA:适合有状态服务,通过优化资源配置提高利用率,需注意更新模式对服务的影响。
- 生产建议:根据服务类型选择伸缩方案,优先使用 HPA;关键服务需提前测试 VPA 的资源推荐合理性,避免扩缩容异常。
更多推荐
所有评论(0)