OpenShift AI - Jupyter Notebook


#### OpenShift AI

Red Hat® OpenShift® AI とは、柔軟でスケーラブルな人工知能 (AI) および機械学習 (ML) プラットフォームです。このプラットフォームにより、企業はハイブリッドクラウド環境全体で AI 対応アプリケーションを大規模に作成および提供できるようになります。

OpenShift AI はオープンソース・テクノロジーを使用して構築されており、実験、モデル提供、革新的なアプリケーションの提供のための、信頼性と一貫性に優れた運用機能を提供します。

https://www.redhat.com/ja/technologies/cloud-computing/openshift/openshift-ai

#### Jupyter Notebook
ここでは、OpenShift AI 2.9.1 / Red Hat OpenShift on IBM Cloud (ROKS) 4.14 の環境で、Jupyter Notebook の実装を確認します。

OpenShift AI 導入完了時点では、以下のように `Jupyter Notebook` のみが使用可能になっています。 (Applications -> Enabled)

![2-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128125/e0ddebdf-8e62-5878-19d1-90b9e63b6721.png)

:::note info
以下にあるとおり、この画面から実行する Jupyter Notebook は `one-off`（単独で実行する 1 回限り）の使用を想定したものであり、継続使用、複数 Notebook の併用等が必要な場合は、`Data Science Project` から起動する必要があります。なお、`one-off` 想定ではあるものの PVC の割り当てが可能なため、PVC (PV) を削除しない限りにおいては、ユーザ・データの保存が可能です。
:::

https://docs.redhat.com/en/documentation/red_hat_openshift_ai_self-managed/2.9/html-single/openshift_ai_tutorial_-_fraud_detection_example/index#setting-up-your-data-science-project

> Note that you can start a Jupyter notebook from here, but it would be a one-off notebook run in isolation. To implement a data science workflow, you must create a data science project. Projects allow you and your team to organize and collaborate on resources within separated namespaces. From a project you can create multiple workbenches, each with their own Jupyter notebook environment, and each with their own data connections and cluster storage. In addition, the workbenches can share models and data with pipelines and model servers. 

Jupyter Notebook を起動してみます。
機能を確認するために、Settings -> Cluster settings にある `PVC size` を Default の `20GiB` から `30GiB` に変更します。

![101.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128125/30dfa0c3-8021-22cd-1eb6-a5175460a24a.png)

Applications -> Enabled から Jupyter Notebook を選択し、以下の設定で起動してみます。

![102.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128125/f0b7b5af-6159-fdfb-33dd-eb25d717f309.png)

Pop Up が表示され、起動が完了すると以下のようになります。

![104.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128125/87e8cbe6-19e6-926e-2545-2be0f5f052d5.png)

Pop Up 表示にしたがって操作すると、以下のような画面が表示されます。

![105.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128125/be3da53e-a014-f5ef-1c5a-db8edf048582.png)

`Notebook`、`Console` にあるアイコンは、それぞれ Jupyter Notebook、Python Prompt を起動します。`Other` にある `Terminal` は、Jupyter Notebook Pod の Shell を起動します。これは、以下のように `oc exec` で Pod に Login したものと同等です。
```shell
$ oc exec -n rhods-notebooks jupyter-nb-xyz-23abdedib-40ms-349db-12yaq-0 -c jupyter-nb-xyz-23abdedib-40ms-349db-12yaq -ti -- sh
(app-root) sh-5.1$
```

Pod は `rhods-notebooks` Project に配置され、Computing Resource を確認すると、指定したとおりになっていることが分かります。
```shell
$ oc get pod -n rhods-notebooks -o custom-columns-file=POD_CUSTOM.txt
NAME                                          NODE         OWNER_KIND    CONTAINERS                                              CPU_LIMITS   MEM_LIMITS   CPU_REQUESTS   MEM_REQUESTS
jupyter-nb-xyz-23abdedib-40ms-349db-12yaq-0   11.222.3.4   StatefulSet   jupyter-nb-xyz-23abdedib-40ms-349db-12yaq,oauth-proxy   2,100m       8Gi,64Mi     1,100m         8Gi,64Mi

$ oc get pvc -n rhods-notebooks
NAME                                                      STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS                 AGE
jupyterhub-nb-xyz-23abdedib-40ms-349db-12yaq-pvc          Bound    pvc-a7582e2b-aa9a-45d6-ba00-a07cf2cfd35b   30Gi       RWO            ibmc-vpc-block-10iops-tier   40m
```

更に確認すると、Pod の Controller は StatefulSet で、その Owner は `Notebook` CR であることが分かります。

```shell
$ oc get notebook -n rhods-notebooks
NAME                                               AGE
jupyter-nb-xyz-23abdedib-40ms-349db-12yaq          4h15m
```
```shell
$ oc explain Notebook
GROUP:      kubeflow.org
KIND:       Notebook
VERSION:    v1

DESCRIPTION:
    <empty>
FIELDS:
  apiVersion    <string>
    APIVersion defines the versioned schema of this representation of an object.
    Servers should convert recognized schemas to the latest internal value, and
    may reject unrecognized values. More info:
    https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources

  kind  <string>
    Kind is a string value representing the REST resource this object
    represents. Servers may infer this from the endpoint the client submits
    requests to. Cannot be updated. In CamelCase. More info:
    https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds

  metadata      <ObjectMeta>
    Standard object's metadata. More info:
    https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata

  spec  <Object>
    <no description>

  status        <Object>
    <no description>
```

https://www.kubeflow.org/docs/components/notebooks/api-reference/notebook-v1/

選択した `Notebook image` や `Deployment size` は、annotation で確認できるようです。
```shell
$ oc -o json get notebook jupyter-nb-xyz-23abdedib-40ms-349db-12yaq | jq -r '.metadata.annotations'
{
  "notebooks.opendatahub.io/inject-oauth": "true",
  "notebooks.opendatahub.io/last-image-selection": "s2i-minimal-notebook:2024.1",
  "notebooks.opendatahub.io/last-size-selection": "Small",
  "notebooks.opendatahub.io/oauth-logout-url": "https://rhods-dashboard-redhat-ods-applications/home",
  "opendatahub.io/accelerator-name": "",
  "opendatahub.io/username": "********"
}
```
Pod Template と思われる箇所で Volume を確認すると、PVC は `/opt/app-root/src` に Mount されていることが分かります。
```shell
$ oc -o json get notebook jupyter-nb-xyz-23abdedib-40ms-349db-12yaq | jq -rc '.spec.template.spec.volumes[]'
{"name":"jupyterhub-nb-xyz-23abdedib-40ms-349db-12yaq-pvc","persistentVolumeClaim":{"claimName":"jupyterhub-nb-xyz-23abdedib-40ms-349db-12yaq-pvc"}}
{"emptyDir":{"medium":"Memory"},"name":"shm"}
{"configMap":{"items":[{"key":"ca-bundle.crt","path":"ca-bundle.crt"}],"name":"workbench-trusted-ca-bundle","optional":true},"name":"trusted-ca"}
{"name":"oauth-config","secret":{"defaultMode":420,"secretName":"jupyter-nb-xyz-23abdedib-40ms-349db-12yaq-oauth-config"}}
{"name":"tls-certificates","secret":{"defaultMode":420,"secretName":"jupyter-nb-xyz-23abdedib-40ms-349db-12yaq-tls"}}

$ oc -o json get notebook jupyter-nb-xyz-23abdedib-40ms-349db-12yaq | jq -rc '.spec.template.spec.containers[] | .name, .volumeMounts[]'
jupyter-nb-xyz-23abdedib-40ms-349db-12yaq
{"mountPath":"/opt/app-root/src","name":"jupyterhub-nb-xyz-23abdedib-40ms-349db-12yaq-pvc"}
{"mountPath":"/dev/shm","name":"shm"}
{"mountPath":"/etc/pki/tls/custom-certs/ca-bundle.crt","name":"trusted-ca","readOnly":true,"subPath":"ca-bundle.crt"}
oauth-proxy
{"mountPath":"/etc/oauth/config","name":"oauth-config"}
{"mountPath":"/etc/tls/private","name":"tls-certificates"}
```
`Terminal` を使用すると、Pod 内部の状況が分かります。
```shell
(app-root) sh-5.1$ lsblk -a
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
vda    253:0    0  101G  0 disk
tqvda1 253:1    0    1G  0 part
mqvda2 253:2    0   99G  0 part /etc/pki/tls/custom-certs/ca-bundle.crt
                                /run/secrets
                                /dev/termination-log
                                /etc/hosts
                                /etc/passwd
                                /run/.containerenv
                                /etc/hostname
                                /etc/resolv.conf
vdb    253:16   0  392K  0 disk
vdc    253:32   0   44K  0 disk
vdd    253:48   0   30G  0 disk /opt/app-root/src
vde    253:64   0   20G  0 disk

(app-root) sh-5.1$ df
Filesystem     1K-blocks     Used Available Use% Mounted on
overlay        102112528 66334508  30571288  69% /
tmpfs              65536        0     65536   0% /dev
tmpfs           32966476        0  32966476   0% /sys/fs/cgroup
/dev/vda2      102112528 66334508  30571288  69% /etc/hosts
tmpfs            8454144        0   8454144   0% /dev/shm
/dev/vdd        30787492      204  30770904   1% /opt/app-root/src
tmpfs            8454144       24   8454120   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs           32966476        0  32966476   0% /proc/asound
tmpfs           32966476        0  32966476   0% /proc/acpi
tmpfs           32966476        0  32966476   0% /proc/scsi
tmpfs           32966476        0  32966476   0% /sys/firmware
```

:::note info
先述の `Notebook` CR を削除すると StatefulSet 等の関連 Resource は全て削除されますが、PVC は削除されないようです。
:::

なお、使用する Container Image は以下のようになっています。
```shell
$ oc -o json get notebook jupyter-nb-xyz-23abdedib-40ms-349db-12yaq | jq -r '.spec.template.spec.containers[] | .name, .image'
jupyter-nb-xyz-23abdedib-40ms-349db-12yaq
image-registry.openshift-image-registry.svc:5000/redhat-ods-applications/s2i-minimal-notebook:2024.1
oauth-proxy
registry.redhat.io/openshift4/ose-oauth-proxy@sha256:4bef31eb993feb6f1096b51b4876c65a6fb1f4401fee97fa4f4542b6b7c9bc46
```