返回文章列表

KubeRay叢集互動與最佳實踐

本文探討與KubeRay叢集互動的實務操作,涵蓋kubectl exec、Ray Job Submission、Ray

容器技術 分散式系統

在 Kubernetes 環境中佈署 Ray 叢集後,需要有效地與叢集互動並執行 Ray 程式。本文將介紹三種主要互動方式:kubectl exec 直接與 head pod 互動執行命令;Ray Job Submission 伺服器提交指令碼執行;以及使用 Ray Client 在本地執行 Ray 工作負載。同時,文章也涵蓋了公開 KubeRay 服務的考量,並探討最佳的叢集組態策略,包括 headGroupSpecworkerGroupSpecsrayStartParams 等關鍵引數的設定,以及資源分配、日誌記錄和持久化組態的最佳實踐。此外,文章也提供使用 Ray 叢集啟動器簡化佈署流程的說明,並提供 AWS、GCP 和 Azure 等不同雲端平台的佈署組態範例,方便讀者根據自身需求快速上手。最後,文章也介紹了 Ray AI Runtime (AIR) 的核心概念,並以一個實際案例逐步演示如何使用 AIR 進行資料預處理、模型訓練、超引數調優、模型儲存、批次預測以及模型佈署等完整流程。

與KubeRay叢集互動的實務

在前面的章節中,我們已經成功佈署了一個Ray叢集於Kubernetes環境中。現在,讓我們進一步瞭解如何與這個叢集互動以及執行Ray程式。

為什麼需要了解Kubernetes

您可能會疑惑為什麼我們花這麼多時間討論Kubernetes,尤其是在您主要感興趣於如何在Kubernetes上執行Ray指令碼的時候。雖然理解Kubernetes的基礎很重要,但我們的最終目標是有效地在Kubernetes上執行Ray應用。

用於測試的Python指令碼

首先,我們將使用以下Python指令碼作為範例,命名為script.py。這個指令碼將連線到Ray叢集並執行一些標準的Ray命令:

import ray
ray.init(address="auto")
print(ray.cluster_resources())

@ray.remote
def test():
    return 12

ray.get([test.remote() for i in range(12)])

內容解密:

  1. import ray:匯入Ray函式庫。
  2. ray.init(address="auto"):自動檢測並連線到Ray叢集。
  3. print(ray.cluster_resources()):列印叢集的資源狀況。
  4. @ray.remote:定義一個可以在Ray叢集上遠端執行的函式。
  5. ray.get([test.remote() for i in range(12)]):遠端執行test函式12次並取得結果。

執行Ray程式的三種主要方法

  1. 使用kubectl exec:直接與head pod互動,執行命令:

kubectl exec kubectl get pods -o custom-columns=POD:metadata.name | grep raycluster-complete-head -it -c ray-head – python

   在這個Python終端中,您可以連線並執行自己的Ray應用。

2. **使用Ray Job Submission伺服器**:
   - 首先,進行埠轉發:
     ```bash
kubectl port-forward service/raycluster-complete-head-svc 8265:8265
  • 然後,提交指令碼:

export RAY_ADDRESS=“http://localhost:8265” ray job submit –working-dir=. – python script.py

   這將輸出任務提交的結果和相關資訊。

3. **使用Ray Client**:
   - 首先,確保本地的Ray安裝版本和Python次要版本與Ray叢集中的版本相符。
   - 然後,進行埠轉發:
     ```bash
kubectl port-forward service/raycluster-complete-head-svc 10001:10001
  • 在本地Python shell中啟動Ray Client連線:

import ray ray.init(address=“ray://localhost:10001”) print(ray.cluster_resources())

@ray.remote def test(): return 12

ray.get([test.remote() for i in range(12)])

   這樣,您就可以直接在本地執行Ray工作負載,而無需透過kubectl或任務提交傳輸程式碼。

### 公開KubeRay服務

在生產環境中,您可能需要考慮其他方法來公開這些服務。預設情況下,Ray服務可以在Kubernetes叢集內的任何地方存取。如果需要從叢集外部存取,可以使用入口控制器。

### 組態KubeRay

讓我們看看執行在Kubernetes上的Ray叢集的組態。以下是一個簡化的組態範例:
```yml
apiVersion: ray.io/v1alpha1
kind: RayCluster
metadata:
  name: raycluster-complete
spec:
  headGroupSpec:
    rayStartParams:
      port: '6379'
      num-cpus: '1'
    template:
      spec:
        containers:
        - name: ray-head
          image: rayproject/ray:1.12.1
          resources:
            limits:
              cpu: "1"
              memory: "1024Mi"
            requests:
              cpu: "1"
              memory: "1024Mi"
          ports:
          - containerPort: 6379
            name: gcs
          - containerPort: 8265
            name: dashboard
          - containerPort: 10001
            name: client
  workerGroupSpecs:
  - groupName: small-group
    replicas: 2
    rayStartParams:
      ...

圖表翻譯:

此圖示呈現了KubeRay的組態結構,包括headGroupSpec和workerGroupSpecs的主要組成部分。

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title KubeRay叢集互動與最佳實踐

package "Kubernetes Cluster" {
    package "Control Plane" {
        component [API Server] as api
        component [Controller Manager] as cm
        component [Scheduler] as sched
        database [etcd] as etcd
    }

    package "Worker Nodes" {
        component [Kubelet] as kubelet
        component [Kube-proxy] as proxy
        package "Pods" {
            component [Container 1] as c1
            component [Container 2] as c2
        }
    }
}

api --> etcd : 儲存狀態
api --> cm : 控制迴圈
api --> sched : 調度決策
api --> kubelet : 指令下達
kubelet --> c1
kubelet --> c2
proxy --> c1 : 網路代理
proxy --> c2

note right of api
  核心 API 入口
  所有操作經由此處
end note

@enduml

圖表翻譯: 此圖表顯示了RayCluster的主要組態結構,包括head節點和worker節點的規格設定。其中,headGroupSpec定義了head節點的引數和容器設定,而workerGroupSpecs則定義了worker節點群組的名稱、副本數量等引數。

在Kubernetes上佈署Ray叢集的關鍵組態與最佳實踐

Ray叢集架構設計與資源分配

在Kubernetes環境中佈署Ray叢集時,合理的資源分配與組態至關重要。理想情況下,每個Ray Pod應盡可能佔用整個Kubernetes節點,以減少不必要的效能開銷。然而,在某些特定情境下,例如資源有限或使用GKE Autopilot等託管服務時,在單一節點上執行多個Ray Pod也是合理的選擇。

主要組態引數詳解

  1. headGroupSpec與workerGroupSpecs

    • headGroupSpec定義了Ray叢集頭節點(Head Pod)的組態。
    • workerGroupSpecs則用於定義工作節點(Worker Pod)的組態,可設定多個工作群組,每個群組擁有獨立的組態範本。
    • replicas欄位決定了每個工作群組中應保持的Worker Pod數量。
  2. rayStartParams

    • 這是一個字串對字串的對映,用於傳遞給Ray Pod的ray start入口點。
    • 特別需要注意的引數包括num-cpusnum-gpus
      • num-cpus:告知Ray排程器該Pod可用的CPU資源數量,可透過Kubernetes資源限制自動偵測,但也可手動覆寫。例如,設定num-cpus:"0"可防止具有非零CPU需求的工作負載被排程到頭節點上。
      • num-gpus:指定可用的GPU數量,目前需手動設定以支援GPU工作負載。
  3. template與resources

    • template欄位是Kubernetes Pod範本,用於定義Head或Worker群組中Pod的具體組態。
    • 必須為每個群組規格指定容器CPU和記憶體請求及限制,對於GPU工作負載,還需設定GPU限制(如nvidia.com/gpu: 1)。
  4. nodeSelector與tolerations

    • 這兩個欄位控制了Worker群組中Ray Pod的排程行為,決定了Pod可被排程到哪些Kubernetes節點上。
    • KubeRay運算元在Pod層級運作,對底層Kubernetes節點的組態不做干預,需由叢集管理員負責。

日誌記錄與持久化組態

Ray叢集的程式預設將日誌寫入Pod中的/tmp/ray/session_latest/logs目錄,並可在Ray儀錶板中檢視。為了在Pod生命週期結束後仍保留日誌,可採用以下方法:

  1. 匯總容器檔案系統中的日誌

    • 在Ray容器中掛載一個empty-dir捲到/tmp/ray/,並將日誌卷掛載到執行日誌匯總工具(如Promtail)的Sidecar容器中。
  2. 將日誌重定向到STDERR

    • 設定環境變數RAY_LOG_TO_STDERR=1,將日誌輸出重定向到STDERR。
    • 在Kubernetes組態中,需在每個Ray群組規格的容器環境變數中新增相應設定:
      env:
      - name: "RAY_LOG_TO_STDERR"
        value: "1"
      
    • 之後可使用針對STDERR和STDOUT流的日誌匯總工具進行處理。

使用Ray叢集啟動器進行佈署

Ray叢集啟動器簡化了在任意雲端平台上佈署Ray叢集的流程,主要功能包括:

  • 使用雲端服務提供商的SDK組態新的例項或機器。
  • 執行Shell命令以根據提供的選項設定Ray。
  • 可選地執行自定義的設定命令,用於設定環境變數或安裝套件。
  • 初始化Ray叢集並佈署自動擴充套件程式。

組態您的Ray叢集

要執行Ray叢集,需在叢集組態檔案中指定資源需求。以下是一個最小化的叢集規格示例(cluster.yaml):

cluster_name: minimal

此組態檔案是啟動叢集的基礎,更多關於叢集YAML檔案的詳細資訊可參考官方檔案中的大型示例。

#### 內容解密:

上述組態展示瞭如何在Kubernetes環境中有效地佈署和管理Ray叢集。透過合理組態headGroupSpecworkerGroupSpecs以及相關引數,可以實作資源的最佳化利用。同時,日誌持久化和容器環境變數的組態確保了系統的可監控性和靈活性。Ray叢集啟動器的使用進一步簡化了跨雲端平台的佈署流程,降低了使用門檻並提升了維運效率。

使用 Ray Cluster Launcher 佈署雲端叢集

Ray Cluster Launcher 是一個強大的工具,能夠幫助使用者在各種雲端平台上佈署和管理 Ray 叢集。本章節將詳細介紹如何使用 Ray Cluster Launcher 在 AWS、GCP 和 Azure 等雲端提供商上佈署 Ray 叢集。

叢集組態

在佈署 Ray 叢集之前,需要建立一個叢集組態檔案,用於定義叢集的相關引數,例如叢集名稱、最大工作節點數、雲端提供商型別等。以下是一個範例組態檔案:

cluster_name: minimal
max_workers: 1
provider:
  type: aws
  region: us-west-2
  availability_zone: us-west-2a
auth:
  ssh_user: ubuntu

組態檔案解說:

  • cluster_name:定義叢集的唯一識別名稱。
  • max_workers:定義除了主節點外,可以啟動的最大工作節點數。
  • provider:定義雲端提供商的相關組態,包括型別、區域和可用區。
  • auth:定義如何與新啟動的節點進行身份驗證,包括 SSH 使用者名稱。

使用 Cluster Launcher CLI 佈署叢集

擁有叢集組態檔案後,可以使用 Ray Cluster Launcher CLI 來佈署指定的叢集。只需執行以下命令:

ray up cluster.yaml

命令解說:

  • ray up 命令會根據組態檔案與雲端提供商互動,啟動主節點並在該節點上執行適當的 Ray 服務或程式。
  • 該命令不會自動啟動所有指定的節點,它只會啟動一個「主」節點,並在該節點上執行 ray start --head 命令。
  • 之後,Ray 自動擴充套件程式會根據提供的叢集組態,在背景執行緒中啟動工作節點。

與 Ray 叢集互動

佈署叢集後,通常需要透過各種操作與叢集互動,例如在叢集上執行指令碼、傳輸檔案、檢視日誌等。Ray 提供了一個 CLI 用於與由 Ray Cluster Launcher 啟動的叢集進行互動。

示例命令:

  1. 執行指令碼:使用 ray job submit 命令在叢集上執行指令碼。

    # 在一個終端中:
    ray attach cluster.yaml -p 8265
    
    # 在另一個終端中:
    export RAY_ADDRESS=http://localhost:8265
    ray job submit --working-dir=. -- python script.py
    

    命令解說:

    • ray attach 命令用於連線到叢集並進行埠轉發。
    • ray job submit 命令用於在叢集上提交作業,包括傳輸本地檔案到叢集並執行指定的 Python 指令碼。
  2. 傳輸檔案:使用 ray rsync-down 命令將檔案從叢集傳輸回本地。

    ray rsync-down cluster.yaml /path/on/cluster/results.log ./results.log
    

    命令解說:

    • 該命令將叢集上的 results.log 檔案傳輸到本地當前目錄。

在不同雲端提供商上佈署 Ray 叢集

Ray 支援在多個主流雲端提供商上佈署叢集,包括 AWS、GCP 和 Azure。以下是針對不同雲端提供商的組態範例:

GCP 組態範例:

cluster_name: minimal
max_workers: 1
provider:
  type: gcp
  region: us-west1
  availability_zone: us-west1-a
  project_id: null # 全域唯一專案 ID
auth:
  ssh_user: ubuntu

Azure 組態範例:

cluster_name: minimal
max_workers: 1
provider:
  type: azure
  location: westus2
  resource_group: ray-cluster
auth:
  ssh_user: ubuntu
  ssh_private_key: ~/.ssh/id_rsa
  ssh_public_key: ~/.ssh/id_rsa.pub

自動擴充套件

Ray 的自動擴充套件功能可以根據工作負載的需求動態調整叢集規模,從而實作資源的最佳利用。自動擴充套件器會考慮使用者指定的硬限制、節點型別、當前資源使用情況等因素來決定是否新增或移除節點。

自動擴充套件邏輯:

  • 當工作節點閒置時間超過 idle_timeout_minutes 設定值時,將被移除。
  • 主節點永遠不會被移除,除非整個叢集被銷毀。
  • 自動擴充套件器使用簡單的 binpacking 演算法,將使用者需求封裝到可用的叢集資源中。

使用Ray AI Runtime的基礎

在閱讀了第1章關於Ray AIR的內容後,我們已經取得了很大的進步。除了瞭解Ray叢集的基礎知識和Ray核心API的基本知識之外,您還學習了Ray中可以用於AI工作負載的更高階別的函式庫,包括Ray RLlib、Tune、Train、Datasets和Serve。在本章中,我們將介紹Ray AIR的核心概念,以及如何使用它來構建和佈署常見的工作流程。

為什麼使用AIR?

使用Ray執行機器學習(ML)工作負載在過去幾年中不斷演進。Ray RLlib和Tune是第一批建立在Ray核心之上的函式庫。隨後,Ray Train、Serve和最近的Ray Datasets等元件也相繼出現。新增Ray AIR作為其他所有Ray ML函式庫的總稱,是與ML社群進行積極討論和徵求回饋的結果。Ray作為一個具有良好GPU支援和狀態化原語(Ray角色)的Python原生工具,是建立像AIR這樣的執行階段的理想選擇。

Ray AIR的主要優勢

  • 統一的工具包:為您的ML工作負載提供統一的工具包,支援多種第三方整合,用於模型訓練或存取自定義資料來源。
  • 易用性:隱藏底層抽象,提供直觀的API,靈感來自scikit-learn等工具的常見模式。
  • 適用於資料科學家和ML工程師:無論是資料科學家還是ML工程師,都可以使用AIR來構建和擴充套件端對端的實驗,或是整合到您的自定義ML平台中。
  • 無縫過渡:支援從筆記型電腦上的實驗到叢集上的生產工作流程的無縫過渡。

以範例介紹AIR的核心概念

AIR的設計哲學是讓您能夠在單一指令碼中處理ML工作負載,並由單一系統執行。讓我們透過一個詳細的使用範例來瞭解AIR及其關鍵概念。以下是我們要做的步驟:

  1. 載入乳腺癌資料集,並使用AIR進行預處理。
  2. 定義XGBoost模型來訓練分類別器。
  3. 設定Tuner來調整超引數。
  4. 儲存已訓練模型的檢查點。
  5. 使用AIR執行批次預測。
  6. 將預測器佈署為服務。

環境設定

請確保安裝以下依賴套件:

pip install "ray[air]==2.2.0" "xgboost-ray>=0.1.10" "xgboost>=1.6.2"
pip install "numpy>=1.19.5" "pandas>=1.3.5" "pyarrow>=6.0.1" "aiorwlock==1.3.0"

圖表說明

圖10-1總結了我們將在下面的範例中採取的步驟,以及我們將使用的AIR元件。 此圖示呈現了從資料載入到使用AIR進行推理的整個流程。

圖表翻譯: 圖10-1描述了使用AIR作為單一分散式系統,從資料載入到推理的完整流程。這個流程涵蓋了資料預處理、模型訓練、超引數調優、模型儲存、批次預測以及將預測器佈署為服務等關鍵步驟。

逐步實作

步驟1:載入資料集並預處理

# 載入資料集
from ray.data import Dataset
dataset = Dataset.read_csv("https://raw.githubusercontent.com/mwaskom/seaborn-data/master/titanic.csv")

# 資料預處理
from ray.data.preprocessors import SimpleImputer
imputer = SimpleImputer(columns=["age"], strategy="mean")
dataset = imputer.fit_transform(dataset)

內容解密:

這段程式碼首先從指定的CSV檔案中載入泰坦尼克號資料集。然後,使用SimpleImputer來填充age欄位中的缺失值,使用平均值策略進行填充。這是資料預處理的一個常見步驟,能夠確保模型訓練時不會因為缺失值而出現問題。

步驟2:定義XGBoost模型

# 定義XGBoost模型
from ray.train.xgboost import XGBoostTrainer
trainer = XGBoostTrainer(
    label_column="survived",
    num_boost_round=100,
    params={"objective": "binary:logistic"}
)

內容解密:

這裡定義了一個XGBoost訓練器,用於訓練一個二元分類別模型。label_column指定了目標變數為survivednum_boost_round設定了提升迭代的次數,params則定義了XGBoost模型的引數,包括目標函式為二元邏輯迴歸。