<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          開源云原生成本優(yōu)化神器 Crane 使用教程

          共 64143字,需瀏覽 129分鐘

           ·

          2022-11-03 21:35

          Crane(https://gocrane.io/) 是一個基于 FinOps 的云資源分析與成本優(yōu)化平臺,它的愿景是在保證客戶應(yīng)用運行質(zhì)量的前提下實現(xiàn)極致的降本。Crane 已經(jīng)在騰訊內(nèi)部自研業(yè)務(wù)實現(xiàn)了大規(guī)模落地,部署數(shù)百個 K8s 集群、管控 CPU 核數(shù)達百萬,在降本增效方面取得了階段性成果。以騰訊某部門集群優(yōu)化為例,通過使用 FinOps Crane,該部門在保障業(yè)務(wù)穩(wěn)定的情況下,資源利用率提升了 3 倍;騰訊另一自研業(yè)務(wù)落地 Crane 后,在一個月內(nèi)實現(xiàn)了總 CPU 規(guī)模 40 萬核的節(jié)省量,相當(dāng)于成本節(jié)約超 1000 萬元/月。

          Crane 會通過下面 3 個方面來開啟成本優(yōu)化之旅:

          • 成本展示: Kubernetes 資源( Deployments, StatefulSets )的多維度聚合與展示。
          • 成本分析: 周期性的分析集群資源的狀態(tài)并提供優(yōu)化建議。
          • 成本優(yōu)化: 通過豐富的優(yōu)化工具更新配置達成降本的目標(biāo)。

          核心功能包括:成本可視化和優(yōu)化評估;內(nèi)置了多種推薦器 - 資源推薦、副本推薦、閑置資源推薦;基于預(yù)測的水平彈性器;負載感知的調(diào)度器;基于 QOS 的混部。下面我們來詳細了解下 Crane 的各項功能。

          安裝

          我們這里使用 Helm 的方式來進行安裝,首先需要安裝 Prometheus 和 Grafana(如果您已經(jīng)在環(huán)境中部署了 Prometheus 和 Grafana,可以跳過該步驟)。

          Crane 使用 Prometheus 獲取集群工作負載對資源的使用情況,可以使用如下所示命令安裝 Prometheus:

          $ helm repo add prometheus-community https://finops-helm.pkg.coding.net/gocrane/prometheus-community
          $ helm upgrade --install prometheus -n crane-system \
              --set pushgateway.enabled=false \
              --set alertmanager.enabled=false \
              --set server.persistentVolume.enabled=false \
              -f https://gitee.com/finops/helm-charts/raw/main/integration/prometheus/override_values.yaml \
              --create-namespace  prometheus-community/prometheus

          由于 Crane 的 Fadvisor 會使用 Grafana 來展示成本預(yù)估,所以我們也需要安裝 Grafana:

          $ helm repo add grafana https://finops-helm.pkg.coding.net/gocrane/grafana
          $ helm upgrade --install grafana \
              -f https://gitee.com/finops/helm-charts/raw/main/integration/grafana/override_values.yaml \
              -n crane-system \
              --create-namespace grafana/grafana

          上面我們指定的 values 文件中配置了 Prometheus 數(shù)據(jù)源以及一些相關(guān)的 Dashboard,直接安裝后即可使用。

          然后接下來安裝 crane 與 fadvisor,同樣直接使用 Helm Chart 安裝即可,如下命令所示:

          $ helm repo add crane https://finops-helm.pkg.coding.net/gocrane/gocrane
          $ helm upgrade --install crane -n crane-system --create-namespace crane/crane
          $ helm upgrade --install fadvisor -n crane-system --create-namespace crane/fadvisor

          安裝后可以查看 Pod 列表了解應(yīng)用狀態(tài):

          $ kubectl get pods -n crane-system
          NAME                                             READY   STATUS             RESTARTS         AGE
          crane-agent-8jrs5                                0/1     CrashLoopBackOff   71 (2m26s ago)   3h23m
          crane-agent-t2rpz                                0/1     CrashLoopBackOff   71 (65s ago)     3h23m
          craned-776c7b6c75-gx8cp                          2/2     Running            0                3h28m
          fadvisor-56fcc547b6-zvf6r                        1/1     Running            0                158m
          grafana-5cd57f9f6b-d7nk5                         1/1     Running            0                3h32m
          metric-adapter-887f6548d-qcbb8                   1/1     Running            0                3h28m
          prometheus-kube-state-metrics-5f6f856ffb-4lrrr   1/1     Running            0                3h34m
          prometheus-node-exporter-97vmz                   1/1     Running            0                3h27m
          prometheus-node-exporter-m2gr9                   1/1     Running            0                3h27m
          prometheus-server-7744f66fb4-lw2sz               2/2     Running            0                3h34m

          需要注意我們這里 crane-agent 啟動失敗了,這是因為我的 K8s 集群使用的是 containerd 這種容器運行時,需要明確聲明指定使用的運行時 endpoint:

          $ kubectl edit ds crane-agent -n crane-system
          # ......
              spec:
                containers:
                - args:
                  - --v=2
                  - --runtime-endpoint=/run/containerd/containerd.sock  # 指定有containerd的sock文件
                  command:
                  - /crane-agent
          # ......

          此外還需要更新 crane-agent 的 rbac 權(quán)限:

          $ kubectl edit clusterrole crane-agent
          # ......
          - apiGroups:
            - ensurance.crane.io
            resources:
            - podqosensurancepolicies
            - nodeqoss  # 增加 nodeqoss 和 podqoss 資源的權(quán)限
            - podqoss
          # ......

          然后我們可以再創(chuàng)建一個 Ingress 對象來暴露 crane 的 dashboard 服務(wù):

          apiVersion: networking.k8s.io/v1
          kind: Ingress
          metadata:
            name: ingress-crane-dashboard
            namespace: crane-system
          spec:
            ingressClassName: nginx
            rules:
              - host: crane.k8s.local # change to your domain
                http:
                  paths:
                    - path: /
                      pathType: Prefix
                      backend:
                        service:
                          name: craned
                          port:
                            number: 9090

          直接應(yīng)用該 ingress 資源對象即可,當(dāng)然前提是你已經(jīng)安裝了 ingress-nginx:

          $ kubectl get pods -n ingress-nginx
          NAME                                            READY   STATUS    RESTARTS      AGE
          ingress-nginx-controller-7647c44fb9-6gcsf       1/1     Running   8 (44m ago)   21d
          ingress-nginx-defaultbackend-7fc5bfd66c-gqmmj   1/1     Running   8 (44m ago)   21d
          $ kubectl get ingress -n crane-system
          NAME                      CLASS   HOSTS             ADDRESS        PORTS   AGE
          ingress-crane-dashboard   nginx   crane.k8s.local   192.168.0.52   80      11s

          crane.k8s.local 映射到 192.168.0.52 后就可以訪問 crane 的 dashboard 了:

          第一次訪問 dashboard 的時候需要添加一個 K8s 集群,添加添加集群按鈕開始添加,填入正確的 CRNE Endpoint 地址即可。

          然后切換到集群總覽可以查看到當(dāng)前集群的一些成本相關(guān)數(shù)據(jù),由于目前數(shù)據(jù)還不足,所以會有一些空的圖表。

          在成本分布頁面可以按照維度成本、集群成本和利用率指標(biāo)以及命名空間成本來展示成本的分布情況。

          智能推薦

          在 dasbhoard 中開箱后就可以看到相關(guān)的成本數(shù)據(jù),是因為在添加集群的時候我們安裝了推薦的規(guī)則。

          推薦框架會自動分析集群的各種資源的運行情況并給出優(yōu)化建議。Crane 的推薦模塊會定期檢測發(fā)現(xiàn)集群資源配置的問題,并給出優(yōu)化建議。智能推薦提供了多種 Recommender 來實現(xiàn)面向不同資源的優(yōu)化推薦。

          成本分析>推薦規(guī)則頁面可以看到我們安裝的兩個推薦規(guī)則。

          這些推薦規(guī)則實際上是安裝在 K8s 集群上的 RecommendationRule CRD 對象:
          $ kubectl get RecommendationRule
          NAME             RUNINTERVAL   AGE
          idlenodes-rule   24h           16m
          workloads-rule   24h           16m

          workloads-rule 這個推薦規(guī)則的資源對象如下所示:

          apiVersion: analysis.crane.io/v1alpha1
          kind: RecommendationRule
          metadata:
            name: workloads-rule
            labels:
              analysis.crane.io/recommendation-rule-preinstall: "true"
          spec:
            resourceSelectors:
              - kind: Deployment
                apiVersion: apps/v1
              - kind: StatefulSet
                apiVersion: apps/v1
            namespaceSelector:
              any: true
            runInterval: 24h
            recommenders:
              - name: Replicas
              - name: Resource

          RecommendationRule 是一個全部范圍內(nèi)的對象,該推薦規(guī)則會對所有命名空間中的 Deployments 和 StatefulSets 做資源推薦和副本數(shù)推薦。相關(guān)規(guī)范屬性如下所示:

          • 每隔 24 小時運行一次分析推薦,runInterval 格式為時間間隔,比如: 1h,1m,設(shè)置為空表示只運行一次。

          • 待分析的資源通過配置 resourceSelectors 數(shù)組設(shè)置,每個 resourceSelector 通過 kindapiVersionname 選擇 K8s 中的資源,當(dāng)不指定 name 時表示在 namespaceSelector 基礎(chǔ)上的所有資源。

          • namespaceSelector 定義了待分析資源的命名空間,any: true 表示選擇所有命名空間。

          • recommenders 定義了待分析的資源需要通過哪些 Recommender 進行分析。目前支持兩種 Recommender

            • 資源推薦(Resource): 通過 VPA 算法分析應(yīng)用的真實用量推薦更合適的資源配置
            • 副本數(shù)推薦(Replicas): 通過 HPA 算法分析應(yīng)用的真實用量推薦更合適的副本數(shù)量

          資源推薦

          Kubernetes 用戶在創(chuàng)建應(yīng)用資源時常常是基于經(jīng)驗值來設(shè)置 request 和 limit,通過資源推薦的算法分析應(yīng)用的真實用量推薦更合適的資源配置,你可以參考并采納它提升集群的資源利用率。該推薦算法模型采用了 VPA 的滑動窗口(Moving Window)算法進行推薦:

          • 通過監(jiān)控數(shù)據(jù),獲取 Workload 過去一周(可配置)的 CPU 和內(nèi)存的歷史用量。
          • 算法考慮數(shù)據(jù)的時效性,較新的數(shù)據(jù)采樣點會擁有更高的權(quán)重。
          • CPU 推薦值基于用戶設(shè)置的目標(biāo)百分位值計算,內(nèi)存推薦值基于歷史數(shù)據(jù)的最大值。

          副本數(shù)推薦

          Kubernetes 用戶在創(chuàng)建應(yīng)用資源時常常是基于經(jīng)驗值來設(shè)置副本數(shù)。通過副本數(shù)推薦的算法分析應(yīng)用的真實用量推薦更合適的副本配置,同樣可以參考并采納它提升集群的資源利用率。其實現(xiàn)的基本算法是基于工作負載歷史 CPU 負載,找到過去七天內(nèi)每小時負載最低的 CPU 用量,計算按 50%(可配置)利用率和工作負載 CPU Request 應(yīng)配置的副本數(shù)。

          當(dāng)我們部署 crane 的時候會在同一個命名空間中創(chuàng)建一個名為 recommendation-configuration 的 ConfigMap 對象,包含一個 yaml 格式的 RecommendationConfiguration,該配置訂閱了 recommender 的配置,如下所示:

          $ kubectl get cm recommendation-configuration -n crane-system -oyaml
          apiVersion: v1
          data:
            config.yaml: |-
              apiVersion: analysis.crane.io/v1alpha1
              kind: RecommendationConfiguration
              recommenders:
                - name: Replicas  # 副本數(shù)推薦
                  acceptedResources:
                    - kind: Deployment
                      apiVersion: apps/v1
                    - kind: StatefulSet
                      apiVersion: apps/v1
                - name: Resource  # 資源推薦
                  acceptedResources:
                    - kind: Deployment
                      apiVersion: apps/v1
                    - kind: StatefulSet
                      apiVersion: apps/v1
          kind: ConfigMap
          metadata:
            name: recommendation-configuration
            namespace: crane-system

          需要注意的是資源類型和 recommenders 需要可以匹配,比如 Resource 推薦默認只支持 Deployments 和 StatefulSets。

          同樣的也可以再查看一次閑置節(jié)點推薦規(guī)則的資源對象,如下所示:

          $ kubectl get recommendationrule idlenodes-rule -oyaml
          apiVersion: analysis.crane.io/v1alpha1
          kind: RecommendationRule
          metadata:
            labels:
              analysis.crane.io/recommendation-rule-preinstall: "true"
            name: idlenodes-rule
          spec:
            namespaceSelector:
              any: true
            recommenders:
            - name: IdleNode
            resourceSelectors:
            - apiVersion: v1
              kind: Node
            runInterval: 24h

          創(chuàng)建 RecommendationRule 配置后,RecommendationRule 控制器會根據(jù)配置定期運行推薦任務(wù),給出優(yōu)化建議生成 Recommendation 對象,然后我們可以根據(jù)優(yōu)化建議 Recommendation 調(diào)整資源配置。

          比如我們這里集群中已經(jīng)生成了多個優(yōu)化建議 Recommendation 對象。

          $ kubectl get recommendations
          NAME                            TYPE       TARGETKIND    TARGETNAMESPACE   TARGETNAME       STRATEGY   PERIODSECONDS   ADOPTIONTYPE          AGE
          workloads-rule-resource-8whzs   Resource   StatefulSet   default           nacos            Once                       StatusAndAnnotation   34m
          workloads-rule-resource-hx4cp   Resource   StatefulSet   default           redis-replicas   Once                       StatusAndAnnotation   34m
          # ......

          可以隨便查看任意一個優(yōu)化建議對象。

          $ kubectl get recommend workloads-rule-resource-g7nwp -n crane-system -oyaml
          apiVersion: analysis.crane.io/v1alpha1
          kind: Recommendation
          metadata:
            name: workloads-rule-resource-g7nwp
            namespace: crane-system
          spec:
            adoptionType: StatusAndAnnotation
            completionStrategy:
              completionStrategyType: Once
            targetRef:
              apiVersion: apps/v1
              kind: Deployment
              name: fadvisor
              namespace: crane-system
            type: Resource
          status:
            action: Patch
            conditions:
            - lastTransitionTime: "2022-10-20T07:43:49Z"
              message: Recommendation is ready
              reason: RecommendationReady
              status: "True"
              type: Ready
            currentInfo: '{"spec":{"template":{"spec":{"containers":[{"name":"fadvisor","resources":{"requests":{"cpu":"0","memory":"0"}}}]}}}}'
            lastUpdateTime: "2022-10-20T07:43:49Z"
            recommendedInfo: '{"spec":{"template":{"spec":{"containers":[{"name":"fadvisor","resources":{"requests":{"cpu":"114m","memory":"120586239"}}}]}}}}'
            recommendedValue: |
              resourceRequest:
                containers:
                - containerName: fadvisor
                  target:
                    cpu: 114m
                    memory: "120586239"
            targetRef: {}

          在 dashboard 的資源推薦頁面也能查看到優(yōu)化建議列表。

          在頁面中可以看到當(dāng)前資源(容器/CPU/Memory)與推薦的資源數(shù)據(jù),點擊采納建議即可獲取優(yōu)化的執(zhí)行命令。
          執(zhí)行命令即可完成優(yōu)化,其實就是修改資源對象的 resources 資源數(shù)據(jù)。
          patchData=`kubectl get recommend workloads-rule-resource-g7nwp -n crane-system -o jsonpath='{.status.recommendedInfo}'`;kubectl patch Deployment fadvisor -n crane-system --patch "${patchData}"

          對于閑置節(jié)點推薦,由于節(jié)點的下線在不同平臺上的步驟不同,用戶可以根據(jù)自身需求進行節(jié)點的下線或者縮容。

          應(yīng)用在監(jiān)控系統(tǒng)(比如 Prometheus)中的歷史數(shù)據(jù)越久,推薦結(jié)果就越準確,建議生產(chǎn)上超過兩周時間。對新建應(yīng)用的預(yù)測往往不準。

          自定義推薦

          Recommendation Framework 提供了一套可擴展的 Recommender 框架并支持了內(nèi)置的 Recommender,用戶可以實現(xiàn)一個自定義的 Recommender,或者修改一個已有的 Recommender。

          和 K8s 調(diào)度框架類似,Recommender 接口定義了一次推薦需要實現(xiàn)的四個階段和八個擴展點,這些擴展點會在推薦過程中按順序被調(diào)用。這些擴展點中的一些可以改變推薦決策,而另一些僅用來提供信息。

          推薦框架架構(gòu)

          Recommender 接口定義如下所示:

          type Recommender interface {
           Name() string
           framework.Filter
           framework.PrePrepare
           framework.Prepare
           framework.PostPrepare
           framework.PreRecommend
           framework.Recommend
           framework.PostRecommend
           framework.Observe
          }

          // Phase: Filter
          type Filter interface {
              // Filter 將過濾無法通過目標(biāo)推薦器推薦的資源
              Filter(ctx *RecommendationContext) error
          }

          // Phase: Prepare
          type PrePrepare interface {
              CheckDataProviders(ctx *RecommendationContext) error
          }

          type Prepare interface {
              CollectData(ctx *RecommendationContext) error
          }

          type PostPrepare interface {
              PostProcessing(ctx *RecommendationContext) error
          }

          type PreRecommend interface {
              PreRecommend(ctx *RecommendationContext) error
          }

          // Phase: Recommend
          type Recommend interface {
              Recommend(ctx *RecommendationContext) error
          }

          type PostRecommend interface {
              Policy(ctx *RecommendationContext) error
          }

          // Phase: Observe
          type Observe interface {
              Observe(ctx *RecommendationContext) error
          }

          整個推薦過程分成了四個階段:FilterPrepareRecommendObserve,階段的輸入是需要分析的 Kubernetes 資源,輸出是推薦的優(yōu)化建議。接口中的 RecommendationContext 保存了一次推薦過程中的上下文,包括推薦目標(biāo)、RecommendationConfiguration 等信息,我們可以根據(jù)自身需求增加更多的內(nèi)容。

          比如資源推薦就實現(xiàn)了 Recommender 接口,主要做了下面 3 個階段的處理:

          • Filter 階段:過濾沒有 Pod 的工作負載
          • Recommend 推薦:采用 VPA 的滑動窗口算法分別計算每個容器的 CPU 和內(nèi)存并給出對應(yīng)的推薦值
          • Observe 推薦:將推薦資源配置記錄到 crane_analytics_replicas_recommendation 指標(biāo)

          除了核心的智能推薦功能之外,Crane 還有很多高級特性,比如可以根據(jù)實際的節(jié)點利用率的動態(tài)調(diào)度器、基于流量預(yù)測的彈性 HPA 等等。

          智能調(diào)度器

          Crane 除了提供了智能推薦功能之外,還提供了一個調(diào)度器插件 Crane-scheduler 可以實現(xiàn)智能調(diào)度和完成拓撲感知調(diào)度與資源分配的工作。

          動態(tài)調(diào)度器

          K8s 的原生調(diào)度器只能通過資源的 requests 值來調(diào)度 pod,這很容易造成一系列負載不均的問題:

          • 對于某些節(jié)點,實際負載與資源請求相差不大,這會導(dǎo)致很大概率出現(xiàn)穩(wěn)定性問題。
          • 對于其他節(jié)點來說,實際負載遠小于資源請求,這將導(dǎo)致資源的巨大浪費。

          為了解決這些問題,動態(tài)調(diào)度器根據(jù)實際的節(jié)點利用率構(gòu)建了一個簡單但高效的模型,并過濾掉那些負載高的節(jié)點來平衡集群。

          動態(tài)調(diào)度器依賴于 prometheus 和 node-exporter 收集匯總指標(biāo)數(shù)據(jù),它由兩個組件組成:
          • Node-annotator 定期從 Prometheus 拉取數(shù)據(jù),并以 annotations 的形式在節(jié)點上用時間戳標(biāo)記它們。
          • Dynamic plugin 直接從節(jié)點的 annotations 中讀取負載數(shù)據(jù),過濾并基于簡單的算法對候選節(jié)點進行評分。

          動態(tài)調(diào)度器提供了一個默認值調(diào)度策略,配置文件如下所示:

          # policy.yaml
          apiVersion: scheduler.policy.crane.io/v1alpha1
           kind: DynamicSchedulerPolicy
           spec:
             syncPolicy:
               ##cpu usage
               - name: cpu_usage_avg_5m
                 period: 3m
               - name: cpu_usage_max_avg_1h
                 period: 15m
               - name: cpu_usage_max_avg_1d
                 period: 3h
               ##memory usage
               - name: mem_usage_avg_5m
                 period: 3m
               - name: mem_usage_max_avg_1h
                 period: 15m
               - name: mem_usage_max_avg_1d
                 period: 3h

             predicate:
               ##cpu usage
               - name: cpu_usage_avg_5m
                 maxLimitPecent: 0.65
               - name: cpu_usage_max_avg_1h
                 maxLimitPecent: 0.75
               ##memory usage
               - name: mem_usage_avg_5m
                 maxLimitPecent: 0.65
               - name: mem_usage_max_avg_1h
                 maxLimitPecent: 0.75

             priority:
               ##cpu usage
               - name: cpu_usage_avg_5m
                 weight: 0.2
               - name: cpu_usage_max_avg_1h
                 weight: 0.3
               - name: cpu_usage_max_avg_1d
                 weight: 0.5
               ##memory usage
               - name: mem_usage_avg_5m
                 weight: 0.2
               - name: mem_usage_max_avg_1h
                 weight: 0.3
               - name: mem_usage_max_avg_1d
                 weight: 0.5

             hotValue:
               - timeRange: 5m
                 count: 5
               - timeRange: 1m
                 count: 2

          我們可以根據(jù)實際需求自定義該策略配置,默認策略依賴于以下指標(biāo):

          • cpu_usage_avg_5m
          • cpu_usage_max_avg_1h
          • cpu_usage_max_avg_1d
          • mem_usage_avg_5m
          • mem_usage_max_avg_1h
          • mem_usage_max_avg_1d

          這幾個指標(biāo)我們這里是通過記錄規(guī)則創(chuàng)建的,可以查看 Prometheus 的配置文件來了解詳細信息:

          $ kubectl get cm -n crane-system prometheus-server -oyaml
          apiVersion: v1
          data:
            alerting_rules.yml: |
              {}
            alerts: |
              {}
            allow-snippet-annotations: "false"
            prometheus.yml: |
              global:
                evaluation_interval: 1m
                scrape_interval: 1m
                scrape_timeout: 10s
              rule_files:
              - /etc/config/recording_rules.yml
              - /etc/config/alerting_rules.yml
              - /etc/config/rules
              - /etc/config/alerts
              scrape_configs:
              - job_name: prometheus
                static_configs:
                - targets:
                  - localhost:9090
              # ......
            recording_rules.yml: |
              groups:
              - interval: 3600s
                name: costs.rules
                rules:
              #   ......
              - interval: 30s
                name: scheduler.rules.30s
                rules:
                - expr: 100 - (avg by (instance) (irate(node_cpu_seconds_total{mode="idle"}[90s]))
                    * 100)
                  record: cpu_usage_active
                - expr: 100*(1-node_memory_MemAvailable_bytes/node_memory_MemTotal_bytes)
                  record: mem_usage_active
              - interval: 1m
                name: scheduler.rules.1m
                rules:
                - expr: avg_over_time(cpu_usage_active[5m])
                  record: cpu_usage_avg_5m
                - expr: avg_over_time(mem_usage_active[5m])
                  record: mem_usage_avg_5m
              - interval: 5m
                name: scheduler.rules.5m
                rules:
                - expr: max_over_time(cpu_usage_avg_5m[1h])
                  record: cpu_usage_max_avg_1h
                - expr: max_over_time(cpu_usage_avg_5m[1d])
                  record: cpu_usage_max_avg_1d
                - expr: max_over_time(mem_usage_avg_5m[1h])
                  record: mem_usage_max_avg_1h
                - expr: max_over_time(mem_usage_avg_5m[1d])
                  record: mem_usage_max_avg_1d
            rules: |
              {}
          kind: ConfigMap
          metadata:
            name: prometheus-server
            namespace: crane-system

          在調(diào)度的 Filter 階段,如果該節(jié)點的實際使用率大于上述任一指標(biāo)的閾值,則該節(jié)點將被過濾。而在 Score 階段,最終得分是這些指標(biāo)值的加權(quán)和。

          在生產(chǎn)集群中,可能會頻繁出現(xiàn)調(diào)度熱點,因為創(chuàng)建 Pod 后節(jié)點的負載不能立即增加。因此,我們定義了一個額外的指標(biāo),名為 hotValue,表示節(jié)點最近幾次的調(diào)度頻率,并且節(jié)點的最終優(yōu)先級是最終得分減去 hotValue。

          我們可以在 K8s 集群中安裝 Crane-scheduler 作為第二個調(diào)度器來進行驗證:

          $ helm repo add crane https://finops-helm.pkg.coding.net/gocrane/gocrane
          $ helm upgrade --install scheduler -n crane-system --create-namespace --set global.prometheusAddr="http://prometheus-server.crane-system.svc.cluster.local:8080" crane/scheduler

          安裝后會創(chuàng)建一個名為 scheduler-config 的 ConfigMap 對象,里面包含的就是調(diào)度器的配置文件,我們會在配置中啟用 Dynamic 動態(tài)調(diào)度插件:

          $ kubectl get cm -n crane-system scheduler-config -oyaml
          apiVersion: v1
          data:
            scheduler-config.yaml: |
              apiVersion: kubescheduler.config.k8s.io/v1beta2
              kind: KubeSchedulerConfiguration
              leaderElection:
                leaderElect: false
              profiles:
              - schedulerName: crane-scheduler
                plugins:
                  filter:
                    enabled:
                    - name: Dynamic
                  score:
                    enabled:
                    - name: Dynamic
                      weight: 3
                pluginConfig:
                - name: Dynamic
                  args:
                    policyConfigPath: /etc/kubernetes/policy.yaml
          kind: ConfigMap
          metadata:
            name: scheduler-config
            namespace: crane-system

          安裝完成后我們可以任意創(chuàng)建一個 Pod,并通過設(shè)置 schedulerName: crane-scheduler 屬性明確指定使用該調(diào)度器進行調(diào)度,如下所示:

          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: cpu-stress
          spec:
            selector:
              matchLabels:
                app: cpu-stress
            replicas: 1
            template:
              metadata:
                labels:
                  app: cpu-stress
              spec:
                schedulerName: crane-scheduler
                hostNetwork: true
                tolerations:
                  - key: node.kubernetes.io/network-unavailable
                    operator: Exists
                    effect: NoSchedule
                containers:
                  - name: stress
                    image: docker.io/gocrane/stress:latest
                    command: ["stress", "-c", "1"]
                    resources:
                      requests:
                        memory: "1Gi"
                        cpu: "1"
                      limits:
                        memory: "1Gi"
                        cpu: "1"

          直接創(chuàng)建上面的資源對象,正常創(chuàng)建的 Pod 就會通過 Crane Scheduler 調(diào)度器進行調(diào)度了:

          Events:
            Type    Reason     Age   From             Message
            ----    ------     ----  ----             -------
            Normal  Scheduled  22s   crane-scheduler  Successfully assigned default/cpu-stress-cc8656b6c-hsqdg to node2
            Normal  Pulling    22s   kubelet          Pulling image "docker.io/gocrane/stress:latest"

          如果想默認使用該動態(tài)調(diào)度器,則可以使用該調(diào)度器去替換掉默認的調(diào)度器即可。

          拓撲感知調(diào)度

          Crane-Scheduler 和 Crane-Agent 配合工作可以完成拓撲感知調(diào)度與資源分配的工作。Crane-Agent 從節(jié)點采集資源拓撲,包括 NUMA、Socket、設(shè)備等信息,匯總到 NodeResourceTopology 這個自定義資源對象中。

          CPU 拓撲感知

          Crane-Scheduler 在調(diào)度時會參考節(jié)點的 NodeResourceTopology 對象獲取到節(jié)點詳細的資源拓撲結(jié)構(gòu),在調(diào)度到節(jié)點的同時還會為 Pod 分配拓撲資源,并將結(jié)果寫到 Pod 的 annotations 中。Crane-Agent 在節(jié)點上 Watch 到 Pod 被調(diào)度后,從 Pod 的 annotations 中獲取到拓撲分配結(jié)果,并按照用戶給定的 CPU 綁定策略進行 CPUSet 的細粒度分配。

          Crane 中提供了四種 CPU 分配策略,分別如下:

            none:該策略不進行特別的 CPUSet 分配,Pod 會使用節(jié)點 CPU 共享池。
            exclusive:該策略對應(yīng) kubelet 的 static 策略,Pod 會獨占 CPU 核心,其他任何 Pod 都無法使用。
            numa:該策略會指定 NUMA Node,Pod 會使用該 NUMA Node 上的 CPU 共享池。
            immovable:該策略會將 Pod 固定在某些 CPU 核心上,但這些核心屬于共享池,其他 Pod 仍可使用。

          首先需要在 Crane-Agent 啟動參數(shù)中添加 --feature-gates=NodeResourceTopology=true,CraneCPUManager=true 開啟拓撲感知調(diào)度特性。

          然后修改 kube-scheduler 的配置文件(scheduler-config.yaml ) 啟用動態(tài)調(diào)度插件并配置插件參數(shù):

          apiVersion: kubescheduler.config.k8s.io/v1beta2
          kind: KubeSchedulerConfiguration
          leaderElection:
            leaderElect: true
          clientConnection:
            kubeconfig: "REPLACE_ME_WITH_KUBE_CONFIG_PATH"
          profiles:
            - schedulerName: default-scheduler # 可以改成自己的調(diào)度器名稱
              plugins:
                preFilter:
                  enabled:
                    - name: NodeResourceTopologyMatch
                filter:
                  enabled:
                    - name: NodeResourceTopologyMatch
                score:
                  enabled:
                    - name: NodeResourceTopologyMatch
                      weight: 2
                reserve:
                  enabled:
                    - name: NodeResourceTopologyMatch
                preBind:
                  enabled:
                    - name: NodeResourceTopologyMatch

          正確安裝組件后,每個節(jié)點均會生成 NodeResourceTopology 對象。

          $ kubectl get nrt
          NAME    CRANE CPU MANAGER POLICY   CRANE TOPOLOGY MANAGER POLICY   AGE
          node1   Static                     SingleNUMANodePodLevel          35d

          可以看出集群中節(jié)點 node1 已生成對應(yīng)的 NRT 對象,此時 Crane 的 CPU Manager Policy 為 Static,節(jié)點默認的 Topology Manager Policy 為 SingleNUMANodePodLevel,代表節(jié)點不允許跨 NUMA 分配資源。

          使用以下實例進行調(diào)度測試:

          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: nginx-deployment
            labels:
              app: nginx
          spec:
            selector:
              matchLabels:
                app: nginx
            template:
              metadata:
                annotations:
                  topology.crane.io/topology-awareness: "true" # 添加注解,表示Pod需要感知CPU拓撲,資源分配不允許跨NUMA。若不指定,則拓撲策略默認繼承節(jié)點上的topology.crane.io/topology-awareness標(biāo)簽
                  topology.crane.io/cpu-policy: "exclusive" # 添加注解,表示Pod的CPU分配策略為exclusive策略。
                labels:
                  app: nginx
              spec:
                containers:
                  - image: nginx
                    name: nginx
                    resources:
                      limits:
                        cpu: "2" # 需要limits.cpu值,如果要開啟綁核,則該值必須等于requests.cpu。
                        memory: 2Gi

          應(yīng)用后可以從 annotations 中查看 Pod 的拓撲分配結(jié)果,發(fā)現(xiàn) Pod 在 NUMA Node0 上被分配了 2 個 CPU 核心。

          $ kubectl get pod -o custom-columns=name:metadata.name,topology-result:metadata.annotations."topology\.crane\.io/topology-result"
          name                                topology-result
          nginx-deployment-754d99dcdf-mtcdp   [{"name":"node0","type":"Node","resources":{"capacity":{"cpu":"2"}}}]

          實現(xiàn)基于流量預(yù)測的彈性

          Kubernetes HPA 支持了豐富的彈性擴展能力,Kubernetes 平臺開發(fā)者部署服務(wù)實現(xiàn)自定義 Metric 的服務(wù),Kubernetes 用戶配置多項內(nèi)置的資源指標(biāo)或者自定義 Metric 指標(biāo)實現(xiàn)自定義水平彈性。

          EffectiveHorizontalPodAutoscaler(簡稱 EHPA)是 Crane 提供的彈性伸縮產(chǎn)品,它基于社區(qū) HPA 做底層的彈性控制,支持更豐富的彈性觸發(fā)策略(預(yù)測,觀測,周期),讓彈性更加高效,并保障了服務(wù)的質(zhì)量。

          • 提前擴容,保證服務(wù)質(zhì)量:通過算法預(yù)測未來的流量洪峰提前擴容,避免擴容不及時導(dǎo)致的雪崩和服務(wù)穩(wěn)定性故障。
          • 減少無效縮容:通過預(yù)測未來可減少不必要的縮容,穩(wěn)定工作負載的資源使用率,消除突刺誤判。
          • 支持 Cron 配置:支持 Cron-based 彈性配置,應(yīng)對大促等異常流量洪峰。
          • 兼容社區(qū):使用社區(qū) HPA 作為彈性控制的執(zhí)行層,能力完全兼容社區(qū)。

          Effective HPA 兼容社區(qū)的 Kubernetes HPA 的能力,提供了更智能的彈性策略,比如基于預(yù)測的彈性和基于 Cron 周期的彈性等。在了解如何使用 EHPA 之前,我們有必要來詳細了解下 K8s 中的 HPA 對象。通過此伸縮組件,Kubernetes 集群可以利用監(jiān)控指標(biāo)(CPU 使用率等)自動擴容或者縮容服務(wù)中的 Pod 數(shù)量,當(dāng)業(yè)務(wù)需求增加時,HPA 將自動增加服務(wù)的 Pod 數(shù)量,提高系統(tǒng)穩(wěn)定性,而當(dāng)業(yè)務(wù)需求下降時,HPA 將自動減少服務(wù)的 Pod 數(shù)量,減少對集群資源的請求量,甚至還可以配合 Cluster Autoscaler 實現(xiàn)集群規(guī)模的自動伸縮,節(jié)省 IT 成本。

          不過目前默認的 HPA 對象只能支持根據(jù) CPU 和內(nèi)存的閾值檢測擴縮容,但也可以通過 custom metric api 來調(diào)用 Prometheus 實現(xiàn)自定義 metric,這樣就可以實現(xiàn)更加靈活的監(jiān)控指標(biāo)實現(xiàn)彈性伸縮了。

          默認情況下,HPA 會通過 metrics.k8s.io 這個接口服務(wù)來獲取 Pod 的 CPU、內(nèi)存指標(biāo),CPU 和內(nèi)存這兩者屬于核心指標(biāo),metrics.k8s.io 服務(wù)對應(yīng)的后端服務(wù)一般是 metrics-server,所以在使用 HPA 的時候需要安裝該應(yīng)用。

          如果 HPA 要通過非 CPU、內(nèi)存的其他指標(biāo)來伸縮容器,我們則需要部署一套監(jiān)控系統(tǒng)如 Prometheus,讓 Prometheus 采集各種指標(biāo),但是 Prometheus 采集到的 metrics 指標(biāo)并不能直接給 K8s 使用,因為兩者數(shù)據(jù)格式是不兼容的,因此需要使用到另外一個組件 prometheus-adapter,該組件可以將 Prometheus 的 metrics 指標(biāo)數(shù)據(jù)格式轉(zhuǎn)換成 K8s API 接口能識別的格式,另外我們還需要在 K8s 注冊一個服務(wù)(即 custom.metrics.k8s.io),以便 HPA 能通過 /apis/ 進行訪問。

          需要注意的是 Crane 提供了一個 metric-adapter 組件,該組件和 prometheus-adapter 都基于 custom-metric-apiserver 實現(xiàn)了 Custom Metric 和 External Metric 的 ApiService,在安裝 Crane 時會將對應(yīng)的 ApiService 安裝為 Crane 的 metric-adapter,所以它會和 prometheus-adapter 沖突,因為 Prometheus 是當(dāng)下最流行的開源監(jiān)控系統(tǒng),所以我們更愿意使用它來獲取用戶的自定義指標(biāo),那么我們就需要去安裝 prometheus-adapter,但是在安裝之前需要刪除 Crane 提供的 ApiService

          # 查看當(dāng)前集群 ApiService
          $ kubectl get apiservice |grep crane-system
          v1beta1.custom.metrics.k8s.io          crane-system/metric-adapter                    True                      3h51m
          v1beta1.external.metrics.k8s.io        crane-system/metric-adapter                    True                      3h51m

          # 刪除 crane 安裝的 ApiService
          $ kubectl delete apiservice v1beta1.custom.metrics.k8s.io
          $ kubectl delete apiservice v1beta1.external.metrics.k8s.io

          然后通過 Helm Chart 來安裝 Prometheus Adapter:

          $ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
          $ helm repo update
          # 指定有 prometheus 地址
          $ helm upgrade --install prometheus-adapter -n crane-system prometheus-community/prometheus-adapter --set image.repository=cnych/prometheus-adapter,prometheus.url=http://prometheus-server.crane-system.svc,prometheus.port=8080

          當(dāng) prometheus-adapter 安裝成功后我們再將 ApiService 改回 Crane 的 metric-adapter,應(yīng)用下面的資源清單即可:

          apiVersion: apiregistration.k8s.io/v1
          kind: APIService
          metadata:
            name: v1beta1.custom.metrics.k8s.io
          spec:
            service:
              name: metric-adapter
              namespace: crane-system
            group: custom.metrics.k8s.io
            version: v1beta1
            insecureSkipTLSVerify: true
            groupPriorityMinimum: 100
            versionPriority: 100
          ---
          apiVersion: apiregistration.k8s.io/v1
          kind: APIService
          metadata:
            name: v1beta1.external.metrics.k8s.io
          spec:
            service:
              name: metric-adapter
              namespace: crane-system
            group: external.metrics.k8s.io
            version: v1beta1
            insecureSkipTLSVerify: true
            groupPriorityMinimum: 100
            versionPriority: 100

          應(yīng)用了上面的對象后,ApiService 改回了 Crane 的 metric-adapter,那么就不能使用 prometheus-adapter 的自定義 Metrics 功能,我們可以通過 Crane 的 metric-adapter 提供的 RemoteAdapter 功能將請求轉(zhuǎn)發(fā)給 prometheus-adapter

          修改 metric-adapter 的配置,將 prometheus-adapter 的 Service 配置成 Crane Metric Adapter 的 RemoteAdapter

          $ kubectl edit deploy metric-adapter -n crane-system
          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: metric-adapter
            namespace: crane-system
          spec:
            template:
              spec:
                containers:
                - args:
                  # 添加外部 Adapter 配置
                  - --remote-adapter=true
                  - --remote-adapter-service-namespace=crane-system
                  - --remote-adapter-service-name=prometheus-adapter
                  - --remote-adapter-service-port=443
          # ......

          這是因為 Kubernetes 限制一個 ApiService 只能配置一個后端服務(wù),為了在一個集群內(nèi)使用 Crane 提供的 Metric 和 prometheus-adapter 提供的 Metric,Crane 支持了 RemoteAdapter 來解決該問題:

          • Crane Metric-Adapter 支持配置一個 Kubernetes Service 作為一個遠程 Adapter
          • Crane Metric-Adapter 處理請求時會先檢查是否是 Crane 提供的 Local Metric,如果不是,則轉(zhuǎn)發(fā)給遠程 Adapter

          下面我們來部署一個示例應(yīng)用,用來測試自定義指標(biāo)的容器彈性伸縮。如下所示的應(yīng)用暴露了 Metric 展示每秒收到的 http 請求數(shù)量。

          # sample-app.yaml
          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: sample-app
          spec:
            selector:
              matchLabels:
                app: sample-app
            template:
              metadata:
                labels:
                  app: sample-app
              spec:
                containers:
                  - image: luxas/autoscale-demo:v0.1.2
                    name: metrics-provider
                    resources:
                      limits:
                        cpu: 500m
                      requests:
                        cpu: 200m
                    ports:
                      - containerPort: 8080
          ---
          apiVersion: v1
          kind: Service
          metadata:
            name: sample-app
          spec:
            ports:
              - name: http
                port: 80
                targetPort: 8080
            selector:
              app: sample-app
            type: NodePort

          當(dāng)應(yīng)用部署完成后,我們可以通過命令檢查 http_requests_total 指標(biāo)數(shù)據(jù):

          $ curl http://$(kubectl get service sample-app -o jsonpath='{ .spec.clusterIP }')/metrics
          # HELP http_requests_total The amount of requests served by the server in total
          # TYPE http_requests_total counter
          http_requests_total 1

          然后我們需要在 Prometheus 中配置抓取 sample-app 的指標(biāo),我們這里使用如下所示命令添加抓取配置:

          $ kubectl edit cm -n crane-system prometheus-server
          # 添加抓取 sample-app 配置
          - job_name: sample-app
            kubernetes_sd_configs:
            - role: pod
            relabel_configs:
            - action: keep
              regex: default;sample-app-(.+)
              source_labels:
              - __meta_kubernetes_namespace
              - __meta_kubernetes_pod_name
            - action: labelmap
              regex: __meta_kubernetes_pod_label_(.+)
            - action: replace
              source_labels:
              - __meta_kubernetes_namespace
              target_label: namespace
            - source_labels: [__meta_kubernetes_pod_name]
              action: replace
              target_label: pod

          配置生效后我們可以在 Prometheus Dashboard 中查詢對應(yīng)的指標(biāo):

          為了讓 HPA 能夠用到 Prometheus 采集到的指標(biāo),prometheus-adapter 通過使用 promql 語句來獲取指標(biāo),然后修改數(shù)據(jù)格式,并把重新組裝的指標(biāo)和值通過自己的接口暴露。而 HPA 會通過 /apis/custom.metrics.k8s.io/ 代理到 prometheus-adapter 的 service 上來獲取這些指標(biāo)。

          如果把 Prometheus 的所有指標(biāo)到獲取一遍并重新組裝,那 adapter 的效率必然十分低下,因此 adapter 將需要讀取的指標(biāo)設(shè)計成可配置,讓用戶通過 ConfigMap 來決定讀取 Prometheus 的哪些監(jiān)控指標(biāo)。

          我們這里使用 Helm Chart 方式安裝的 prometheus-adapter,其默認的 Rule 配置如下所示:

          $ kubectl get cm -n crane-system prometheus-adapter -oyaml
          apiVersion: v1
          data:
            config.yaml: |
              rules:
              - seriesQuery: '{__name__=~"^container_.*",container!="POD",namespace!="",pod!=""}'
                seriesFilters: []
                resources:
                  overrides:
                    namespace:
                      resource: namespace
                    pod:
                      resource: pod
                name:
                  matches: ^container_(.*)_seconds_total$
                  as: ""
                metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>,container!="POD"}[5m]))
                  by (<<.GroupBy>>)
              # ...... 其他規(guī)則省略
          kind: ConfigMap
          metadata:
            name: prometheus-adapter
            namespace: crane-system

          Prometheus adapter 的配置文件格式如上所示,它分為兩個部分,第一個是 rules,用于 custom metrics,另一個是 resourceRules,用于 metrics,如果你只用 Prometheus adapter 做 HPA,那么 resourceRules 就可以省略。

          我們可以看到 rules 規(guī)則下面有很多的查詢語句,這些查詢語句的作用就是盡可能多的獲取指標(biāo),從而讓這些指標(biāo)都可以用于 HPA。也就是說通過 prometheus-adapter 可以將 Prometheus 中的任何一個指標(biāo)都用于 HPA,但是前提是你得通過查詢語句將它拿到(包括指標(biāo)名稱和其對應(yīng)的值)。也就是說,如果你只需要使用一個指標(biāo)做 HPA,那么你完全就可以只寫一條查詢,而不像上面使用了好多個查詢。整體上每個規(guī)則大致可以分為 4 個部分:

          • Discovery:它指定 Adapter 應(yīng)該如何找到該規(guī)則的所有 Prometheus 指標(biāo)
          • Association:指定 Adapter 應(yīng)該如何確定和特定的指標(biāo)關(guān)聯(lián)的 Kubernetes 資源
          • Naming:指定 Adapter 應(yīng)該如何在自定義指標(biāo) API 中暴露指標(biāo)
          • Querying:指定如何將對一個獲多個 Kubernetes 對象上的特定指標(biāo)的請求轉(zhuǎn)換為對 Prometheus 的查詢

          我們這里使用的 sample-app 應(yīng)用的指標(biāo)名叫 http_requests_total,通過上面的規(guī)則后會將 http_requests_total 轉(zhuǎn)換成 Pods 類型的 Custom Metric,可以獲得類似于 pods/http_requests 這樣的數(shù)據(jù)。

          執(zhí)行以下命令,通過 Custom Metrics 指標(biāo)查詢方式,查看 HPA 可用指標(biāo)詳情。

          $ kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/http_requests" | jq .
          {
            "kind""MetricValueList",
            "apiVersion""custom.metrics.k8s.io/v1beta1",
            "metadata": {
              "selfLink""/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/%2A/http_requests"
            },
            "items": [
              {
                "describedObject": {
                  "kind""Pod",
                  "namespace""default",
                  "name""sample-app-6876d5585b-wv8fl",
                  "apiVersion""/v1"
                },
                "metricName""http_requests",
                "timestamp""2022-10-27T11:19:05Z",
                "value""18m",
                "selector": null
              }
            ]
          }

          接下來我們就可以來測試下基于流量預(yù)測的容器彈性伸縮,這就需要用到 Crane 的 EHPA 對象了,我們可以使用上面的 pods/http_requests 自定義指標(biāo)來實現(xiàn)彈性功能。

          許多業(yè)務(wù)在時間序列上天然存在周期性的,尤其是對于那些直接或間接為“人”服務(wù)的業(yè)務(wù)。這種周期性是由人們?nèi)粘;顒拥囊?guī)律性決定的。例如,人們習(xí)慣于中午和晚上點外賣;早晚總有交通高峰;即使是搜索等模式不那么明顯的服務(wù),夜間的請求量也遠低于白天時間。對于這類業(yè)務(wù)相關(guān)的應(yīng)用來說,從過去幾天的歷史數(shù)據(jù)中推斷出次日的指標(biāo),或者從上周一的數(shù)據(jù)中推斷出下周一的訪問量是很自然的想法。通過預(yù)測未來 24 小時內(nèi)的指標(biāo)或流量模式,我們可以更好地管理我們的應(yīng)用程序?qū)嵗€(wěn)定我們的系統(tǒng),同時降低成本。EHPA 對象可以使用 DSP 算法來預(yù)測應(yīng)用未來的時間序列數(shù)據(jù),DSP 是一種預(yù)測時間序列的算法,它基于 FFT(快速傅里葉變換),擅長預(yù)測一些具有季節(jié)性和周期的時間序列。

          創(chuàng)建一個如下所示的 EHPA 資源對象,并開啟預(yù)測功能:

          # sample-app-ehpa.yaml
          apiVersion: autoscaling.crane.io/v1alpha1
          kind: EffectiveHorizontalPodAutoscaler
          metadata:
            name: sample-app-ehpa
            annotations:
              # metric-query.autoscaling.crane.io 是固定的前綴,后面是 前綴.Metric名字,需跟 spec.metrics 中的 Metric.name 相同,前綴支持 pods、resource、external
              metric-query.autoscaling.crane.io/pods.http_requests: "sum(rate(http_requests_total[5m])) by (pod)"
          spec:
            # ScaleTargetRef 是對需要縮放的工作負載的引用
            scaleTargetRef:
              apiVersion: apps/v1
              kind: Deployment
              name: sample-app
            # minReplicas 是可以縮小到的縮放目標(biāo)的最小副本數(shù)
            minReplicas: 1
            # maxReplicas 是可以擴大到的縮放目標(biāo)的最大副本數(shù)
            maxReplicas: 10
            # scaleStrategy 表示縮放目標(biāo)的策略,值可以是 Auto 或 Manual
            scaleStrategy: Auto
            # metrics 包含用于計算所需副本數(shù)的規(guī)范。
            metrics:
              # 在使用預(yù)測算法預(yù)測時,你可能會擔(dān)心預(yù)測數(shù)據(jù)不準帶來一定的風(fēng)險,EHPA 在計算副本數(shù)時,不僅會按預(yù)測數(shù)據(jù)計算,同時也會考慮實際監(jiān)控數(shù)據(jù)來兜底,提升彈性的安全性,所以可以定義下面的 Resource 監(jiān)控數(shù)據(jù)來兜底
              # - type: Resource
              - type: Pods
                pods:
                  metric:
                    name: http_requests
                  target:
                    type: AverageValue
                    averageValue: 500m # 當(dāng)出現(xiàn)了小數(shù)點,K8s 又需要高精度時,會使用單位 m 或k。例如1001m=1.001,1k=1000。
            # prediction 定義了預(yù)測資源的配置,如果未指定,則默認不啟用預(yù)測功能
            prediction:
              predictionWindowSeconds: 3600 # PredictionWindowSeconds 是預(yù)測未來指標(biāo)的時間窗口
              predictionAlgorithm:
                algorithmType: dsp # 指定dsp為預(yù)測算法
                dsp:
                  sampleInterval: "60s" # 監(jiān)控數(shù)據(jù)的采樣間隔為1分鐘
                  historyLength: "7d" # 拉取過去7天的監(jiān)控指標(biāo)作為預(yù)測的依據(jù)

          在上面的資源對象中添加了一個 metric-query.autoscaling.crane.io/pods.http_requests: "sum(rate(http_requests_total[5m])) by (pod)" 的 注解,這樣就可以開啟自定義指標(biāo)的預(yù)測功能了。

          相應(yīng)的在規(guī)范中定義了 spec.prediction 屬性,用來指定預(yù)測資源的配置,其中的 predictionWindowSeconds 屬性用來指定預(yù)測未來指標(biāo)的時間窗口,predictionAlgorithm 屬性用來指定預(yù)測的算法,比如我們這里配置的 algorithmType: dsp 表示使用 DSP(Digital Signal Processing)算法進行預(yù)測,該算法使用在數(shù)字信號處理領(lǐng)域中常用的的離散傅里葉變換、自相關(guān)函數(shù)等手段來識別、預(yù)測周期性的時間序列,關(guān)于該算法的實現(xiàn)原理可以查看官方文檔 https://gocrane.io/zh-cn/docs/tutorials/timeseriees-forecasting-by-dsp/ 的相關(guān)介紹,或者查看源碼以了解背后原理,相關(guān)代碼位于 pkg/prediction/dsp 目錄下。此外在 prediction.predictionAlgorithm.dsp 下面還可以配置 dsp 算法的相關(guān)參數(shù),比如我們這里配置的 sampleInterval: "60s" 表示監(jiān)控數(shù)據(jù)的采樣間隔為 1 分鐘,historyLength: "7d" 表示拉取過去 7 天的監(jiān)控指標(biāo)作為預(yù)測的依據(jù),此外還可以配置預(yù)測方式等。

          然后核心的配置就是 spec.metrics 了,用來指定計算所需副本數(shù)的規(guī)范,我們這里指定了基于 Pods 指標(biāo)的計算方式。

          - type: Pods
            pods:
              metric:
                name: http_requests
              target:
                type: AverageValue
                averageValue: 500m

          上面的配置表示當(dāng) pods/http_requests 的自定義指標(biāo)平均值達到 500m 后就可以觸發(fā) HPA 縮放,這里有一個點需要注意自定義指標(biāo)的 pods.metric.name 的值必須和 annotations 注解 metric-query.autoscaling.crane.io/pods.<metric name> 指標(biāo)名保持一致。

          EHPA 對象水平彈性的執(zhí)行流程如下所示:

          • EffectiveHPAController 創(chuàng)建 HorizontalPodAutoscalerTimeSeriesPrediction 對象
          • PredictionCore 從 Prometheus 獲取歷史 metric 通過預(yù)測算法計算,將結(jié)果記錄到 TimeSeriesPrediction
          • HPAController 通過 metric client 從 KubeApiServer 讀取 metric 數(shù)據(jù)
          • KubeApiServer 將請求路由到 Crane 的 Metric-Adapter。
          • HPAController 計算所有的 Metric 返回的結(jié)果得到最終的彈性副本推薦。
          • HPAController 調(diào)用 scale API 對目標(biāo)應(yīng)用擴/縮容。

          整體流程如下所示:

          直接應(yīng)用上面的 EPHA 對象即可:

          $ kubectl apply -f sample-app-ehpa.yaml
          effectivehorizontalpodautoscaler.autoscaling.crane.io/sample-app-ehpa created
          $ kubectl get ehpa
          NAME              STRATEGY   MINPODS   MAXPODS   SPECIFICPODS   REPLICAS   AGE
          sample-app-ehpa   Auto       1         10                       1          17s

          由于我們開啟了自動預(yù)測功能,所以 EPHA 對象創(chuàng)建后會創(chuàng)建一個對應(yīng)的 TimeSeriesPrediction 對象:

          $ kubectl get tsp
          NAME                   TARGETREFNAME   TARGETREFKIND   PREDICTIONWINDOWSECONDS   AGE
          ehpa-sample-app-ehpa   sample-app      Deployment      3600                      3m50s
          $ kubectl get tsp ehpa-sample-app-ehpa -oyaml
          apiVersion: prediction.crane.io/v1alpha1
          kind: TimeSeriesPrediction
          metadata:
            name: ehpa-sample-app-ehpa
            namespace: default
          spec:
            predictionMetrics:
            - algorithm:
                algorithmType: dsp
                dsp:
                  estimators: {}
                  historyLength: 7d
                  sampleInterval: 60s
              expressionQuery:
                expression: sum(http_requests{})
              resourceIdentifier: pods.http_requests
              type: ExpressionQuery
            predictionWindowSeconds: 3600
            targetRef:
              apiVersion: apps/v1
              kind: Deployment
              name: sample-app
              namespace: default
          status:
            conditions:
            - lastTransitionTime: "2022-10-27T13:01:14Z"
              message: not all metric predicted
              reason: PredictPartial
              status: "False"
              type: Ready
            predictionMetrics:
            - ready: false
              resourceIdentifier: pods.http_requests

          在 status 中可以看到包含 not all metric predicted 這樣的信息,這是因為應(yīng)用運行時間較短,可能會出現(xiàn)無法預(yù)測的情況。同樣也會自動創(chuàng)建一個對應(yīng)的 HPA 對象:

          $ kubectl get hpa
          NAME                   REFERENCE               TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
          ehpa-sample-app-ehpa   Deployment/sample-app   16m/500m   1         10        1          69m

          然后我們可以使用 ab 命令對 sample-app 做一次壓力測試,正常也可以觸發(fā)該應(yīng)用的彈性擴容。

          $ kubectl get svc sample-app
          NAME         TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
          sample-app   NodePort   10.104.163.144   <none>        80:31941/TCP   3h59m
          # 對 nodeport 服務(wù)做壓力測試
          $ ab -c 50 -n 2000 http://192.168.0.106:31941/
          $ kubectl get hpa
          NAME                   REFERENCE               TARGETS      MINPODS   MAXPODS   REPLICAS   AGE
          ehpa-sample-app-ehpa   Deployment/sample-app   7291m/500m   1         10        10         71m
          $ kubectl describe hpa ehpa-sample-app-ehpa
          Name:                       ehpa-sample-app-ehpa
          # ......
          Metrics:                    ( current / target )
            "http_requests" on pods:  8350m / 500m
          Min replicas:               1
          Max replicas:               10
          Deployment pods:            10 current / 10 desired
          Conditions:
            Type            Status  Reason            Message
            ----            ------  ------            -------
            AbleToScale     True    ReadyForNewScale  recommended size matches current size
            ScalingActive   True    ValidMetricFound  the HPA was able to successfully calculate a replica count from pods metric http_requests
            ScalingLimited  True    TooManyReplicas   the desired replica count is more than the maximum replica count
          Events:
            Type    Reason             Age   From                       Message
            ----    ------             ----  ----                       -------
            Normal  SuccessfulRescale  57s   horizontal-pod-autoscaler  New size: 4; reason: pods metric http_requests above target
            Normal  SuccessfulRescale  42s   horizontal-pod-autoscaler  New size: 8; reason: pods metric http_requests above target
            Normal  SuccessfulRescale  27s   horizontal-pod-autoscaler  New size: 10; reason: pods metric http_requests above target

          我們可以使用如下所示命令來查看 EHPA 自動生成的 HPA 對象的資源清單:

          $ kubectl get hpa.v2beta2.autoscaling ehpa-sample-app-ehpa -oyaml
          apiVersion: autoscaling/v2beta2
          kind: HorizontalPodAutoscaler
          metadata:
            name: ehpa-sample-app-ehpa
            namespace: default
          spec:
            maxReplicas: 10
            metrics:
            - pods:
                metric:
                  name: http_requests
                target:
                  averageValue: 500m
                  type: AverageValue
              type: Pods
            minReplicas: 1
            scaleTargetRef:
              apiVersion: apps/v1
              kind: Deployment
              name: sample-app
          # ...... 省略其他部分

          可以觀測到已經(jīng)創(chuàng)建出基于自定義指標(biāo)預(yù)測的 Metric: http_requests,由于生產(chǎn)環(huán)境的復(fù)雜性,基于多指標(biāo)的彈性(CPU/Memory/自定義指標(biāo))往往是生產(chǎn)應(yīng)用的常見選擇,因此 Effective HPA 通過預(yù)測算法覆蓋了多指標(biāo)的彈性,達到了幫助更多業(yè)務(wù)在生產(chǎn)環(huán)境落地水平彈性的成效。

          除此之外 EHPA 對象還支持基于 cron 的自動縮放,除了基于監(jiān)控指標(biāo),有時節(jié)假日和工作日的工作負載流量存在差異,簡單的預(yù)測算法可能效果不佳。然后可以通過設(shè)置周末 cron 來支持更大數(shù)量的副本來彌補預(yù)測的不足。對于一些非 web 流量的應(yīng)用,比如一些應(yīng)用不需要在周末使用,可以把工作負載的副本數(shù)減少到 1,也可以配置 cron 來降低你的服務(wù)成本。

          QOS 增強與混部

          除了上面介紹的主要功能之外,crane 還具有很多 QoS 增強功能,QoS 相關(guān)能力保證了運行在 Kubernetes 上的 Pod 的穩(wěn)定性。crane 具有干擾檢測和主動回避能力,當(dāng)較高優(yōu)先級的 Pod 受到資源競爭的影響時,Disable Schedule、Throttle 以及 Evict 將應(yīng)用于低優(yōu)先級的 Pod,以保證節(jié)點整體的穩(wěn)定,目前已經(jīng)支持節(jié)點的 cpu/內(nèi)存 負載絕對值/百分比作為水位線,在發(fā)生干擾進行驅(qū)逐或壓制時,會進行精確計算,將負載降低到略低于水位線即停止操作,防止誤傷和過渡操作。

          同時,crane 還支持自定義指標(biāo)適配整個干擾檢測框架,只需要完成排序定義等一些操作,即可復(fù)用包含精確操作在內(nèi)的干擾檢測和回避流程。

          此外 crane 還具有預(yù)測算法增強的彈性資源超賣能力,將集群內(nèi)的空閑資源復(fù)用起來,同時結(jié)合 crane 的預(yù)測能力,更好地復(fù)用閑置資源,當(dāng)前已經(jīng)支持 cpu 和內(nèi)存的空閑資源回收。同時具有彈性資源限制功能,限制使用彈性資源的 workload 最大和最小資源使用量,避免對高優(yōu)業(yè)務(wù)的影響和饑餓問題。

          同時具備增強的旁路 cpuset 管理能力,在綁核的同時提升資源利用效率。

          總結(jié)

          2022 年,騰訊云原生 FinOps Crane 項目組,結(jié)合行業(yè)及產(chǎn)業(yè)的發(fā)展趨勢,聯(lián)動中國產(chǎn)業(yè)互聯(lián)網(wǎng)發(fā)展聯(lián)盟、中國信通院、中國電子節(jié)能技術(shù)協(xié)會、FinOps 基金會及中國內(nèi)外眾多生態(tài)合作伙伴,開展及推動技術(shù)標(biāo)準、國內(nèi)聯(lián)盟、國際開源、雙碳升級等多維度的成果落地,輸出了系列白皮書和標(biāo)準指南,旨在助力企業(yè)和生態(tài)更良性發(fā)展和應(yīng)用先進技術(shù),達成降本增效,節(jié)能減排目標(biāo)方向。

          Crane 能力全景圖

          我們可以自己在 K8s 集群中安裝 crane 來獲取這些相關(guān)功能,此外這些能力也都會在騰訊云 TKE 的原生節(jié)點產(chǎn)品 Housekeeper 中提供,新推出的 TKE Housekeeper 是騰訊云推出的全新 K8s 運維范式,可以幫助企業(yè)像管理 Workload 一樣聲明式管理 Node 節(jié)點,高效解決節(jié)點維護、資源規(guī)劃等各種各樣的運維問題。

          毫無疑問,Crane 已經(jīng)是 K8s 集群中用于云資源分析和經(jīng)濟的最佳 FinOps 平臺了。目前,騰訊云 Crane 已進入 CNCF LandScape,這意味著 Crane 已成為云原生領(lǐng)域的重要項目。面向未來,騰訊云還將持續(xù)反饋開源社區(qū)、共建開源生態(tài),幫助更多企業(yè)通過云原生全面釋放生產(chǎn)力,加速實現(xiàn)數(shù)字化和綠色化雙轉(zhuǎn)型。




          最后,上周末舉行的騰訊云 Techo Day 技術(shù)開放日活動也對 Crane 進行了深入解析,相關(guān)資料及課件被收錄進了《騰訊云云原生工具指南》里,除此以外,里面還涵蓋了遨馳分布式云操作系統(tǒng)、微服務(wù)等多款熱門產(chǎn)品的技術(shù)原理解讀,幫助開發(fā)者用專業(yè)方法解決業(yè)務(wù)痛點,還有多個云原生實踐標(biāo)桿案例分享,講述云原生如何實現(xiàn)價值,非常推薦給感興趣的朋友下載看看。


          ▲ 點擊上方卡片關(guān)注Github愛好者,獲取前沿開源作品

          瀏覽 140
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产精品 码一本A片 | 2018天天操天天干 | 久久国内综合视频 | 婷婷午夜 | A片在线免费观看网址 |