Goldilocks 与 VPA 资源请求推荐治理
一个共享集群长期显示 CPU request 使用率很低,团队据此把二十多个 Deployment 的 request 一次性减半。变更后,普通时段一切正常,发布高峰却有 Pod 因 CPU 竞争而启动变慢,HPA 又因为 request 变小而更早放大副本,节点供给随之突增。原来的“浪费”没有简单消失,而是从静态预留转成了启动长尾、扩容抖动和更多节点成本。
另一个团队安装 Goldilocks 后,直接把仪表盘里的 target 批量写回生产。几天后才发现推荐对象同时包含业务容器、service mesh sidecar 和短期异常样本;部分 VPA 还没有积累足够历史。Goldilocks 能把 VPA recommendation 变得易读,却不会替团队判断业务峰值、SLO、HPA 耦合、发布余量和中断风险。推荐是容量证据,不是自动批准的变更单。
Goldilocks 展示建议,VPA 才生成 recommendation
Goldilocks 不是独立的自动扩缩器。它的 controller 为选择的工作负载创建或维护 VerticalPodAutoscaler 对象,dashboard 读取这些对象的 recommendation 并提供适合审核的视图。默认思路是让 VPA 保持 Off,只输出建议,不自动驱逐或修改生产 Pod。Goldilocks 当前稳定应用发行线为 v4.15.1;VPA 当前正式版为 1.7.0,API 使用 autoscaling.k8s.io/v1。实施时仍应锁定镜像摘要与 chart 版本,并在升级前核对目标 Kubernetes 兼容性。
运行链路可以拆成五步:工作负载声明 requests;kubelet 与指标流水线产生资源使用样本;VPA Recommender 聚合容器历史并写入 VPA status.recommendation;Goldilocks controller 发现已启用命名空间并管理 VPA;dashboard 读取推荐。任何一段缺失,页面都可能空白或陈旧。
官方的 Goldilocks 安装说明给出 Helm 与组件配置入口,Goldilocks FAQ解释了常见推荐与工作负载行为,VPA Quick Start则展示 VPA 对象和 recommendation 的真实字段。遇到版本行为差异时,应先查看锁定发行版的文档,而不是从仪表盘颜色猜测含义。
安装前先确认指标、CRD 与读取权限
实验至少需要一个非生产 Kubernetes 集群、可工作的资源指标流水线、Helm、创建 CRD 和集群级 RBAC 的管理员,以及一个只供实验使用的命名空间。VPA 安装会增加 CRD、Recommender、Updater 和 Admission Controller 等组件;Goldilocks 会增加 controller、dashboard、Service 和 RBAC。即使只做 recommendation,也不能把这些组件当作零成本页面。
先检查已有安装,避免两个 release 同时写同一类 VPA:
kubectl version
helm version
kubectl api-resources | grep -i verticalpodautoscaler
kubectl get deployment -A | grep -E 'vpa-|goldilocks'
kubectl top nodes
kubectl auth can-i create customresourcedefinitions.apiextensions.k8s.io
kubectl auth can-i create clusterroles.rbac.authorization.k8s.iokubectl top 成功只证明 Resource Metrics API 的当前样本可读,不证明 VPA 已有足够推荐历史。若 VPA 已由平台统一提供,应用团队不应再安装第二套;只需让 Goldilocks 连接受支持的 VPA API。生产环境的 CRD、ClusterRole 与 webhook 变更应由平台 owner 审核,业务账号只获得指定命名空间的 VPA 只读权限。
VPA 1.7.0 的 Auto 模式已弃用,应显式选择 Off、Initial、Recreate、InPlaceOrRecreate 或 InPlace。Goldilocks 做审核时使用 Off 最容易保持字段所有权清晰;它也不兼容 Kubernetes Pod 级 spec.resources,若集群使用该能力,必须先通过VPA 发行说明核对限制。
用锁定版本安装 VPA 与 Goldilocks
先从组织允许的来源取得 VPA 1.7.0 清单或制品,审查 CRD、webhook、镜像与 RBAC 后安装。官方仓库提供按 tag 固定的部署入口;生产环境应镜像到受控仓库并锁定摘要。安装后验证 API 与三个核心组件,而不是只看 Helm release:
kubectl get crd verticalpodautoscalers.autoscaling.k8s.io
kubectl api-resources --api-group=autoscaling.k8s.io
kubectl get deploy -n kube-system | grep vpa
kubectl get pods -n kube-system | grep vpaGoldilocks 官方 chart 仓库可按下面方式加入。chart 版本与应用版本不是同一个编号,先搜索并选择 APP VERSION 为 4.15.1 的 chart,把解析出的 chart 版本写进环境锁定文件,再安装:
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
helm repo update fairwinds-stable
helm search repo fairwinds-stable/goldilocks --versions
helm upgrade --install goldilocks fairwinds-stable/goldilocks \
--namespace goldilocks --create-namespace \
--version <approved-chart-version> \
--set controller.enabled=true \
--set dashboard.enabled=true \
--wait --timeout 5m预期看到 controller 与 dashboard Deployment Available,Service 存在,controller 日志没有 VPA discovery、RBAC 或 webhook 错误:
helm status goldilocks -n goldilocks
kubectl get deploy,pod,svc -n goldilocks
kubectl logs -n goldilocks deploy/goldilocks-controller --tail=100安装命令中的组件键以锁定 chart 的 values 为准,升级前应执行 helm show values fairwinds-stable/goldilocks --version <approved-chart-version> 并纳入评审。公网仓库不可达时,使用已校验的内部 OCI/chart 镜像,不应临时关闭 TLS 验证。
命名空间标签决定哪些工作负载进入观察
Goldilocks 通常通过命名空间标签 goldilocks.fairwinds.com/enabled=true 发现工作负载。这个字段会扩大 controller 创建 VPA 和 dashboard 展示容量事实的范围;给全体命名空间批量打标,既增加 Recommender 计算与 API 对象数量,也可能把敏感工作负载名称和 requests 暴露给页面访问者。
先建立小范围实验:
kubectl create namespace rightsizing-lab
kubectl label namespace rightsizing-lab goldilocks.fairwinds.com/enabled=true
kubectl get namespace rightsizing-lab --show-labels创建一个稳定、可持续产生轻量 CPU 与内存使用的 Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: steady-worker
namespace: rightsizing-lab
spec:
replicas: 2
selector:
matchLabels: {app: steady-worker}
template:
metadata:
labels: {app: steady-worker}
spec:
containers:
- name: worker
image: registry.k8s.io/e2e-test-images/resource-consumer:1.13
args: ["-port", "8080", "-consume-cpu", "20", "-consume-mem", "32"]
ports:
- containerPort: 8080
resources:
requests: {cpu: 100m, memory: 96Mi}
limits: {cpu: 500m, memory: 256Mi}kubectl apply -f steady-worker.yaml
kubectl rollout status deployment/steady-worker -n rightsizing-lab --timeout=120s
kubectl get vpa -n rightsizing-lab镜像参数属于实验发行版接口,受限网络应先同步到内部仓库。若镜像拉取失败,Pod 已经调度但不 Ready,这不是 Goldilocks 或 VPA 推荐故障;应先修复镜像来源,再开始累计样本。
recommendation 四组数值必须按容器解释
VPA recommendation 位于状态而不是 spec。每个容器分别给出 lowerBound、target、upperBound 与 uncappedTarget:
kubectl get vpa -n rightsizing-lab -o yaml
kubectl get vpa -n rightsizing-lab \
-o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{range .status.recommendation.containerRecommendations[*]} {.containerName}{" target="}{.target}{" lower="}{.lowerBound}{" upper="}{.upperBound}{" uncapped="}{.uncappedTarget}{"\n"}{end}{end}'target 是 Recommender 在当前策略与边界下建议的 request;lowerBound 与 upperBound 是推荐区间信号,不是 guaranteed QoS 或硬性安全上下限;uncappedTarget 展示未受 VPA policy 上限约束的目标。当 uncappedTarget 明显高于 target,说明策略上限正在截断建议,不能把较低 target 当作负载天然只需要这么多资源。
推荐按容器拆分,所以 sidecar、代理、日志 agent 都会独立出现。业务容器的峰值模式与 sidecar 的连接数、配置推送或证书轮换峰值不同,不能把所有容器按同一个比例缩放。初始化容器、短任务和生命周期不稳定的工作负载也要单独判断;仪表盘中的总量适合发现候选对象,真正变更必须回到容器字段。
VPA policy 可以通过 resourcePolicy.containerPolicies 约束受控资源、最小值、最大值和容器模式。字段改变会直接改变 recommendation 的裁剪结果。使用 policy 时,应把“为什么设置边界、谁批准、何时复审”留在配置评审记录中,避免永久上限把业务增长隐藏掉。
正向实验:从建议产生到审核候选
等待多个采样周期后,检查 Deployment 使用、VPA 状态、controller 日志与 dashboard。页面可通过本地端口转发访问,不要默认创建公网 LoadBalancer 或匿名 Ingress:
kubectl top pod -n rightsizing-lab --containers
kubectl get vpa -n rightsizing-lab -o yaml
kubectl logs -n goldilocks deploy/goldilocks-controller --tail=100
kubectl port-forward -n goldilocks svc/goldilocks-dashboard 8080:80预期结果不是某个固定 request,而是 steady-worker 对应的 VPA 出现非空 status.recommendation.containerRecommendations,其中 containerName=worker 与真实容器一致;Goldilocks 页面展示同一对象,且 controller 无持续 reconcile 错误。推荐值受样本历史、负载和发行版算法影响,文章中的演示负载不能转换成生产阈值。
把建议转成审核候选时,先记录原 request、target、区间、负载版本、样本窗口内的吞吐与延迟,再在 Git 中只改一个工作负载。比如 target 比当前 request 低很多,也不要一步降到 target;选择一个保留发布与冷启动余量的候选值,在预发布或少量副本上验证。通过 kubectl diff 或 GitOps diff 确认只改变目标容器的 requests:
kubectl get deployment steady-worker -n rightsizing-lab -o yaml
kubectl diff -f steady-worker-candidate.yaml
kubectl apply -f steady-worker-candidate.yaml
kubectl rollout status deployment/steady-worker -n rightsizing-lab --timeout=120s
kubectl top pod -n rightsizing-lab --containers验收应观察一段具有代表性的业务周期:Pod Ready 长尾不恶化,CPU throttling、OOM、重启、延迟和错误率不增长,HPA 与节点伸缩没有异常放大,VPA target 不因样本不足持续单向漂移。生产阈值由 SLO、压测、历史峰值与容量预算决定。
反向实验:用短时尖峰暴露自动照抄的风险
对实验容器制造短时 CPU 峰值,再观察即时使用与 VPA recommendation 的变化。资源消费者镜像支持通过 HTTP 请求改变消耗;先转发端口,然后发送受控请求,具体接口以镜像发行版为准:
kubectl port-forward -n rightsizing-lab deploy/steady-worker 18080:8080
curl -X POST 'http://localhost:18080/ConsumeCPU' -d 'millicores=350&durationSec=120'
kubectl top pod -n rightsizing-lab --containers
kubectl get vpa -n rightsizing-lab -o yaml若镜像接口与锁定版本不同,可以改用组织已有的压测工作负载;关键是同时保存峰值开始、结束和推荐变化的相对时间线。预期现象是 kubectl top 较快看到使用变化,而 VPA recommendation 经过聚合后才变化,且不会等同于某一瞬时值。短峰若反复出现,target 或 upperBound 可能上移;只有一次异常并不自动等于长期 request 应提升。
更危险的反例是把 VPA 更新模式切成会修改 Pod 的模式,再与 HPA 同时基于 CPU 利用率运行。VPA 改小 CPU request 后,即使 CPU 使用量不变,usage/request 也会升高,HPA 可能扩副本;两条控制环互相影响。实验不需要真的在生产启用,只要检查对象所有权即可:
kubectl get hpa -n rightsizing-lab
kubectl get vpa -n rightsizing-lab -o jsonpath='{range .items[*]}{.metadata.name}{" mode="}{.spec.updatePolicy.updateMode}{"\n"}{end}'发现 HPA 使用 CPU/内存利用率时,VPA 应保持 Off,或明确排除 HPA 所依赖的资源维度。任何自动更新模式都需要单独评估驱逐、原地调整支持、PDB、启动时间和回滚路径,不能由 Goldilocks 页面按钮替代架构决策。
样本不足、异常峰值和 sidecar 要分别审查
新部署、低频任务和周期性批作业最容易产生“看起来很精确”的不可靠建议。推荐对象存在不代表样本覆盖了周峰、发布峰、缓存冷启动、故障恢复或批处理窗口。审核时应把 recommendation 与工作负载版本、replicas、吞吐、延迟、重启、HPA、节点类型放在同一时间线上。
建议长期不出现时,按链路分层:
kubectl top pod -n rightsizing-lab --containers
kubectl get vpa -n rightsizing-lab -o yaml
kubectl logs -n kube-system deploy/vpa-recommender --tail=200
kubectl logs -n goldilocks deploy/goldilocks-controller --tail=200
kubectl get events -n rightsizing-lab --sort-by=.metadata.creationTimestampMetrics API 不可用、VPA Recommender 无法读取历史、selector 没有匹配 Pod、容器刚改名、RBAC 拒绝、Goldilocks 未发现标签命名空间,都会造成不同失败。先确认 VPA status 是否为空:status 有推荐而 dashboard 没有,是 Goldilocks 展示或读取路径;status 本身为空,则应回到 VPA 与指标链路。
sidecar 必须单独建立责任。service mesh 代理的资源可能随连接数和遥测配置增长,日志 agent 可能随日志风暴增长。应用 owner 不能擅自把平台 sidecar request 改小,平台 owner 也不能用 sidecar 总量掩盖业务容器浪费。建议导出时保留 containerName,并为注入容器建立独立策略和升级复测。
推荐写回会同时影响调度、HPA 与节点成本
requests 是多个控制环共享的事实。调低 CPU 或内存 request,单个节点表面可容纳更多 Pod,但更容易发生运行时争用;HPA 的资源利用率分母会改变;Cluster Autoscaler 或 Karpenter 看到的待调度需求也会改变。调高 request 则可能改善隔离,却增加 Pending、节点数和碎片。
因此 rightsizing 的成本不能只看“request 降低多少”。至少同时比较:工作负载可用副本、节点数与实例类型、空闲碎片、扩缩容次数、启动长尾、CPU throttling、OOM/eviction、HPA 副本曲线以及真实业务 SLO。Goldilocks dashboard 本身还会增加 API list/watch、VPA 对象、Recommender 内存与遥测存储成本;大集群应分批启用命名空间,观察控制器队列、API 限流和推荐延迟。
对于稳定在线服务,Goldilocks 适合持续发现明显 over-request 或 under-request 的候选项;对于短时 Job、强周期业务、GPU/扩展资源、需要 Pod 级资源语义或极端峰值保护的工作负载,单靠历史推荐不足。批任务还可能更适合队列与配额治理;Goldilocks 不决定作业何时准入,也不负责 Pod 放置。
Dashboard 是敏感容量入口,不应匿名暴露
Goldilocks 页面会显示 namespace、workload、container、当前 requests 与建议区间,这些信息能够推断业务拓扑、规模和容量弱点。默认使用 kubectl port-forward 做受控访问;需要团队共享时,应放在已有身份代理后,限制 namespace 读取范围,启用访问日志和会话过期,不直接开放公网 Service。
controller 通常需要跨命名空间观察 workload 并管理 VPA,dashboard 需要读取 VPA 与工作负载。安装后审查实际 ClusterRole,而不是假设 chart 已经最小化:
kubectl get clusterrole,clusterrolebinding | grep goldilocks
kubectl describe clusterrole <goldilocks-controller-role>
kubectl auth can-i list verticalpodautoscalers.autoscaling.k8s.io \
--as=system:serviceaccount:goldilocks:<dashboard-service-account> --all-namespaces若使用外部身份代理,客户端 Secret、TLS 私钥和 OIDC 配置进入现有密钥系统,按服务账号轮换,不写进 values 文件或提示词。卸载时不仅删除 Pod,还要撤销 ClusterRoleBinding、Ingress/DNS、证书、监控抓取和临时管理员凭证。审计应能回答谁查看了哪些容量数据、谁批准了 request 变更、变更对应哪次压测和回滚。
从人工建议走向自动更新要设置更高门槛
最稳妥的起点是 Goldilocks + VPA Off + Git 审核:推荐只产生候选,资源字段仍由应用仓库的单一 owner 写入。团队成熟后,可以对启动成本低、无 HPA 资源利用率耦合、PDB 与回滚完善的工作负载评估 Initial、Recreate、InPlaceOrRecreate 或 InPlace。不同模式改变的是何时、以何种中断语义应用推荐,不能统一开启。
自动化若把 dashboard recommendation 直接生成 PR,也必须保留策略:样本年龄、最小变化幅度、单次变化上限、容器白名单、发布冻结、SLO 回归、双人审核与自动回滚。PR 机器人只能写指定 requests 字段,不能同时控制 replicas、limits、HPA target 或 VPA update mode。推荐缺失或异常时应 fail closed,不生成“清空 request”的变更。
长期 owner 至少分三层:应用团队对业务峰值、SLO 和最终 request 负责;平台团队对 VPA/Goldilocks 版本、RBAC、性能和策略模板负责;FinOps 或容量团队用成本事实提出候选,但不越权批准可靠性风险。没有人对建议正确性承担责任时,仪表盘越漂亮,批量误改反而越快。
升级、回退与安全卸载要按依赖逆序执行
升级前导出 Helm values、VPA CRD schema、现有 VPA 对象、RBAC 与镜像摘要,在隔离命名空间验证新版本能读取旧 recommendation,controller 不会批量重建或删除非本 release 的 VPA。Goldilocks、chart 和 VPA 是三条版本线,不能只升级页面;先升级 CRD 所需兼容项,再升级 VPA 组件,最后升级 Goldilocks,并在每一步比较对象数量、recommendation 非空比例和 reconcile 错误。
若新版本推荐明显漂移,先停止把建议写回 Git,冻结命名空间扩展,回退 Goldilocks 或 VPA 组件;不要立即删除 CRD,因为删除 CRD 会连同所有 VPA 自定义资源一起删除。回退后确认旧组件能读取保留对象,dashboard 与 kubectl get vpa 一致,再恢复审核流程。
完全退出时,先移除命名空间启用标签,确认 Goldilocks 不再创建新对象;保留一段只读观察窗口并导出必要的审核记录;然后卸载 Goldilocks,删除由它拥有且已确认无其他消费者的 VPA,再卸载 VPA 组件。CRD 只有在集群中没有其他 VPA 使用者、对象已核对、回滚窗口结束后才可删除。
kubectl label namespace rightsizing-lab goldilocks.fairwinds.com/enabled-
kubectl get vpa -A
helm uninstall goldilocks -n goldilocks
kubectl delete namespace goldilocks --wait=trueVPA 的卸载命令取决于组织采用的安装方式,应执行对应锁定发行版的卸载流程,并复核 webhook configuration、CRD、ClusterRoleBinding 与 API discovery 残留。强行删除 namespace 或 CRD 可能留下 webhook 故障或误删其他团队对象。
清理实验并把 recommendation 变成可审计证据
实验结束先删除工作负载和 VPA,再移除标签与命名空间;如果集群中的 Goldilocks/VPA 是共享平台,不卸载共享组件:
kubectl delete deployment steady-worker -n rightsizing-lab --wait=true
kubectl delete vpa --all -n rightsizing-lab
kubectl label namespace rightsizing-lab goldilocks.fairwinds.com/enabled-
kubectl delete namespace rightsizing-lab --wait=true
kubectl get vpa -A同时停止 port-forward,删除临时 YAML、导出的容量数据和测试镜像缓存;若实验创建了 LoadBalancer、Ingress、证书或额外节点,逐项核销。推荐历史与截图同样属于敏感容量记录,应按审计需求设保留期,不长期散落在工单和聊天工具里。
成熟的治理记录不会只保存“Goldilocks 建议 200m”。它会关联工作负载 revision、容器名、原 request、四组 recommendation、样本覆盖、峰值解释、候选值、压测与灰度证据、HPA/节点影响、批准人和回滚值。这样 recommendation 才从一张易读页面变成可以复核、可以拒绝、也可以安全撤销的工程证据。
