KubernetesのNamespaceごとに構築したRay Clusterへの参照をアクセス時のパスで切り替える

::: note info
これは [ZOZO Advent Calendar 2024](https://qiita.com/advent-calendar/2024/zozo) カレンダー Vol.9 の 3日目の記事です。
:::

# はじめに
昨日は[GKE上に構成したRay Clusterに内部Load Balancer経由でプライベートアクセスする](https://qiita.com/okmtz/private/2f7bfb0ee48445fc69ba)というタイトルで、Ray Clusterに関する記事を投稿しました。  
昨日に引き続き、本日もRay Cluster関連の投稿になります。Ray Clusterについては1日目の記事（[GKE上に構成したRay Clusterに外部Load Balancer経由でアクセスする](https://qiita.com/okmtz/private/09b6b7be9d9bcaf1df9b)）で簡単に説明しているため、ご参照ください。

本記事では、KubernetesのNamespaceごとにRay Clusterを構築し、Load Balancerのアクセス時のパスにより、参照するRay Clusterを切り替え可能にする構成をご紹介します。

# NamespaceごとにRay Clusterを作成
RayClusterオブジェクトの作成自体は、単一のNamespaceを利用する場合と違いありません。一方で、リクエストパスごとに異なるRay Clusterにアクセスするためには構成に少し工夫が必要です。

[GKE上に構成したRay Clusterに外部Load Balancer経由でアクセスする](https://qiita.com/okmtz/private/09b6b7be9d9bcaf1df9b)では、Ingress単体ではパスごとに異なるRay Clusterへのアクセスの振り分けができないと記載しておりました。  
Istioを導入することで、リクエストパスのrewriteを利用できるようになります。これによりRay ClusterのHead Nodeへのリクエストで404エラーが発生する問題を回避できます。

Istioの導入については割愛するため前回記事（[GKE上に構成したRay Clusterに内部Load Balancer経由でプライベートアクセスする](https://qiita.com/okmtz/private/2f7bfb0ee48445fc69ba)）をご参照ください。

## Virtual Serviceの作成
リクエストパスに基づいたルーティングができるよう、各NamespaceごとにVirtual Serviceを作成してください。
パスベースのルーティング設定以外の箇所はNamespace間で共通になるため、Kustomizeでパッチを当てるなどおすすめします。

```base/service.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: raycluster-autoscaler
  labels:
    app.kubernetes.io/instance: raycluster-autoscaler
spec:
  gateways:
  - asm-ingress/asm-ingressgateway
  hosts:
  - <external-host>
  - <internal-host>
```

```namespace-a/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: namespace-a
resources:
- ../ray-cluster.yaml
- ../service.yaml

patches: 
  - path: ./ray-cluster.yaml
  - path: ./service-patch.yaml
```

パスベースのルーティングができるよう、`spec.http.match.uri.prefix`フィールドを指定してください。  
また`spec.http.route.rewrite.uri`フィールドを`/`で指定してください。

```namespace-a/service-patch.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: raycluster-autoscaler
  labels:
    app.kubernetes.io/instance: raycluster-autoscaler
spec:
  http:
  - route:
    - destination:
        host: raycluster-autoscaler-head-svc
        port:
          number: 8265
      weight: 100
    rewrite:
      uri: /
    match:
      - uri:
          prefix: /namespace-a/
```

# NamespaceごとのRay Clusterへのアクセス
各Namespaceごとに作成したVirtual Serviceに記載のパスルーティングに一致する形式でRay Clusterにアクセスすることで、パスに対応するRay Clusterへリクエストできます。

例えば、`mlops` Namespaceと`mlops-2` NamespaceのそれぞれのNamespaceに対応するRay Clusterを構築します。Virtual ServiceのPathでそれぞれ`mlops`・`mlops-2`を指定した場合、次のようにそれぞれ異なるRay ClusterのDashboardにアクセスできます。

`/mlops/`にアクセスする場合 → `https://<sample-ray-cluster-host>/mlops/`
![スクリーンショット 2024-11-24 17.32.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576866/bb111a2d-5429-0629-a33a-3b0f14592968.png)

`/mlops-2`にアクセスする場合 → `https://<sample-ray-cluster-host>/mlops-2/`
![スクリーンショット 2024-11-24 17.38.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576866/2dfc2f31-7d49-2321-ff65-ad99da134910.png)

小さくて恐縮ですが、Recent JobsがそれぞれのDashboardで異なっており、別々のDashboardにルーティングできていることがわかります。

CLIでRayのJobをSubmitする場合も同様で、次のようにパスを指定することで異なるRay ClusterにJobをSubmit可能です。

例：`RAY_ADDRESS="https://<sample-ray-cluster-host>/mlops/"`