Serverless 成本再優化:Knative 支持搶佔式實例

作者:元毅、向先

Knative 是一款雲原生、跨平臺的開源 Serverless 應用編排框架,而搶佔式實例是公有云中性價比較高的資源。Knative 與搶佔式實例的結合可以進一步降低用戶資源使用成本。本文介紹如何在 Knative 中使用搶佔式實例。

背景信息

搶佔式實例是一種低成本競價型實例,您可以對阿里雲當前閒置的資源出價,獲得資源後運行容器,直到出價低於市場價格或者庫存不足等原因導致資源回收。

Knative 是一款基於 Kubernetes 的開源 Serverless 應用編排框架,其目標是制定雲原生、跨平臺的 Serverless 應用編排標準。Knative 主要功能包括基於請求的自動彈性、縮容到 0、多版本管理、基於流量的灰度發佈、函數部署以及事件驅動等。

Knative 與搶佔實例結合

Knative 中提供了 Serverless 工作負載:Knative Service,可以基於請求自動擴縮容 Pod,使用搶佔式實例的話只需要配置相應的 Pod 註解即可。而在 Virtual Node 根據 Pod 的註解自動申請對應的 ECI 資源規格。當前 Virtual Node 提供了搶佔式實例自動替換能力,可以更加自動化的使用搶佔式實例。

Knative 結合搶佔式實例的優勢:

  • Serverless 場景: 短時 web 服務請求,資源隨時使用,用完即釋放,不會長時間佔用資源。
  • 優雅下線的天然適配: 在 Virtual Node 實現自動替換過程中,需要先刪除 Pod,然後工作負載控制器再創建新的搶佔式實例,這就要求業務容器具備優雅下線的能力。而在 Knative 中會爲每個 Pod 設置 1 個 queue-proxy sidecar 容器,在刪除 Pod 時,會先觸發 queue-proxy 容器等待請求處理完成,然後再刪除業務容器。
  • 成本敏感: 對於使用 Knative 用戶,更關心成本,因此支持搶佔式實例更具吸引力。

如何做到搶佔式實例自動替換

由於 ECI 搶佔式實例在市場價格高於出價或實例規格庫存不足時會被回收。因此,使用 ECI 搶佔式實例在帶來經濟性的同時,也帶來了應用穩定性的挑戰。爲儘量避免 ECI 搶佔式實例回收導致的業務中斷,容器服務 Virtual Node 在 ECI 搶佔式實例回收前,通過發出的 SpotToBeReleased Event 和 Pod Condition 來通知用戶。可以基於這些通知,進行搶佔實例的優雅退出和 Pod 輪轉等處理。

優先使用搶佔式實例

可以通過設置 k8s.aliyun.com/eci-spot-strategy 註解,如 SpotAsPriceGo 策略表示系統自動出價,跟隨當前市場實際價格。創建後,可以穩定使用 1 小時,超出 1 小時保護期後,如果某一時刻的市場價格高於出價或實例規格庫存不足,搶佔式實例會被釋放。在到達保護期之前,Virtual Node 會發出到期通知,然後會自動驅逐刪除 Pod,然後 Knative 會自動創建新的搶佔式實例 Pod,如果搶佔成功,則繼續通過搶佔式實例提供服務。

無搶佔式實例,使用標準實例

如果想盡量保證服務的穩定性,避免申請搶佔實例失敗導致的服務受損。可以通過配置 k8s.aliyun.com/eci-spot-fallback: true,自動轉爲按量付費,以保證實例創建成功。

搶佔式實例中斷通知

搶佔式實例會在中斷前 3 分鐘發出 SpotToBeReleased Event,同時會更新 Pod Conditions 的 ContainerInstanceExpired 字段爲 true。

Pod 的 Conditions 字段和 Events 字段顯示如下。

配置搶佔式實例到期的優雅處理方式

爲儘量避免 ECI 搶佔式實例回收導致的業務中斷,虛擬節點提供了可配置的 ECI 搶佔式實例優雅下線的功能。您可以爲搶佔型 Pod 配置 annotations k8s.aliyun.com/eci-spot-release-strategy: api-evict。

那麼當虛擬節點接收到 SpotToBeReleased Event 時,則會調用 Eviction API 來驅逐該搶佔式實例。API 發起的驅逐將遵從您的 PodDisruptionBudgets 和 terminationGracePeriodSeconds 配置。使用 API 創建 Eviction 對象,類似於對 Pod 執行策略控制的 DELETE 操作。

  1. 調用 API 請求:虛擬節點接收到 SpotToBeReleased Event,調用 Eviction API。
  2. PDB 檢查:API 服務器驗證與目標 Pod 關聯的 PodDisruptionBudget。
  3. 驅逐執行:如果API服務器允許驅逐,Pod 將按照如下方式刪除。
    1. API 服務器中的 Pod 資源會更新刪除時間戳,之後 API 服務器會認爲此 Pod 資源將被終止。此 Pod 資源還會標記上配置的寬限期。
    2. 本地運行狀態的 Pod 所處的節點上的 kubelet 注意到 Pod 資源被標記爲終止,並開始優雅停止本地 Pod。
    3. 當 kubelet 停止 Pod 時,控制面從 Endpoint 和 EndpointSlice 對象中移除該 Pod。因此,控制器不再將此 Pod 視爲有用對象。
    4. Pod 的寬限期到期後,kubelet 強制終止本地 Pod。
    5. kubelet 告訴 API 服務器刪除 Pod 資源。
    6. API 服務器刪除 Pod 資源。
  1. Knative Service:Knative 中會爲每個 Pod 設置 1 個 queue-proxy sidecar 容器,在刪除 Pod 時,會先觸發 queue-proxy 容器等待請求處理完成,然後再刪除業務容器。

釋放說明

搶佔式實例創建成功後,在保護期內可以正常運行。超出保護期後,如果市場價格高於出價或者資源庫存不足,搶佔式實例會被釋放。可以通過以下信息瞭解搶佔式實例的釋放情況。

  • 預釋放事件搶佔式實例在釋放前約 5 分鐘,會產生 SpotToBeReleased 事件。注意:ECI 會通過 Kubernetes Events 事件通知的方式告知您搶佔式實例將被釋放, 在此期間,您可以做一定的處理來確保業務不受實例釋放所影響。
    • 通過 kubectl describe 命令查看 Pod 詳細信息,在返回信息的 Events 中可以看到預釋放事件。示例如下:
    • 通過 kukubectl get events 命令查看事件信息,在返回信息中可以看到預釋放事件。示例如下:
  • 釋放後 Pod 狀態搶佔式實例釋放後,實例信息仍會保留,狀態變更爲 Failed,Failed 原因爲 BidFailed。
    • 通過 kubectl get pod 命令查看 Pod 信息,在返回信息中可以看到 Pod 狀態已變更。示例如下:
    • 通過 kubectl describe 命令查看 Pod 詳細信息,在返回信息中可以看到 Pod 狀態信息。示例如下:
Events:
  Type     Reason            Age    From          Message
  ----     ------            ----   ----          -------
  Warning  SpotToBeReleased  3m32s  kubelet, eci  Spot ECI will be released in 3 minutes
LAST SEEN   TYPE      REASON             OBJECT         MESSAGE
3m39s       Warning   SpotToBeReleased   pod/pi-frmr8   Spot ECI will be released in 3 minutes
NAME       READY   STATUS      RESTARTS   AGE
pi-frmr8   1/1     BidFailed   0          3h5m
Status:             Failed
Reason:             BidFailed
Message:            The pod is spot instance, and have been released at 2020-04-08T12:36Z

配置方式

在 Knative Service 中添加 Annotation 來創建搶佔式實例。相關 Annotation 如下:

🔔 說明: 僅支持在創建 ECI Pod 時添加 ECI 相關 Annotation 來生效 ECI 功能,更新 ECI Pod 時添加或者修改 ECI 相關 Annotation 均不會生效。

示例一:指定 ECS 規格,採用 SpotWithPriceLimit 策略

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: helloworld-go
spec:
  template:
    metadata:
      labels:
        alibabacloud.com/eci: "true"
      annotations:
        k8s.aliyun.com/eci-use-specs : "ecs.c6.large"           #指定ECS實例規格
        k8s.aliyun.com/eci-spot-strategy: "SpotWithPriceLimit"  #採用自定義設置價格上限的策略
        k8s.aliyun.com/eci-spot-price-limit: "0.25"            #設置每小時價格上限
    spec:         
      containers:
      - env:
        - name: TARGET
          value: "Knative"
        image: registry.cn-hangzhou.aliyuncs.com/knative-sample/helloworld-go:73fbdd56

以上 YAML 示例可創建一個 ecs.c6 規格的搶佔式實例。

  • 創建時,如果沒有滿足規格和價格上限要求的庫存,則創建失敗。
  • 創建後,可以穩定使用 1 小時,超出 1 小時保護期後,如果某一時刻的市場價格高於出價或實例規格庫存不足,搶佔式實例會被釋放。

示例二:設置沒有庫存時自動轉爲按量付費

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: helloworld-go
spec:
  template:
    metadata:
      labels:
        alibabacloud.com/eci: "true" 
      annotations:
        k8s.aliyun.com/eci-use-specs : "ecs.c6.large"           #指定ECS實例規格
        k8s.aliyun.com/eci-spot-strategy: "SpotWithPriceLimit"  #採用自定義設置價格上限的策略
        k8s.aliyun.com/eci-spot-price-limit: "0.05"            #設置每小時價格上限
        k8s.aliyun.com/eci-spot-fallback: "true"                #當搶佔式實例沒有庫存時,自動轉爲按量付費
    spec:         
      containers:
      - env:
        - name: TARGET
          value: "Knative"
        image: registry.cn-hangzhou.aliyuncs.com/knative-sample/helloworld-go:73fbdd56

以上 YAML 示例可創建一個 ecs.c6 規格的搶佔式實例。

  • 創建時,如果有滿足規格和價格上限要求的庫存,則會創建一個搶佔式實例。創建後,可以穩定使用 1 小時,超出 1 小時保護期後,如果某一時刻的市場價格高於出價或實例規格庫存不足,搶佔式實例會被釋放。
  • 創建時,如果沒有滿足規格和價格上限要求的庫存,則會創建一個按量付費的實例。創建後,系統不會主動釋放實例。實例創建成功後,您可以通過 kubectl describe pod 命令查看對應 Pod 的事件來確認是否轉爲按量付費實例,如果看到 SpotDegraded 事件,則表明已轉爲按量付費實例。

最佳實踐

由於搶佔式實例不能保證一直有庫存,而我們大部分情況下希望服務不能中斷。那麼我們可以這樣配置:

  • 採用系統自動出價,跟隨當前市場實際價格前市場實際價格。
  • 設置搶佔式實例的保護期。
  • 搶佔式實例沒有庫存時,自動轉爲按量付費,以保證實例創建成功。

具體 Knative Service 配置如下:

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: helloworld-go
spec:
  template:
    metadata:
      labels:
        alibabacloud.com/eci: "true" 
      annotations:
        k8s.aliyun.com/eci-use-specs : "ecs.c6.large"           #指定ECS實例規格
        k8s.aliyun.com/eci-spot-strategy: "SpotAsPriceGo"  #採用自定義設置價格上限的策略
        k8s.aliyun.com/eci-spot-duration: "1"
        k8s.aliyun.com/eci-spot-fallback: "true"                #當搶佔式實例沒有庫存時,自動轉爲按量付費
    spec:         
      containers:
      - env:
        - name: TARGET
          value: "Knative"
        image: registry.cn-hangzhou.aliyuncs.com/knative-sample/helloworld-go:73fbdd56

小結

當前容器服務 Knative 結合 Virtual Node 已支持自動替換的方式使用搶佔式實例,歡迎有興趣的加入 Knative 釘釘交流羣。(羣號:23302777

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章