1. 安装 KEDA
使用 Helm 安装 KEDA(推荐指定版本以确保兼容性):
helm upgrade --install keda kedacore/keda \
--namespace keda --create-namespace \
--version 2.9.0
✅ 此命令会部署 KEDA Operator、Metrics Server 和相关 CRDs。
2. 部署 podinfo 应用(带 metrics 暴露)
podinfo 是一个轻量级示例应用,自带 /metrics 接口(暴露 http_requests_total 等指标)。
# podinfo-dep.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: podinfo
spec:
replicas: 2
selector:
matchLabels:
app: podinfo
template:
metadata:
labels:
app: podinfo
annotations:
prometheus.io/scrape: "true" # 原生 Prometheus 采集注解(非必需,若用 ServiceMonitor 可省略)
spec:
containers:
- name: podinfod
image: stefanprodan/podinfo:0.0.1
imagePullPolicy: Always
command:
- ./podinfo
- -port=9898
- -logtostderr=true
- -v=2
ports:
- containerPort: 9898
protocol: TCP
readinessProbe:
httpGet:
path: /readyz
port: 9898
initialDelaySeconds: 1
periodSeconds: 2
livenessProbe:
httpGet:
path: /healthz
port: 9898
initialDelaySeconds: 1
periodSeconds: 3
resources:
requests:
memory: "32Mi"
cpu: "1m"
limits:
memory: "256Mi"
cpu: "100m"
volumeMounts:
- name: metadata
mountPath: /etc/podinfod/metadata
readOnly: true
volumes:
- name: metadata
downwardAPI:
items:
- path: "labels"
fieldRef:
fieldPath: metadata.labels
- path: "annotations"
fieldRef:
fieldPath: metadata.annotations
部署:
kubectl apply -f podinfo-dep.yaml
3. 配置 Prometheus 采集指标(使用 ServiceMonitor)
⚠️ 仅适用于 已部署 Prometheus Operator(如 KubeSphere、kube-prometheus-stack)的环境。
3.1 创建 Service(必须命名端口)
# svc.yaml
apiVersion: v1
kind: Service
metadata:
name: podinfo
labels:
app: podinfo
spec:
type: NodePort
selector:
app: podinfo
ports:
- name: metrics # ← 关键:必须命名
port: 9898
targetPort: 9898
nodePort: 31198 # 可选,用于外部访问
protocol: TCP
3.2 创建 ServiceMonitor
# servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: podinfo-servicemonitor
namespace: default
labels:
release: prometheus # 必须匹配 Prometheus 实例的 serviceMonitorSelector
spec:
selector:
matchLabels:
app: podinfo # 匹配 Service 的 labels
namespaceSelector:
matchNames:
- default # 允许监控 default 命名空间
endpoints:
- port: metrics # 必须与 Service 的 port.name 一致
path: /metrics
interval: 30s
scheme: http
应用:
kubectl apply -f svc.yaml
kubectl apply -f servicemonitor.yaml
4. 创建 KEDA ScaledObject(基于 Prometheus QPS)
# scaledobject.yaml
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: podinfo-prometheus-qps
namespace: default
spec:
scaleTargetRef:
name: podinfo # 要扩缩的 Deployment 名称
pollingInterval: 15 # 每 15 秒查询一次 Prometheus
cooldownPeriod: 30 # 缩容冷却时间(秒)
minReplicaCount: 1
maxReplicaCount: 10
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus-k8s.kubesphere-monitoring-system.svc:9090
metricName: http_requests_qps
query: |
scalar(sum(rate(http_requests_total{namespace="default", job="podinfo"}[2m])))
threshold: "2" # QPS > 2 时扩容
💡 提示:
serverAddress需替换为你集群中 Prometheus 的 内部 Service 地址job="podinfo"需在 Prometheus UI 中确认实际标签
部署并验证:
kubectl apply -f scaledobject.yaml
kubectl get hpa # 应看到 keda-hpa-podinfo-prometheus-qps
5. 压测与观察扩缩容行为
5.1 安装压测工具 hey
从 Go 1.17 起,go get 不再用于安装可执行程序。使用:
go install github.com/rakyll/hey@latest
确保 $GOPATH/bin 在 PATH 中:
export PATH="$PATH:$(go env GOPATH)/bin"
5.2 发起压测
hey -n 10000 -q 10 -c 5 http://<K8S_PUBLIC_IP>:31198/
5.3 观察扩容
kubectl get pod -w -l app=podinfo
应看到副本数自动增加。
5.4 观察缩容
停止压测后:
kubectl get pod -w -l app=podinfo
kubectl describe hpa keda-hpa-podinfo-prometheus-qps
6. 缩容延迟解释
即使指标已低于阈值,缩容仍可能延迟,原因如下:
✅ cooldownPeriod: 30
- 作用:每次缩容后,30 秒内禁止再次缩容(KEDA 层面防抖)。
- 注意:不影响首次缩容触发时间。
✅ HPA downscale-stabilization(默认 5 分钟)
- 来源:
kube-controller-manager的参数--horizontal-pod-autoscaler-downscale-stabilization=5m - 作用:HPA 会保留过去 5 分钟内建议的最大副本数,并以此作为当前目标,防止因瞬时流量下降而过早缩容。
- 这是缩容延迟约 5 分钟的主要原因。
- 普通用户无法修改,需集群管理员调整。
📌 结论:在生产环境中,即使
cooldownPeriod=30,缩容生效通常仍需等待约 5 分钟,这是 Kubernetes 的防抖设计,不是配置错误。
7. 附:关键验证命令
# 查看资源状态
kubectl get deploy,svc,pod,hpa,scaledobject -l app=podinfo
# 查看 ScaledObject 详情
kubectl get scaledobject podinfo-prometheus-qps -o yaml
# 查看 HPA 事件(含缩容原因)
kubectl describe hpa keda-hpa-podinfo-prometheus-qps
# 查看 KEDA Operator 日志
kubectl logs -n keda -l app=keda-operator
# 验证 Prometheus 指标(集群内)
kubectl run -it --rm debug --image=busybox --restart=Never -- sh
# 在容器内执行:
wget -qO- "http://prometheus-k8s.kubesphere-monitoring-system.svc:9090/api/v1/query?query=sum(rate(http_requests_total{namespace=\"default\",job=\"podinfo\"}[2m]))"
评论