本文独立博客阅读地址:https://thiscute.world/posts/finops-for-kubernetes/
FinOps 是一种不断发展的云财务管理学科和文化实践,通过帮助工程、财务、技术和业务团队在数据驱动的预算分配上进行协作,使成本预算能够产生最大的业务价值。
随着越来越多的企业上云,云计算的成本管控也越来越受关注。在讨论 Kubernetes 成本之前,先简单聊下如何管控云计算成本,有一个新名词被用于形容这项工作——FinOps.
传统的数据中心的成本是比较固定的,所有的成本变动通常都伴随着硬件更替。
而在云上环境就很不一样了,由于云服务的按量收费特性,以及五花八门的计费规则,开发人员稍有不慎,云成本就可能会出现意料之外的变化。另一方面由于计费的复杂性,业务扩容对成本的影响也变得难以预测。
目前的主流云服务商(AWS/GCP/Alicloud/...)基本都提供基于资源标签的成本查询方法,也支持将成本导出并使用 SQL 进行细致分析。
因此其实要做到快速高效的云成本分析与管控,主要就涉及到如下几个点:
但是也存在许多特殊的云上资源,云服务商目前并未提供良好的成本分析手段,Kubernetes 集群成本就是其中之一。
目前许多企业应该都面临着这样的场景:所有的服务都运行在一或多个 Kubernetes 集群上,其中包含多条业务线、多个产品、多个业务团队的服务,甚至除了业务服务,可能还包含 CICD、数据分析、机器学习等多种其他工作负载。而这些 Kubernetes 集群通常都由一个独立的 SRE 部门管理。
但是 Kubernetes 集群本身并不提供成本拆分的能力,我们只能查到集群的整体成本、每个节点组的成本等这样粗粒度的成本信息,缺乏细粒度的成本分析能力。
此外,Kubernetes 集群是一个非常动态的运行环境,其节点的数量、节点规格、Pod 所在的节点/Zone/Region,都可能会随着时间动态变动,这为成本分析带来了更大的困难。
这就导致我们很难回答这些问题:每条业务线、每个产品、每个业务团队、或者每个服务分别花了多少钱?是否存在资源浪费?有何优化手段?
而 FinOps for Kubernetes,就是通过工程化分析、可视化成本分析等手段,来回答这些成本问题,分析与管控 Kubernetes 的成本。
接下来我会先介绍下云上 Kubernetes 成本分析的思路与手段,最后再介绍如何使用 Kubecost 分析 Kubernetes 集群的成本。
要做好 Kubernetes 成本工作,有如下三个要点:
以 AWS EKS 为例,它的成本有这些组成部分:
总结下,其实就是三部分成本:计算、存储、网络。其中计算与存储成本是相对固定的,而网络成本就比较动态,跟是否跨区、是否通过 NAT 等诸多因素有关。
Kubernetes 提供了三种资源分配的方式,即服务质量 QoS,不同的分配方式,成本的计算难度也有区别:
要做到统一分析、拆分 Kubernetes 与其他云资源的成本,如下是一些最佳实践:
成本优化实践:
上述讨论的绝大部分策略,都适用于多云环境。在这种涉及多个云服务提供商的场景,最重要的一点是:搭建平台无关的成本分析与管控平台。而其核心仍然是文章最前面提到的两点,只需要补充两个字 一致:
这样就可以把不同云服务商的数据转换成统一的格式,然后在自有的成本平台上进行统一的分析了。
搭建一个这样的成本分析平台其实并不难,许多大公司都是这么干的,小公司也可以从一个最小的平台开始做起,再慢慢完善功能。
以我现有的经验看,其实主要就包含这么几个部分:
前面讨论的内容都很「虚」,下面来点更「务实」的:Kubernetes 成本分析实战。
目前据我所知,主要有如下两个相关的开源工具:
其中 kubecost 是最成熟的一个,我们接下来以 kubecost 为例介绍下如何分析 Kubernetes 成本。
kubecost 有两种推荐的安装方法:
开源的 cost-model 直接使用此配置文件即可部署:https://github.com/kubecost/cost-model/blob/master/kubernetes/exporter/exporter.yaml
而如果要部署带 UI 的商业版,需要首先访问 https://www.kubecost.com/install#show-instructions 获取到 kubecostToken
,然后使用 helm 进行部署。
首先下载并编辑 values.yaml 配置文件:https://github.com/kubecost/cost-analyzer-helm-chart/blob/develop/cost-analyzer/values.yaml
然后部署:
kubectl create namespace kubecost helm repo add kubecost https://kubecost.github.io/cost-analyzer/ helm install kubecost kubecost/cost-analyzer -n kubecost -f kubecost-values.yaml
通过 port-forward 访问:
kubectl port-forward --namespace kubecost deployment/kubecost-cost-analyzer 9090
现在访问 http://localhost:9090 就能进入 Kubecost 的 UI 面板,其中最主要的就是 Allocation 成本拆分功能。
Kubecost 通过 AWS/GCP 等云服务商 API 动态获取各 region/zone 的上述四项资源的每小时成本:CPU-hour, GPU-hour, Storage Gb-hour 与 RAM Gb-hour,或者通过 json 文件静态配置这几项资源的成本。
OD 按需实例的资源价格通常比较固定,而 AWS Spot 实例的成本波动会比较大,可以通过 SpotCPU/SpotRAM 这两个参数来设置 spot 的默认价格,也可以为 kubecost 提供权限使它动态获取这两项资源的价格。
kubecost 根据每个容器的资源请求 requests 以及资源用量监控进行成本分配,对于未配置 requests 的资源将仅按实际用量监控进行成本分配。
kubecost 的成本统计粒度为 container,而 deployment/service/namespace/label 只是按不同的维度进行成本聚合而已。
https://github.com/kubecost/docs/blob/b7e9d25994ce3df6b3936a06023588f2249554e5/network-allocation.md
对提供线上服务的云上 Kubernetes 集群而言,网络成本很可能等于甚至超过计算成本。这里面最贵的,是跨区/跨域传输的流量成本,以及 NAT 网关成本。
使用单个可用区风险比较高,资源池也可能不够用,因此我们通常会使用多个可用区,这就导致跨区流量成本激增。
kubecost 也支持使用 Pod network 监控指标对整个集群的流量成本进行拆分,kubecost 会部署一个绑定 hostNetwork 的 daemonset 来采集需要的网络指标,提供给 prometheus 拉取,再进行进一步的分析。
kubecost 将网络流量分成如下几类:
更多的待研究,看 kubecost 官方文档吧。
另外还看到 kubecost 有忽略 s3 流量(因为不收费)的 issue: https://github.com/kubecost/cost-model/issues/517
https://github.com/kubecost/docs/blob/b7e9d25994ce3df6b3936a06023588f2249554e5/apis.md
查询成本拆分结果的 API 示例:
import requests resp = requests.get("http://localhost:9090/model/allocation", params={ "window": "2022-05-05T00:00:00Z,2022-05-06T00:00:00Z", "aggregate": "namespace,label:app", # 以这几个纬度进行成本聚合 "external": True, # 拆分集群外部的成本(比如 s3/rds/es 等),需要通过其他手段提供外部资源的成本 "accumulate": True, # 累加指定 window 的所有成本 "shareIdle": False, # 将空闲成本拆分到所有资源上 "idleByNode": False, # 基于节点进行空闲资源的统计 "shareTenancyCosts": True, # 在集群的多个租户之间共享集群管理成本、节点数据卷成本。这部分成本将被添加到 `sharedCost` 字段中 "shareNamespaces": "kube-system,kubecost,istio-system,monitoring", # 将这些名字空间的成本设为共享成本 "shareLabels": "", "shareCost": None, "shareSplit": "weighted", # 共享成本的拆分方法,weight 加权拆分,even 均分 }) resp_json = resp.json() print(resp_json['code']) result = resp_json['data'] print(result[0])
查询结果中有这几种特殊成本类别:
__idle__
: 未被占用的空闲资源消耗的成本__unallocated_
: 不含有 aggregate
对应维度的成本,比如按 label:app
进行聚合,不含有 app
这个 label 的 pod 成本就会被分类到此标签__unmounted__
: 未挂载 PV 的成本此外如果使用 kubecost 可视化面板,可能还会看到一个 other
类别,这是为了方便可视化,把成本太低的一些指标聚合展示了。