Prometheus+K8s弹性伸缩综合项目

一、HPA 水平自动伸缩(Horizontal Pod Autoscaler)

1.1 概念

HPA 基于 CPU 利用率(或其他自定义指标)自动扩缩 Deployment / ReplicaSet / ReplicationController 的 Pod 副本数 ;由 K8s API 资源 + 控制器实现,控制器周期性调整副本数,使 Pod 平均指标与目标值匹配。

  • 不适用于 DaemonSet(无法扩缩)。

  • 生产四类指标: 表格

    指标类型 说明 示例
    Resource metrics CPU / 内存利用率(metrics-server 提供) CPU 50%
    Pod metrics Pod 维度指标(网络利用率、流量) 出站带宽
    Object metrics 特定对象指标(Ingress 每秒请求数) requests/sec
    Custom metrics 自定义监控(服务响应时间、QPS) nginx QPS,需 Prometheus Adapter

1.2 前置:部署 metrics-server(提供 CPU / 内存指标)

复制代码
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

⚠️ 报错案例 :v0.8.0 后安全要求高,必须加 --kubelet-insecure-tls,否则拉不到 kubelet 指标、探针失败:

复制代码
containers:
- args:
  - --cert-dir=/tmp
  - --secure-port=10250
  - --kubelet-insecure-tls          # 添加
  - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
  - --metric-resolution=15s

kubectl apply -f metrics-server-components.yaml
# 个别 Pod 长时间 0/1:直接 kubectl delete pod 让 Deployment 重建
kubectl top nodes
kubectl top pods

1.3 案例一:CPU 指标 HPA 实战

① 部署 nginx 应用 + Service

复制代码
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, memory: 100Mi}   # HPA 利用率按 requests 算,必须写 requests
---
apiVersion: v1
kind: Service
metadata: {name: nginx, namespace: default}
spec:
  type: NodePort
  ports: [{port: 80, targetPort: 80}]
  selector: {app: nginx}

② 创建 HPA(autoscaling/v2,CPU 超 50% 扩容,1~10 副本)

复制代码
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata: {name: nginx-hpa, namespace: default}
spec:
  scaleTargetRef:                 # 必须与 Deployment 名称一致
    apiVersion: apps/v1
    kind: Deployment
    name: nginx
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50    # 平均 CPU 利用率 >50% 触发扩容

kubectl apply -f nginx-hpa.yaml
kubectl get hpa     # TARGETS 0%/50%,MINPODS 1,MAXPODS 10

③ 压测与观测

复制代码
yum install -y httpd-tools
ab -c 10000 -n 10000000000 http://192.168.18.129:30699/
# 另开终端 watch kubectl get pods 观测:2 → 9 个 Pod
# 压测停止约 5 分钟后自动缩回 1 个

缩容有冷却窗口(stabilization),指标回落后不会立刻降副本。


二、Prometheus + HPA 自定义指标(按 QPS 伸缩)

2.1 前置环境调整

复制代码
# 验证 metrics-server
kubectl top pods -n kube-system
# kube-proxy 开启 strictARP(MetalLB IPVS 必需)
kubectl edit configmap kube-proxy -n kube-system   # ipvs.strictARP: true
kubectl rollout restart daemonset kube-proxy -n kube-system

2.2 部署 MetalLB(LoadBalancer 地址池,二层模式)

复制代码
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.15.2/config/manifests/metallb-native.yaml

ippool.yaml(地址池):

复制代码
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata: {name: first-pool, namespace: metallb-system}
spec:
  addresses: ["192.168.18.240-192.168.18.250"]

l2.yaml(二层通告):

复制代码
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata: {name: example, namespace: metallb-system}

kubectl apply -f ippool.yaml -f l2.yaml
kubectl get ipaddresspool -n metallb-system

2.3 部署 ingress-nginx(v1.13.2)

复制代码
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.13.2/deploy/static/provider/cloud/deploy.yaml
# 把 externalTrafficPolicy: Local 改为 Cluster(实验环境)
kubectl apply -f deploy.yaml
# 等 5 分钟,controller Service 获 EXTERNAL-IP 192.168.18.240

2.4 Helm 安装 kube-prometheus-stack(Prometheus + Grafana)

复制代码
# 装 Helm3.19.0:解压把 helm 移到 /usr/bin/
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm show values prometheus-community/kube-prometheus-stack --version 77.6.2 > kube-prometheus-stack.yaml

关键修改:serviceMonitorSelectorNilUsesHelmValues: false(关闭只监控本 chart,才能发现所有应用 ServiceMonitor)。

复制代码
helm install kps prometheus-community/kube-prometheus-stack --version 77.6.2 \
  -f ./kube-prometheus-stack.yaml -n monitoring --create-namespace

Ingress 暴露 Prometheus / Grafana:

复制代码
# prometheus-ingress.yaml
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}}}
# grafana-ingress.yaml 同理 host: grafana.abner.com → kps-grafana:80

kubectl apply -f prometheus-ingress.yaml -f grafana-ingress.yaml
# Windows hosts 加 192.168.18.240 prometheus.abner.com / grafana.abner.com
# Grafana 账号在 Secret 里 base64 解码:
kubectl get secret kps-grafana -n monitoring -o yaml
echo -n "YWRtaW4=" | base64 --decode   # admin
echo -n "cHJvbS1vcGVyYXRvcg==" | base64 --decode  # prom-operator

2.5 部署带 exporter 的 nginx 应用

① nginx.conf 开启 stub_status

复制代码
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;
    }
  }
}

kubectl create configmap nginx-config --from-file=nginx.conf

② 双容器 Pod:nginx + nginx-prometheus-exporter

复制代码
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
        imagePullPolicy: IfNotPresent
        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}]   # 端口名供 relabel 筛选
        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}

③ Prometheus 抓取配置(additionalScrapeConfigs)

在 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          # 只保留端口名为 exporter-port 的端点
  - source_labels: [__meta_kubernetes_namespace]
    target_label: namespace
  - source_labels: [__meta_kubernetes_pod_name]
    target_label: pod

helm upgrade kps prometheus-community/kube-prometheus-stack --version 77.6.2 \
  -f ./kube-prometheus-stack.yaml -n monitoring

2.6 部署 prometheus-adapter(关键桥接组件)

作用 :HPA/VPA 无法直接读 Prometheus,Adapter 把 Prometheus 指标转成 K8s 自定义指标 API(custom.metrics.k8s.io)供 HPA 查询。

复制代码
helm show values prometheus-community/prometheus-adapter --version 5.1.0 > prometheus-adapter.yaml

修改:

复制代码
prometheus:
  url: http://kps-kube-prometheus-stack-prometheus.monitoring.svc.cluster.local.
  port: 9090
rules:
  default: true
  custom:
  - seriesQuery: 'nginx_http_requests_total{namespace!="",pod!=""}'
    resources:
      overrides:
        namespace: {resource: "namespace"}
        pod: {resource: "pod"}
    name: {as: "nginx_http_requests"}          # xxx_total → xxx
    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

# 验证自定义指标 API
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/nginx_http_requests" | jq

2.7 三指标 HPA(CPU + 内存 + QPS)

复制代码
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata: {name: nginx-hpa, namespace: default}
spec:
  minReplicas: 1
  maxReplicas: 5
  scaleTargetRef: {apiVersion: apps/v1, kind: Deployment, name: nginx-with-exporter}
  metrics:
  - type: Resource
    resource: {name: cpu, target: {type: Utilization, averageUtilization: 70}}
  - type: Resource
    resource: {name: memory, target: {type: AverageValue, averageValue: 150Mi}}
  - type: Pods
    pods:
      metric: {name: nginx_http_requests}
      target: {type: AverageValue, averageValue: 50}

注意类型差异:CPU 用 Utilization(占 requests 百分比);内存 / QPS 用 AverageValue(绝对值);QPS 指标 type 是 Pods。

复制代码
kubectl apply -f hpa.yaml
kubectl describe hpa nginx-hpa    # 看三指标 current/target 与 Conditions
ab -c 1000 -n 1000000 http://10.96.221.125/

扩容事件(SuccessfulRescale):

复制代码
New size: 2; reason: cpu resource utilization above target
New size: 4; reason: pods metric nginx_http_requests above target
New size: 5; reason: pods metric nginx_http_requests above target

压测停止约 12 分钟后自动缩回 1(All metrics below target)。


三、VPA 垂直 Pod 自动伸缩(Vertical Pod Autoscaler)

3.1 概念与优缺点

VPA 根据资源使用率自动调整单个 Pod 的 CPU / 内存 requests (纵向加资源,而非加 Pod 数)。适合无法靠加副本扩容的场景(如数据库)。

  • 优点:按需分配资源、节点利用率高;自动安排到合适节点;免去压测定 requests;减少人工维护。
  • 缺点 :不能与 HPA 同时使用。

3.2 部署前置(所有节点)

复制代码
# ① 升级 openssl11 并软链
yum install -y openssl-devel openssl11 openssl11-devel
rm -rf $(which openssl) && ln -s /usr/bin/openssl11 /usr/bin/openssl
openssl version    # OpenSSL 1.1.1k

# ② git 低于 2.23 需源码升级到 2.28.0(vpa-up.sh 用了 git switch)
yum remove git -y
yum groupinstall "Development Tools" -y
yum install gettext-devel perl-CPAN perl-devel zlib-devel curl-devel expat-devel -y
tar zxvf git-2.28.0.tar.gz && cd git-2.28.0
make prefix=/usr/local all && make prefix=/usr/local install
rm -rf /usr/bin/git && ln -s /usr/local/bin/git /usr/bin/git

3.3 安装 VPA

复制代码
git clone https://github.com/kubernetes/autoscaler.git
cd autoscaler/vertical-pod-autoscaler/hack
bash vpa-up.sh

自动部署三组件:vpa-recommender(算推荐值)、vpa-updater(驱逐 / 更新)、vpa-admission-controller(准入注入),并生成 TLS 证书。

3.4 updateMode 四种模式(重点对比)

表格

模式 行为
Off 只收集数据、显示推荐值,不修改 Pod(只观察)
Initial 仅 Pod 创建时应用一次推荐,启动后不再调整
Recreate 生成新推荐就终止旧 Pod、重建新 Pod(短暂中断)
Auto 默认;尽量在线调整,无法在线调整则重建 Pod

3.5 案例 A:updateMode: Off(只给推荐)

复制代码
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"}

kubectl get vpa    # MODE=Off,CPU 250m MEM 131072k,PROVIDED=True

压测前后推荐值不变,Pod requests 仍是原来的 100m/250Mi------Off 只展示不生效。

3.6 案例 B:updateMode: Auto(驱逐重建应用推荐值)

复制代码
spec:
  targetRef: {kind: Deployment, name: dep-nginx02}
  updatePolicy: {updateMode: "Auto"}
  resourcePolicy: {containerPolicies: [{containerName: nginx,
    minAllowed: {cpu: "250m", memory: "100Mi"},
    maxAllowed: {cpu: "2000m", memory: "2048Mi"}}]}

kubectl apply -f nginx-vpa-auto.yaml
# Pod 被重建(新 Pod 名出现),describe 看到 requests 变为推荐值
# cpu: 250m, memory: 131072k  ← 自动垂直扩容
kubectl describe pod <新pod>

四、HPA vs VPA 对比表

表格

对比项 HPA 水平伸缩 VPA 垂直伸缩
伸缩方向 增加 / 减少 Pod 数量 调整单 Pod 的 CPU / 内存 requests
适用 无状态 Web、服务(加副本分担流量) 数据库等不便加副本的应用
指标来源 CPU / 内存(metrics-server)或自定义(Prometheus Adapter) 历史资源使用率推荐
典型触发 CPU>50%、QPS>50 实际使用率偏离推荐
能否同用 可与 VPA 冲突,不能同用 不能与 HPA 同用
生效方式 改 Deployment 副本数 Off 观察 / Auto 重建 / Recreate 重建 / Initial 仅创建时

五、全链路组件关系

复制代码
metrics-server ──→ Resource 指标(CPU/内存) ──→ HPA
nginx exporter ──→ Prometheus 抓取 ──→ prometheus-adapter ──→ custom.metrics API ──→ HPA(QPS)
                                                     VPA recommender ──→ updater/admission ──→ Pod requests

思维导图

相关推荐
分布式存储与RustFS2 小时前
镜像仓库的层别只堆本地盘:用 RustFS 给 Harbor 当 S3 后端
运维·云原生·开源·对象存储·分布式存储·s3·性能基准
雪落漂泊4 小时前
Liunux进程(七):程序控制篇(中)
linux·运维·windows
分布式存储与RustFS4 小时前
工作流脚本和依赖 JAR 散在各节点本地盘:用 DolphinScheduler 资源中心接到 RustFS
运维·云原生·开源·对象存储·分布式存储·s3·性能基准
分布式存储与RustFS21 小时前
群晖 NAS 被 C3RB3R 锁了:本地备份一起被加密,RustFS 对象锁为什么删不掉
运维·云原生·开源·对象存储·分布式存储·s3·性能基准
真好啊又活了一天21 小时前
服务器和虚机配置IPV6
运维·服务器·github
东风微鸣21 小时前
把 DeepSeek Harness 装进 K8s
kubernetes·deepseek·harness
zixu_star21 小时前
定时任务是什么?从日常自动化到 AI 应用,软件如何自动执行任务?
运维·人工智能·自动化
AR-26710-21 小时前
Linux Day33——定时任务+lvm
linux·运维
润滑卫士1 天前
液压系统工作粘度窗口等级选型:泵允许粘度范围与油温-粘度匹配计算
运维