在 Kubernetes 環境中佈署 Ray 叢集後,需要有效地與叢集互動並執行 Ray 程式。本文將介紹三種主要互動方式:kubectl exec 直接與 head pod 互動執行命令;Ray Job Submission 伺服器提交指令碼執行;以及使用 Ray Client 在本地執行 Ray 工作負載。同時,文章也涵蓋了公開 KubeRay 服務的考量,並探討最佳的叢集組態策略,包括 headGroupSpec、workerGroupSpecs、rayStartParams 等關鍵引數的設定,以及資源分配、日誌記錄和持久化組態的最佳實踐。此外,文章也提供使用 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)])
內容解密:
import ray:匯入Ray函式庫。ray.init(address="auto"):自動檢測並連線到Ray叢集。print(ray.cluster_resources()):列印叢集的資源狀況。@ray.remote:定義一個可以在Ray叢集上遠端執行的函式。ray.get([test.remote() for i in range(12)]):遠端執行test函式12次並取得結果。
執行Ray程式的三種主要方法
- 使用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也是合理的選擇。
主要組態引數詳解
headGroupSpec與workerGroupSpecs
headGroupSpec定義了Ray叢集頭節點(Head Pod)的組態。workerGroupSpecs則用於定義工作節點(Worker Pod)的組態,可設定多個工作群組,每個群組擁有獨立的組態範本。replicas欄位決定了每個工作群組中應保持的Worker Pod數量。
rayStartParams
- 這是一個字串對字串的對映,用於傳遞給Ray Pod的
ray start入口點。 - 特別需要注意的引數包括
num-cpus和num-gpus:num-cpus:告知Ray排程器該Pod可用的CPU資源數量,可透過Kubernetes資源限制自動偵測,但也可手動覆寫。例如,設定num-cpus:"0"可防止具有非零CPU需求的工作負載被排程到頭節點上。num-gpus:指定可用的GPU數量,目前需手動設定以支援GPU工作負載。
- 這是一個字串對字串的對映,用於傳遞給Ray Pod的
template與resources
template欄位是Kubernetes Pod範本,用於定義Head或Worker群組中Pod的具體組態。- 必須為每個群組規格指定容器CPU和記憶體請求及限制,對於GPU工作負載,還需設定GPU限制(如
nvidia.com/gpu: 1)。
nodeSelector與tolerations
- 這兩個欄位控制了Worker群組中Ray Pod的排程行為,決定了Pod可被排程到哪些Kubernetes節點上。
- KubeRay運算元在Pod層級運作,對底層Kubernetes節點的組態不做干預,需由叢集管理員負責。
日誌記錄與持久化組態
Ray叢集的程式預設將日誌寫入Pod中的/tmp/ray/session_latest/logs目錄,並可在Ray儀錶板中檢視。為了在Pod生命週期結束後仍保留日誌,可採用以下方法:
匯總容器檔案系統中的日誌
- 在Ray容器中掛載一個
empty-dir捲到/tmp/ray/,並將日誌卷掛載到執行日誌匯總工具(如Promtail)的Sidecar容器中。
- 在Ray容器中掛載一個
將日誌重定向到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叢集。透過合理組態headGroupSpec、workerGroupSpecs以及相關引數,可以實作資源的最佳化利用。同時,日誌持久化和容器環境變數的組態確保了系統的可監控性和靈活性。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 啟動的叢集進行互動。
示例命令:
執行指令碼:使用
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 指令碼。
傳輸檔案:使用
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及其關鍵概念。以下是我們要做的步驟:
- 載入乳腺癌資料集,並使用AIR進行預處理。
- 定義XGBoost模型來訓練分類別器。
- 設定Tuner來調整超引數。
- 儲存已訓練模型的檢查點。
- 使用AIR執行批次預測。
- 將預測器佈署為服務。
環境設定
請確保安裝以下依賴套件:
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指定了目標變數為survived,num_boost_round設定了提升迭代的次數,params則定義了XGBoost模型的引數,包括目標函式為二元邏輯迴歸。