本期内容
Kubevela addon
添加腾讯Crane
平均来说企业上云会节省 14% 的成本,但是到 2020 年,由于缺乏成本优化手段,80% 企业的云资源成本将会大幅超出预算;
同时,45% 的企业由于缺乏优化措施,在直接迁移上云的过程中会超买 55% 的资源,并且在上云的第一个 18 个月内会多花费 70%.
在云资源巨大的投入成本和浪费面前,那些当初对上云趋之若鹜的人,甚至开始谈“云”色变。
如何优化和管理不同的公有云成本?这已然成为迫在眉睫的难题。
那在这种情况下,为了减少云上资源的浪费,一种文化革命 FinOps (云成本优化)就应运而生了。
我们先来看一下 FinOps 基金会对 FinOps 的定义:
FinOps 是将 DevOps、财务和业务整合在一起的变革,其目标在于优化一个组织在云计算上的支出的财务规范和技术解决方案,即根据支出的历史记录和来自预期负载的信息,FinOps 可以在需要时预分配资源或估算成本。
FinOps 可以称为“财务运营” ,或者更直白地称为“成本优化”,是将财务问责制引入云的 IT 支持,进行调整以优化质量和支出。
FinOps 可以简单理解为云成本优化,为了更好地规划和预测云消费的支出要求,如今越来越多的公司正在转向 FinOps。
而 Crane 则正是为了 FinOps 的而诞生的。
Crane 是一个云原生开源项目,为推进云原生用户在确保业务稳定性的基础上做到真正的极致降本,腾讯推出了国内第一个基于云原生技术的成本优化开源项目 Crane( Cloud Resource Analytics and Economics )
Crane 遵循 FinOps 标准,旨在为云原生用户提供云成本优化一站式解决方案。
Crane的目标是提供一个一站式项目,帮助Kubernetes 用户通过一系列丰富的功能来节省云资源的使用,这些功能包括:
基于监测数据的时间序列预测
使用和成本可见性
使用和成本优化包括:
R2(资源重新分配)
R3(请求和副本推荐)
有效的pod自动缩放(有效的水平和垂直pod自动缩放)
同时,因为 Crane 基于 Prometheus,以及 grafana,它也可以起到对云上资源监控的作用。
为了快速一键化部署 Crane,我们这里选择将 Crane 插件化,作为 Kubevela 的 addon 集成到集群中进行快速使用。
│ metadata.yaml│ readme.md│ template.yaml│├─image│ crane-overview.png│ crane.png│ wechat.jpeg│└─resources ├─config │ grafana-config.yaml │ namespace.yaml │ prometheus-config.yaml │ ├─release │ crane-release.yaml │ fadvisor-release.yaml │ grafana-release.yaml │ prometheus-release.yaml │ └─repo crane-repo.yaml grafana-repo.yaml prometheus-repo.yaml
其中 image 中图片为 readme 中所需的贴图;resource 中的每个 yaml 文件则是定义了一个 k8s resource。
这里将 crane 插件化主要是使用的 Helm 的方式(Kubevela Helm插件),分别将 Prometheus,Grafana,Crane 的 repo 链接引入,然后使用对应的 ConfigMap 中的配置部署对应的 Helm Release。
apiVersion: v1kind: Namespacemetadata: name: crane-system
创建 Prometheus 配置的 ConfigMap:
apiVersion: v1kind: ConfigMapmetadata: name: prometheus namespace: crane-systemdata: override_values: | ## Prometheus server ConfigMap entries ## serverFiles: ## Records configuration ## Ref: https: recording_rules.yml: groups: - name: costs.rules interval: 3600s rules: - expr: | sum(label_replace(irate(container_cpu_usage_seconds_total{container!="POD", container!="",image!=""}[1h]), "node", "$1", "instance", "(.*)")) by (container, pod, node, namespace) * on (node) group_left() avg(avg_over_time(node_cpu_hourly_cost[1h])) by (node) record: namespace:container_cpu_usage_costs_hourly:sum_rate - expr: | sum(label_replace(avg_over_time(container_memory_working_set_bytes{container!="POD",container!="",image!=""}[1h]), "node", "$1", "instance", "(.*)")) by (container, pod, node, namespace) / 1024.0 / 1024.0 / 1024.0 * on (node) group_left() avg(avg_over_time(node_ram_hourly_cost[1h])) by (node) record: namespace:container_memory_usage_costs_hourly:sum_rate - expr: | avg(avg_over_time(node_cpu_hourly_cost[1h])) by (node) record: node:node_cpu_hourly_cost:avg - expr: | avg(avg_over_time(node_ram_hourly_cost[1h])) by (node) record: node:node_ram_hourly_cost:avg - expr: | avg(avg_over_time(node_total_hourly_cost[1h])) by (node) record: node:node_total_hourly_cost:avg - name: scheduler.rules.30s interval: 30s rules: - record: cpu_usage_active expr: 100 - (avg by (instance) (irate(node_cpu_seconds_total{mode="idle"}[90s])) * 100) - record: mem_usage_active expr: 100*(1-node_memory_MemAvailable_bytes/node_memory_MemTotal_bytes) - name: scheduler.rules.1m interval: 1m rules: - record: cpu_usage_avg_5m expr: avg_over_time(cpu_usage_active[5m]) - record: mem_usage_avg_5m expr: avg_over_time(mem_usage_active[5m]) - name: scheduler.rules.5m interval: 5m rules: - record: cpu_usage_max_avg_1h expr: max_over_time(cpu_usage_avg_5m[1h]) - record: cpu_usage_max_avg_1d expr: max_over_time(cpu_usage_avg_5m[1d]) - record: mem_usage_max_avg_1h expr: max_over_time(mem_usage_avg_5m[1h]) - record: mem_usage_max_avg_1d expr: max_over_time(mem_usage_avg_5m[1d]) # adds additional scrape configs to prometheus.yml # must be a string so you have to add a | after extraScrapeConfigs: # example adds prometheus-blackbox-exporter scrape config extraScrapeConfigs: |- # this is used to scrape fadvisor - job_name: "fadvisor" honor_timestamps: true scheme: http metrics_path: /metrics static_configs: - targets: ['fadvisor.crane-system.svc.cluster.local:8081'] server: service: persistentVolume: enabled: false annotations: { } labels: { } clusterIP: "" ## List of IP addresses at which the Prometheus server service is available ## Ref: https: ## externalIPs: [ ] loadBalancerIP: "" loadBalancerSourceRanges: [ ] servicePort: 8080 sessionAffinity: None type: ClusterIP nodeExporter: hostRootfs: false alertmanager: enabled: false pushgateway: enabled: false kubeStateMetrics: ## If false, kube-state-metrics sub-chart will not be installed ## enabled: true ## kube-state-metrics sub-chart configurable values ## Please see https: ## kube-state-metrics: prometheus: monitor: honorLabels: true image: repository: ccr.ccs.tencentyun.com/tkeimages/kube-state-metrics pullPolicy: IfNotPresent tag: "2.2.4"
创建 grafana 配置的 ConfigMap:
apiVersion: v1kind: ConfigMapmetadata: labels: app.kubernetes.io/managed-by: Helm annotations: meta.helm.sh/release-name: grafana meta.helm.sh/release-namespace: crane-system name: grafana namespace: crane-systemdata: override_values: | service: enabled: true type: ClusterIP port: 8082 targetPort: 3000 # targetPort: 4181 To be used with a proxy extraContainer annotations: {} labels: {} portName: service # Administrator credentials when not using an existing secret (see below) adminUser: admin adminPassword: admin
将Prometheus,granfana,crane的repo作为 HelmRepository 资源添加。
通过添加这个 3 个 repo 我们可以访问到远程的 Helm 仓库以此来使用 Helm 来安装。
apiVersion: source.toolkit.fluxcd.io/v1beta1kind: HelmRepositorymetadata: name: prometheus namespace: crane-systemspec: interval: 10m timeout: 5m url: https:
apiVersion: source.toolkit.fluxcd.io/v1beta1kind: HelmRepositorymetadata: name: grafana namespace: crane-systemspec: interval: 10m timeout: 5m url: https:
apiVersion: source.toolkit.fluxcd.io/v1beta1kind: HelmRepositorymetadata: name: crane namespace: crane-systemspec: interval: 10m timeout: 5m url: https:
apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata: name: prometheus namespace: crane-systemspec: timeoout: 10m interval: 5m chart: spec: chart: prometheus version: 15.8.5 sourceRef: kind: HelmRepository name: prometheus interval: 5m targetNamespace: crane-system releaseName: prometheus valuesFrom: [{kind: ConfigMap,name: prometheus,valuesKey: override_values}]
sourceRef:为第 3 步中配置的 Helm Repo;
targetName:为部署的目标命名空间;
releaseName:为选择使用的 Release,因为相同的仓库中可能存在多个,所以这里需要指定特定的 release;
valuesFrom:为读取配置文件,这里选择类型为 ConfigMap 同时指定在第一步中创建的 Prometheus 的 cm 名称,valuesKey 为指定的 configMap 中的数据的 key;
apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata: name: grafana namespace: crane-systemspec: timeoout: 10m interval: 5m chart: spec: chart: grafana version: 6.28.0 sourceRef: kind: HelmRepository name: grafana interval: 5m targetNamespace: crane-system releaseName: grafana valuesFrom: [{kind: ConfigMap,name: grafana,valuesKey: override_values}]
apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata: name: fadvisor namespace: crane-systemspec: timeoout: 10m interval: 5m chart: spec: chart: fadvisor version: 0.2.0 sourceRef: kind: HelmRepository name: crane interval: 5m targetNamespace: crane-system releaseName: fadvisor
这里的f advisor 为 crane 官方开发的指标采集器。
apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata: name: crane namespace: crane-systemspec: timeoout: 10m interval: 5m chart: spec: chart: crane version: 0.3.0 sourceRef: kind: HelmRepository name: crane interval: 5m targetNamespace: crane-system releaseName: crane
PS:
以上的部署过程需要按顺序执行,但是在 kubevela的 addon 部署中,所有的资源是同时执行的所以有时可能会执行顺序错乱。
但是这部并不会导致整体执行失败,因为 k8s 会有定时的重调机制在重调机制触发时会将错误的资源重新创建。
使用 vela cli 从本地 enable crane 组件;
先到 crane 的本地目录,然后
vela addon enable crane
即可看到每个组件都可以部署,并再 crane-system 的命名空间下可以看到结果类似如下:
将对应的crane service的访问方式改为NodePort
在部署的环境下使用kubectl get svc -n crane-system 命令查找对应的服务
;使用 kubectl edit svc craned -n crane-system 并将type 修改为 NodePort。
这时 k8s 会自动分配一个端口。
使用kubectl get svc craned -n crane-system -o yaml 查看对应端口,即 dashboard-service 的端口
也可以使用以下命令暂时将端口转出:
kubectl port-forward -n crane-system svc/craned 9090
同时集群中也添加了对应的 CRD 资源如 EHAP 等。