尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Kubernetes生产实战:HPA自动扩缩容与Helm编排实践
1. 先搞清楚这两个东西到底在解决什么问题1.1 扩容这件事为什么不能靠手点我见过太多团队在 Kubernetes 上跑业务第一年风平浪静第二年一到流量高峰就全员进入“备战状态”。运维盯着 Grafana 看流量流量一涨立刻 kubectl scale deployment流量下去再缩回来。这套手工流程在节点规模小、发布频率低的时候还能忍一旦服务数量上了两位数或者业务本身有明显的波峰波谷手工扩容就成了事故高发区。HPAHorizontal Pod Autoscaler解决的就是“Pod 数量跟着负载自动走”的问题。它的核心逻辑并不复杂持续采集业务指标判断当前副本数是否满足需求不满足就调整 Deployment 的 replicas。难点从来不是 HPA 本身而是你愿不愿意把“扩多少、什么时候扩、扩完稳不稳”这套策略交给控制器以及你能不能把指标和参数配到贴合业务的水平。HPA 适合谁来用只要你的服务是无状态的、支持多副本水平扩展的都值得上 HPA。状态fulset能不能用能用但你要想清楚 session 保持、分布式锁这些事。HPA 不适合什么场景单体应用、有状态服务、以及“加机器也救不了性能”的数据库这些场景扩 Pod 只是自欺欺人。我在生产环境里的原则是无状态接入层和业务处理层必须上 HPA数据层靠缓存和分片扛别把 HPA 当万能药。1.2 YAML 管理为什么需要 Helm再说 Helm。很多人第一次接触 Helm 就一个感觉“不就是把一堆 YAML 打包吗”这么理解不算错但太浅了。Kubernetes 的原生 YAML 有个致命问题不可编程。测试环境和生产环境只是镜像 tag 不同、副本数不同、资源配置不同你就得维护两套几乎一样的 YAML。一旦有 20 个微服务每个服务 10 个 YAML文件数量直接冲破两百你根本分不清哪个文件被改过、哪个文件是废弃的。Helm 引入了一套模板引擎把 YAML 里“变的部分”抽成参数把“不变的部分”固化成模板。部署时传一组 values 进去生成一份完整的、可预测的 YAML。你还可以把一套服务整体打包成 Chart用一条 helm install 命令完成部署用 helm upgrade 完成更新用 helm rollback 回退版本。这套体验用完之后很难回到裸 YAML 时代。不过我要先把话说清楚Helm 不是银弹它管的是“部署与发布”不解决“集群内服务编排”的问题。服务间的依赖关系、启动顺序那是 Operator 和 Init Container 的活。Helm 的价值集中在三个词标准化、参数化、可回滚。标准化的意思是所有服务都用同一套 Chart 结构团队之间的理解成本大幅降低参数化意味着环境差异通过 values 文件隔离而不是靠人肉复制粘贴可回滚意味着每次发布都有完整的版本记录出问题一条命令回到上一版。2. HPA 核心原理与算法拆解2.1 指标采集链路从 cAdvisor 到 HPA 控制器想要配好 HPA必须先理解指标从哪来、走到哪去。我画过很多次这条链路每次给团队讲都会强调HPA 本身不采集任何数据它只负责“读数据、做计算、调副本”。Kubernetes 从 v1.8 开始HPA 的指标来源从 Heapster 迁移到了 metrics-server。metrics-server 从各节点的 kubelet 内置 cAdvisor 拉取 CPU 和内存的实时使用量聚合后通过 Metrics API 对外暴露。HPA 控制器默认每 15 秒horizontal-pod-autoscaler-sync-period通过 API Server 查询一次 Metrics API拿到当前 Pod 的实际用量然后和目标值做比较算出一个期望副本数最后调用 scale 子资源更新工作负载对象。这中间有一个关键点大家容易忽略metrics-server 提供的是“瞬时快照”性质的指标它只保留最近 1-2 分钟的数据并且不存历史。这意味着 HPA 的决策本身就基于最近一段窗口内的观测值。如果你希望 HPA 基于更平滑的、更长窗口的数据做决策就得自己引入 Prometheus Custom Metrics APIHPA 会定期调用自定义指标接口获取数据。这是后面降噪的基础。CPU 指标为什么用“request 的百分比”而不是“节点总 CPU 的百分比”这个问题我在团队里问过很多人一多半答不上来。其实设计意图很明确如果按节点总 CPU 算同一个 Deployment 在不同规格的节点上跑同样的负载算出来的利用率完全不一样伸缩行为会变得不可预测。按 Pod 的 requests 算相当于先定义了一个“基线”然后看实际用量在该基线中的占比。离谱的是很多人把 requests 设得极低比如 CPU requests 只有 50m实际突发冲到 1000mHPA 一看利用率 2000%直接疯狂扩容打到集群资源耗尽。所以记住HPA 的扩缩容行为从你写 requests 那刻起就已经被决定了。2.2 副本数计算一条公式看懂 HPA 的决策逻辑HPA 调节副本数的公式是这样的desiredReplicas ceil(currentReplicas * (currentMetricValue / desiredMetricValue))如果拿 CPU 利用率举例currentMetricValue 是当前所有 Pod 的平均 CPU 利用率desiredMetricValue 是你在 HPA 里配置的 targetAverageUtilization。关键在于当前副本数过低或过高时HPA 还会做一次“修正”desiredReplicas ceil(currentReplicas * (currentMetricValue / desiredMetricValue))当 scaling 事件发生的时候如果 desiredReplicas 和当前副本数相差太大HPA 会限制单次调整的幅度。这个限制由--horizontal-pod-autoscaler-tolerance默认 0.1和扩容/缩容速率窗口共同控制。举个例子当前有 4 个副本平均 CPU 利用率是 90%目标利用率是 50%。那么期望副本数 ceil(4 * (0.9 / 0.5)) ceil(7.2) 8。一个周期内从 4 扩到 8看起来一步到位但实际生产中 Kubernetes 不会直接推到 8它会受到扩容速率和冷却时间的约束。HPA 的扩容策略和缩容策略可以分开配置。默认行为是只要有扩容需求尽快扩容但单步最多翻倍缩容则比较保守需要连续多个周期都观察到低利用率才会执行而且单步最多缩一半。为什么要这样设计因为互联网流量的特点是脉冲式上涨、缓慢回落。扩容慢了会导致请求超时缩容快了会导致抖动和成本震荡。Kubernetes 默认“快速扩容、缓慢缩容”的策略本质上是拿成本换稳定性。不过默认策略只支持“翻倍/减半”这样比较粗糙的步长如果你希望更精细地控制伸缩节奏就需要配置behavior字段。我在后面的实战部分会给出一个完整的配置示例。2.3 冷却窗与降噪为什么一扩容就停不下来“扩上去了不下来”是我听到过最多的 HPA 抱怨。很多人觉得 HPA 有问题其实问题出在指标抖动上。CPU 利用率天然是波动的可能上一秒 80%下一秒 40%再下一秒又 70%。如果 HPA 对这种抖动反应过度就会频繁在扩缩容之间切换造成副本数振荡。这种振荡不仅让集群资源分配不稳定还会导致 Pod 频繁创建销毁引发连接池重连、缓存穿透等一系列连锁反应。Kubernetes 给出的默认解决方案有两个一是容忍度tolerance默认 0.1也就是说当前利用率在目标值上下 10% 的区间内浮动时HPA 认为“已经达标了”不调整副本数。二是冷却时间扩容默认 3 秒缩容默认 5 分钟配合速率限制让缩容动作被大幅放缓。但说实话默认值在真实业务里基本不够用。我自己的经验是扩容侧没问题缩容侧的stabilizationWindowSeconds至少调到 300 秒到 600 秒让缩容决策基于一个更长的稳定窗口避免流量稍微抖一下就缩掉一个副本然后马上又要扩回来。还有一个容易被忽略的点单指标 HPA 的决策是比较“短视”的而生产环境往往是多指标共同作用。比如一个 Web 服务CPU 不高但 P99 延迟已经飙升这时候只盯着 CPU 显然不靠谱。靠自定义指标扩展可以解决但复杂度也随之上升。后面实战部分我会给出一个“CPU QPS 双指标”的配置方案。3. HPA 生产级实战配置3.1 基础配置清单与一次完整部署先从最简单的开始。假设我有一个 Deployment 叫order-service在prod命名空间跑着CPU requests 写得比较合理比如 500m。我要给这个服务配置 HPA目标 CPU 利用率 60%副本数范围 3 到 10。YAML 长这样apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: order-service-hpa namespace: prod spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: order-service minReplicas: 3 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 60创建命令很简单kubectl apply -f hpa.yaml kubectl get hpa -n prod如果你用的是旧版 API 比如autoscaling/v1那只能配 CPU 一个指标。autoscaling/v2才能同时配多个指标和 behavior 策略。我这里直接按 v2 讲v1 没有任何理由继续用了。组件版本需求metrics-server至少 0.6.xKubernetes 至少 1.23。很多老集群配完 HPA 发现没有指标十有八九是 metrics-server 版本太老或者没启动起来。3.2 多指标与自定义指标不要只盯着 CPU生产环境里 CPU 利用率绝不是唯一的伸缩依据甚至很多时候它不是最优依据。典型的反例是一个服务大量时间在等待下游响应CPU 利用率一直很低但它的吞吐已经打满队列堆积严重。这时候 CPU 指标完全无法反映压力必须用 QPS、连接数、队列深度这类更贴近业务的指标。autoscaling/v2支持在同一条 HPA 里配置多个指标控制器会把每个指标算出的期望副本数都列出来然后取最大值。这个设计背后的逻辑很清晰任何一个指标达到瓶颈都应该触发扩容取最大值是最稳的保守策略。spec: metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 60 - type: Pods pods: metric: name: http_requests_per_second target: type: AverageValue averageValue: 800Pods类型的指标表示“每个 Pod 的平均值”适合按每 Pod 指标做伸缩的场景。另一个类型Object则直接引用某个集群对象上的指标比如 Ingress 的 QPS。这里要特别注意使用Pods或Object类型的前提是你已经部署了 Prometheus Adapter 或者其它自定义指标 API 的实现比如阿里云、AWS 的云厂商指标适配器并且配置了相应的指标发现规则。没有这一层HPA 去查询自定义指标时会直接报 “failed to get object metric”。我用过好几种指标适配方案说说实际感受。Prometheus Adapter 最灵活但配置复杂尤其是discovery.rules的写法正则没写对就永远拿不到数据。云厂商的适配器最省心但绑定平台。如果从零搭建我建议先跑通 Prometheus Adapter 一个自定义指标再做多指标 HPA。这个链路涉及组件多一定要一步一步验证。验证命令kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1 | jq .能列出指标列表才说明适配器工作正常。3.3 伸缩行为调优一个参数一个坑HPA 从 v1.18 之后支持behavior字段可以分别定义扩容和缩容的策略。下面这份配置是我在生产环境打磨过很久的模板behavior: scaleUp: stabilizationWindowSeconds: 0 selectPolicy: Max policies: - type: Pods value: 4 periodSeconds: 60 - type: Percent value: 100 periodSeconds: 60 scaleDown: stabilizationWindowSeconds: 600 selectPolicy: Min policies: - type: Pods value: 1 periodSeconds: 300拆开解释。扩容侧我把稳定窗口设为 0意思是不等有需求立即扩。然后两个策略并存4 个 Pod / 60 秒 和 100% / 60 秒selectPolicy: Max取两者中扩得更多的那个也就是说每 60 秒最多翻倍但至少能扩 4 个。这样设计应对突增流量比较从容。缩容侧稳定窗口 600 秒意思是持续 10 分钟观察到低利用率才允许缩容而且策略取 Min每 5 分钟最多缩 1 个 Pod。这个缩容策略非常保守代价是成本下降慢但换来的是稳定。如果你对成本更敏感可以把 Pods 值调成 2periodSeconds 调成 180但请谨慎缩容太快真的是事故发动机。关于stabilizationWindowSeconds我要多说一句它表示的是“在当前这个方向上观测多久的稳定信号才执行动作”。你把它设得越大HPA 的“反应就越迟钝”。我之前调过一个服务缩容稳定窗口设了 1200 秒结果业务波峰过去之后副本数还维持在高位接近 20 分钟成本白白烧了很久。后来改成 600 秒平衡多了。没有万能参数必须根据你的业务周期特征去调整。调试 HPA 时最有用的工具是kubectl describe hpa。它会显示 HPA 的 Events、当前指标值、目标值、以及上一次扩缩容的时间和原因。生产环境排查扩容异常第一步永远是看 Events。然后再用kubectl top pod确认节点上是否能拿到指标。如果top pod有数据但 HPA 看不到恭喜你遇到了 API 聚合层的问题去查kube-aggregator和 APIService 状态。4. Helm 的核心价值与 Chart 结构4.1 Helm 的版本演进与选型Helm 的版本话题是个老生常谈但每次都要提的坑。Helm v2 使用 Tiller 作为集群端组件需要在集群里跑一个带管理员权限的 Pod。这个设计在安全上很糟糕任何能访问 Tiller 的人约等于拿到了集群的超级权限。Helm v3 彻底移除了 Tiller客户端直接通过 kubeconfig 访问 API Server安全性大幅提升。我不理解为什么 2024 年了还有人主动问“要不要用 v2”统一 v3没有商量的余地。Helm v3 的 release 信息默认以 Secret 形式存储在集群里helm list会去读这些 Secret。这带来一个现实问题如果误删了 release 对应的 Secrethelm 就认为这个 release 不存在了但实际工作负载都还跑着。所以备份 Secret 是有必要的在大规模集群里尤其重要。4.2 Chart 目录结构从零开始认识模板机制一个标准 Chart 长这样my-chart/ ├── Chart.yaml ├── values.yaml ├── charts/ # 依赖的子 Chart └── templates/ ├── deployment.yaml ├── service.yaml ├── hpa.yaml ├── ingress.yaml ├── _helpers.tpl # 公共模板函数 └── NOTES.txt # 部署完成后输出的提示信息Chart.yaml是 Chart 的元数据里面必须有name和version。values.yaml是默认参数文件用户在安装时可以用-f覆盖。templates/下放的是 Go template 语法的 YAML 模板Helm 会将模板与 values 合并渲染成最终 YAML。charts/目录用来放依赖的子 Chart如果你要把中间件一起打包进 Chart就放到这里。模板语法的核心是三点一是.Values对象直接读取 values.yaml 中的值二是{{ .Release.Name }}这类内置对象拿到 release 名称和命名空间三是模板函数比如nindent、quote、default。我在 _helpers.tpl 里最常用的函数是生成资源的标准化名称{{- define my-chart.fullname -}} {{- printf %s-%s .Release.Name .Chart.Name | trunc 63 | trimSuffix - -}} {{- end -}}这套公式把release-name和chart-name拼起来截断到 63 字符避免超出 Kubernetes 资源名的长度限制。很多人第一次看到会懵其实它只是表示这段模板函数输出的内容剥离开来不要想得太复杂。你只需要记住模板里出来的{{ }}块会被渲染成最终文本{{-和-}}里的横线是去除前后空白的语法标记。原理通了写起来就顺畅了。5. Helm 落地实操从 Chart 到 Release5.1 完整模板编写示例下面我用一个实际例子走一遍。假设我要为order-service写一套 Chart包含 Deployment、Service 和 HPA。先看values.yamlreplicaCount: 3 image: repository: registry.internal/order-service tag: v1.2.0 pullPolicy: IfNotPresent resources: requests: cpu: 500m memory: 512Mi limits: cpu: 1000m memory: 1Gi hpa: enabled: true minReplicas: 3 maxReplicas: 10 cpuUtilization: 60templates/deployment.yamlapiVersion: apps/v1 kind: Deployment metadata: name: {{ include order-service.fullname . }} labels: app.kubernetes.io/name: {{ include order-service.name . }} app.kubernetes.io/instance: {{ .Release.Name }} spec: replicas: {{ .Values.replicaCount }} selector: matchLabels: app.kubernetes.io/name: {{ include order-service.name . }} app.kubernetes.io/instance: {{ .Release.Name }} template: metadata: labels: app.kubernetes.io/name: {{ include order-service.name . }} app.kubernetes.io/instance: {{ .Release.Name }} spec: containers: - name: {{ .Chart.Name }} image: {{ .Values.image.repository }}:{{ .Values.image.tag }} imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - containerPort: 8080 resources: {{- toYaml .Values.resources | nindent 12 }}这里有个很常用的技巧{{- toYaml .Values.resources | nindent 12 }}。它的作用是把resources这个嵌套对象转成 YAML并且每行缩进 12 个空格。为什么必须用nindent因为如果直接写{{ toYaml .Values.resources }}生成的 YAML 不会有正确的缩进层级渲染出来大概率是坏的。我第一次写模板时在这上面栽过跟头渲染出的 YAML 缩进乱七八糟整个 Deployment 直接报错。以后记住嵌套对象一律toYaml nindent别手写缩进。HPA 模板需要按条件渲染values.yaml里hpa.enabled: true控制是否启用{{- if .Values.hpa.enabled }} apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: {{ include order-service.fullname . }}-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: {{ include order-service.fullname . }} minReplicas: {{ .Values.hpa.minReplicas }} maxReplicas: {{ .Values.hpa.maxReplicas }} metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: {{ .Values.hpa.cpuUtilization }} {{- end }}模板写完后一定要用helm lint做静态检查再跑一次helm template --debug查看渲染出的 YAML 长什么样。这两步能在十秒内发现 90% 的模板错误。我见过太多人直接helm install然后盯着报错日志满头大汗。先把渲染结果过一遍什么问题都清楚了。5.2 安装、升级与回滚发布全流程先用helm install发布 v1.2.0helm install order-service ./order-chart -n prod -f values-prod.yaml-f参数指定环境专属的values-prod.yaml里面覆盖了镜像 tag、replicaCount 等环境相关参数。-n prod指定命名空间。发布完用helm list -n prod查看输出里会显示 release 名称、命名空间、状态、更新的时间戳和 Chart 版本。过了一阵子镜像更新到v1.3.0执行helm upgrade order-service ./order-chart -n prod -f values-prod.yaml --set image.tagv1.3.0这里混用了-f和--set--set是直接在命令行覆盖单个值。生产环境我强烈建议用 values 文件而不是大堆--set因为 values 文件可以进 Git发布记录可追溯。命令行--set只适合临时调试。万一 v1.3.0 出了问题用一条命令回滚helm rollback order-service 55是 revision 编号取决于helm history里列出的版本号。回滚本质上是创建一个新的 release 版本把配置恢复到指定的历史版本。所以不要担心回滚本身会丢版本记录它只是“再做一次升级目标版本是过去某个版本”。5.3 多环境管理与依赖 Chart生产环境里同一个 Chart 要部署到 dev、staging、prod 多个环境。我推荐的目录结构是order-chart/ ├── Chart.yaml ├── values.yaml ├── values-dev.yaml ├── values-staging.yaml ├── values-prod.yaml └── templates/每个环境一份 values 文件内容只有该环境差异化的配置。有人会用--namespace区分环境也有团队用不同的集群这个看你的基础设施怎么组织。核心原则是一样的环境差异进 values公共结构进模板。别把环境相关的硬编码搞到 Deployment 模板里否则环境一多模板就失控了。依赖管理方面如果你的服务依赖 Redis、MySQL 这些中间件可以在Chart.yaml里声明依赖dependencies: - name: redis version: 17.x.x repository: https://charts.bitnami.com/bitnami然后执行helm dependency update下载依赖 Chart 到charts/目录。这样一键部署整个技术栈是很快的但要注意依赖版本和上游 Chart 的兼容性、安全更新是持续的运维负担别为了“一条命令部署全部”把整个中间件生命周期绑在 Helm 上。中间件升级前在 staging 环境完整跑一遍。6. 常见问题与排查技巧实录6.1 HPA 的坑我踩过的都在这了“HPA 一直显示 unknown / unable to fetch metrics”排查路径清晰先kubectl top nodes和kubectl top pods如果这两个命令没数据问题在 metrics-server 或节点 kubelet。如果 top 有数据但 HPA 显示 unknown检查 HPA 的spec.scaleTargetRef是否写对了 Deployment 名字和命名空间再查 metrics-server 是否注册了 APIService。用下面这条命令验证kubectl get apiservices | grep metrics如果状态不是 Available大概率是 kubelet 的--authentication-token-webhook配置有问题或者 metrics-server 的证书没配好。这种问题在自建集群比较常见托管集群一般不用操心。“CPU 利用率虚高 / 虚低”绝大多数情况可以追溯到两个原因。一是 Deployment 里 CPU requests 写得太小比如 50m业务一忙 CPU 利用率轻松到百分之几百HPA 直接扩满。二是冷启动因素Java 应用刚启动时 CPU 飙高几秒后回落HPA 可能因为这一下触发扩容。解决办法是把 requests 调到合理值以及把扩容稳定窗口稍微设大一点。“缩容太慢成本压不下来”这种情况我通常建议拆成两步看第一步确认是否真的持续低负载用kubectl top pods连续观察第二步如果确实低把scaleDown.stabilizationWindowSeconds调小比如从 600 调到 300。但记得缩容调的太激进会导致流量抖动时副本数来回跳小心把服务搞得不稳定。“HPA 扩了副本但 Pod 一直 Pending”这个非常典型。HPA 扩容成功但节点资源不够Pod 调度不上去。kubectl get pods看到一堆 Pendingkubectl describe pod会显示Insufficient cpu。HPA 本身没出问题是集群容量的问题。处理方式分两个层面应用层面给 Deployment 加topologySpreadConstraints和PodDisruptionBudget调度层面可以考虑节点弹性伸缩。集群节点自动扩缩容HPA 才能真的发挥威力否则 HPA 扩到一半被资源卡住上层服务质量还是保不住。6.2 Helm 的坑都是实践的眼泪渲染结果和预期不符改了很久也不知道哪里出了错我的建议是用helm template --debug直接看渲染结果它会把渲染后的 YAML 和报错信息一起输出。还不行就在模板里临时加{{ fail debug }}或者把变量打印出来。最笨但最有效的排查方式逐步简化模板二分法缩小错误范围。别拿着几百行模板强行人肉 trace效率太低。升级时提示 “rendered manifests contain a resource that already exists”这个报错通常意味着两个 release 管理的资源发生了重叠最常见就是资源 name 写死成同一个固定值。解决办法不要手动写资源名统一用include my-chart.fullname .生成带 release 前缀的名字。如果你坚持写固定资源名那不同环境、不同发布版本之间必然冲突。release 更新了但 Pod 没有滚动更新这个坑太经典了。原因几乎都是 Kubernetes Deployment 的模板里没有触发滚动更新的字段。镜像 tag 从 v1.2.0 换成 v1.3.0Deployment 的 template spec 变了确实会触发滚动更新。但如果你改的是 configmap、values 里的环境变量而 Deployment 没有引用这些内容的变化Pod 不会重启。解决办法是加一个sha256sum注解template: metadata: annotations: checksum/config: {{ include (print $.Template.BasePath /configmap.yaml) . | sha256sum }}这样每次 configmap 内容变化hash 跟着变Deployment 模板也随之变化Pod 就会滚动重启。这个注解我几乎每个服务都会加省了无数手动kubectl rollout restart。误删 release业务还跑着但 helm list 看不到前面说过Helm v3 的 release 信息存在 Secret 里。误删之后想恢复先检查当前工作负载是否正常正常就别乱动不正常的话用kubectl get secret -n prod | grep order-service看看 Secret 还在不在。Secret 还在就可以重新创建 release 记录不在的话只能按新 Chart 重新 install但工作负载的配置可能没法完全还原。最好的方式还是定期备份 release 的 Secret尤其是核心服务。7. 把 HPA 和 Helm 组合起来后的生产工作流7.1 一套可以照抄的组合模板很多团队会问HPA 和 Helm 到底怎么组合才最优雅我现在的做法是在 Chart 里默认内置 HPA 模板通过values.yaml开关控制。这样新服务接入时天然就有 HPA 能力不会出现“部署完忘了配 HPA”的情况。我自己维护的 Chart 里有这样一段逻辑hpa.enabled为 true 时生成 HPA同时hpa.behavior支持自定义。对应的 values 结构长这样hpa: enabled: true minReplicas: 2 maxReplicas: 8 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 60 behavior: scaleDown: stabilizationWindowSeconds: 600 policies: - type: Pods value: 1 periodSeconds: 300通过 Helm 模板把这一段结构化渲染到 HPA 里部署时用不同环境的 values 文件控制 min/max。staging 环境可以允许 HPA 生效但 max 调小生产环境按真实容量规划。这个组合的价值在于HPA 配置不再是散落在集群里的孤立的 YAML而是跟服务一起打包、一起走版本控制、一起发布回滚。服务更新了HPA 策略也跟着走不会出现 Deployment 升级后 HPA 的scaleTargetRef指向旧名字导致失效的问题。7.2 发布流程中的扩缩容联动我再分享一个实际例子。有一次我把一个核心服务的镜像从 v2.1.0 升级到 v2.2.0这个版本改了内存缓存策略内存占用下降了 30%。升级后 HPA 按 CPU 和内存双指标运行观察到内存利用率明显下降HPA 自动把副本数从 8 缩到了 5。整个过程我没有做任何手动操作全靠发布前在 values 里已经配好的多指标 HPA。你可以想象一下如果发布后需要人工看着监控缩容那运维工程师早就被这种琐事淹没了。这也引出一个关键认知HPA 不是和发布流程割裂的静态配置它是发布产物的一部分。你在发布一个新版本时通常要同步审视 HPA 策略是否合理。比如新版本对 CPU 的需求变了你还在用老的 targetAverageUtilization那 HPA 的行为就会偏离预期。把这些放进同一个 Chart、同一个 release 流程你才能保证“代码、镜像、扩缩容策略”三者始终处于一致状态。8. 写在最后的经验玩 HPA 和 Helm 这几年我最大的感受是这两样东西单学都不难难的是把它们放进真实的生产链路里。HPA 调的是你对业务容量的认知Helm 调的是你对交付流程的规划。任何一方的配置脱离了实际业务形态都会变成运维事故的源头。给刚接触这套技术栈的同学一个上手路线先用kind或单节点集群搭一套本地环境装上 metrics-server 和 Helm v3跑一个无状态的 Nginx 服务给它配一个最简 HPA把kubectl describe hpa的输出看明白。然后把 HPA 参数逐个改成不同的值观察副本数的变化曲线。这个实验做完你对 HPA 的理解会超过很多只看文档的人。接下来把 Nginx 的部署方式改成 Helm Chart把镜像 tag、副本数、HPA 参数全部参数化再跑一遍helm upgrade --set。完成这一步你就具备在生产环境安全使用这些工具的基础了。最后再提醒一件事无论你的 HPA 策略调得多精细Helm 模板写得多优雅一定要给集群节点留出弹性扩缩容的余量。HPA 只能保证“需要的 Pod 数”被计算出来没法保证“Pod 能调度到足够的节点上”。把应用层伸缩和基础设施层伸缩联动起来才是容器化架构下运维弹性的完整闭环。
RELATED

相关推荐

HPA与Helm实战:Kubernetes自动扩缩容与模板化部署

HPA与Helm实战:Kubernetes自动扩缩容与模板化部署

如果你负责维护一个 Kubernetes 集群,或者正打算把业务往容器平台上迁移,那么 HPA 和 Helm 这两样东西早晚会一起出现在你的工作清单里。HPA 干的事情比较纯粹:让应用的副本数跟着流量自动变化,流量大了自动扩容,闲下来…

📅 2026/10/21 3:15:50
单周期RISC-V CPU设计:Vivado实战与FPGA落地指南

单周期RISC-V CPU设计:Vivado实战与FPGA落地指南

简介:本资源是一套基于Verilog实现的单周期CPU完整FPGA设计工程,面向数字电路、计算机组成原理课程学习者及FPGA初学者,旨在通过可综合、可仿真的真实项目,直观呈现取指、译码、执行、写回等CPU核心流程,解决教学中抽象…

📅 2026/10/21 3:15:50
用GDAL实现遥感影像裁剪:从范围裁剪到批量处理实战

用GDAL实现遥感影像裁剪:从范围裁剪到批量处理实战

搞遥感影像处理的人,迟早都会碰到影像裁剪这个需求。无论是从一幅标准景影像里切出研究区,还是按行政区边界做镶嵌裁剪,抑或是给深度学习模型准备训练切片,这一步几乎绕不开。GDAL 是我这些年用得最顺手的工具,没有之一…

📅 2026/10/21 3:10:50
MORE NEWS

更多资讯

📰

轻量级实时事件分析工具rea:从事件采集到告警可视化的实践

后台数据越堆越多,每次想临时查个指标都得现写脚本,查完又扔。后来实在受不了,我就花了两周时间做了个代号叫“rea”的小东西——一个轻量级的实时事件分析工具。简单说,就是给日志和用户行为事件装了一根“实时水管”&#xff0c…

📰

用先知AI精炼男装产品语言:从概念到爆款的实战方法

做男装产品这么多年,我见过太多“设计师自我感动、销售卖不动、老板压库存”的循环。新版型打出来了,面料选好了,但消费者就是看不懂,说不出你比隔壁那家好在哪。问题往往不在产品本身,而在你没把概念翻译成市场上的语…

📰

车道线检测从训练到TensorRT部署实战:轻量化模型与INT8量化全流程

车道线检测这个题目,做视觉的同行基本都绕不开。尤其是自动驾驶场景,车道线是感知链路里最基础也最关键的一环,它直接决定车辆能不能稳稳待在自己这条车道里,也影响后续换道、转弯等决策。我这次做的不是单纯训练一个模型&#xf…

📰

2026年起号新逻辑:AI工具一分钟生成原创图文与多平台分发实操

说实话,2026年再谈“起号”,玩法跟前几年已经完全不是一回事了。过去那种“搬运伪原创批量发”的野路子,现在基本是发一个死一个;而真正能稳定起号的内容,反而回到了最基础的“原创图文”赛道。这篇东西想聊的就是我最…

📰

从零手写字符设备驱动:安卓底层驱动的灵魂与实战

1. 为什么说字符设备驱动是安卓驱动的灵魂1.1 安卓系统里驱动到底站在哪一层我在之前的系列文章里反复强调过一件事:安卓系统从上到下是一条完整的调用链,应用层跑在虚拟机上,框架层提供各种服务,再往下是系统服务和硬件抽象层&am…

📰

CoppeliaSim+Python小车视觉追踪:从仿真到真机移植的完整实现指南

简介:面向机器人仿真与控制学习的CoppeliaSim(原Vrep)Python小车追踪工程,聚焦如何在仿真环境中驱动小车实时追踪目标点,覆盖环境搭建、API调用、路径规划与控制算法联调等关键环节。压缩包共17个文件,包含…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬