Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Python API server client #1561

Merged
merged 28 commits into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
8dc50ab
Added Python API server client
blublinsky Oct 24, 2023
4532036
updated _init_.py
blublinsky Oct 25, 2023
d7e4505
Add setup tools for build
blublinsky Oct 25, 2023
4a511d9
Add setup tools for build
blublinsky Oct 25, 2023
858cb3e
Add setup tools for build
blublinsky Oct 25, 2023
aeef883
Add setup tools for build
blublinsky Oct 25, 2023
ac9ff0d
package restructuring and local module build
blublinsky Oct 25, 2023
d71c134
more cleanup
blublinsky Oct 25, 2023
99344ef
more testing
blublinsky Oct 26, 2023
11e022d
more testing
blublinsky Oct 26, 2023
aab4009
more testing
blublinsky Oct 26, 2023
503eb85
Merge branch 'master' into apiserver_python
blublinsky Oct 31, 2023
75b6674
Added Python API server client
blublinsky Oct 24, 2023
e9aab6b
updated _init_.py
blublinsky Oct 25, 2023
47be601
Add setup tools for build
blublinsky Oct 25, 2023
ad957b0
Add setup tools for build
blublinsky Oct 25, 2023
91b0428
Add setup tools for build
blublinsky Oct 25, 2023
b20fe22
Add setup tools for build
blublinsky Oct 25, 2023
ddcd920
package restructuring and local module build
blublinsky Oct 25, 2023
5bdbbaa
more cleanup
blublinsky Oct 25, 2023
74882db
more testing
blublinsky Oct 26, 2023
f2be3f6
more testing
blublinsky Oct 26, 2023
f1ba2d1
more testing
blublinsky Oct 26, 2023
e388e58
rebased and fixed APIs to use v1
blublinsky Oct 31, 2023
0654efe
Merge remote-tracking branch 'origin/apiserver_python' into apiserver…
blublinsky Oct 31, 2023
8b1456c
rebased and fixed APIs to use v1
blublinsky Oct 31, 2023
0df8186
rebased and fixed APIs to use v1
blublinsky Oct 31, 2023
a1c097f
rebased and fixed APIs to use v1
blublinsky Nov 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 47 additions & 61 deletions apiserver/Volumes.md
Original file line number Diff line number Diff line change
@@ -1,102 +1,93 @@
# Volumes support for Ray cluster by the API server

API server allows to specify multiple types of volumes mounted to the Ray pods (nodes). These include:
[hostPath](https://kubernetes.io/docs/concepts/storage/volumes/#hostpath),
[hostPath](https://kubernetes.io/docs/concepts/storage/volumes/#hostpath),
[PVC](https://kubernetes.io/docs/concepts/storage/persistent-volumes/),
[ephemeral](https://kubernetes.io/docs/concepts/storage/ephemeral-volumes/),
[config maps](https://kubernetes.io/docs/concepts/storage/volumes/#configmap),
[secrets](https://kubernetes.io/docs/concepts/storage/volumes/#secret),
and [empty dir](https://kubernetes.io/docs/concepts/storage/volumes/#emptydir).
Multiple volumes of different type can be mounted to both head and worker nodes, by defining a volume array for them

Multiple volumes of different type can be mounted to both head and worker nodes, by defining a volume array for them

## HostPath volumes

A hostPath volume mounts a file or directory from the host node's filesystem into your Pod. This is not something that
A hostPath volume mounts a file or directory from the host node's filesystem into your Pod. This is not something that
most Pods will need, but it offers a powerful escape hatch for some applications.

For example, some uses for a hostPath are:

* running a container that needs access to Docker internals; use a hostPath of /var/lib/docker
* running cAdvisor in a container; use a hostPath of /sys
* allowing a Pod to specify whether a given hostPath should exist prior to the Pod running, whether it should be
created, and what it should exist as
* allowing a Pod to specify whether a given hostPath should exist prior to the Pod running, whether it should be created, and what it should exist as

The code below gives an example of hostPath volume definition:

````
```json
{
"name": "hostPath", # unique name
"source": "/tmp", # data location on host
"mountPath": "/tmp/hostPath", # mounting path
"volumeType": 1, # volume type - host path
"hostPathType": 0, # host path type - directory
"mountPropagationMode": 1 # mount propagation - host to container
"name": "hostPath", # unique name
"source": "/tmp", # data location on host
"mountPath": "/tmp/hostPath", # mounting path
"volumeType": 1, # volume type - host path
"hostPathType": 0, # host path type - directory
"mountPropagationMode": 1 # mount propagation - host to container
}
````
```

## PVC volumes

A Persistent Volume Claim (PVC) is a request for storage by a user. It is similar to a Pod. Pods consume node resources
and PVCs consume PV resources. Pods can request specific levels of resources (CPU and Memory). Claims can request
A Persistent Volume Claim (PVC) is a request for storage by a user. It is similar to a Pod. Pods consume node resources and PVCs consume PV resources. Pods can request specific levels of resources (CPU and Memory). Claims can request
specific size and access modes (e.g., they can be mounted `ReadWriteOnce`, `ReadOnlyMany` or `ReadWriteMany`).

The caveat of using PVC volumes is that the same PVC is mounted to all nodes. As a result only PVCs with access
mode `ReadOnlyMany` can be used in this case.

The code below gives an example of PVC volume definition:

````
```json
{
"name": "pvc", # unique name
"mountPath": "/tmp/pvc", # mounting path
"volumeType": 0, # volume type - PVC
"mountPropagationMode": 2, # mount propagation mode - bidirectional
"readOnly": false # read only
"name": "pvc", # unique name
"mountPath": "/tmp/pvc", # mounting path
"source": "claim", # claim name
"volumeType": 0, # volume type - PVC
"mountPropagationMode": 2, # mount propagation mode - bidirectional
"readOnly": false # read only
}
````
```

## Ephemeral volumes

Some application need additional storage but don't care whether that data is stored persistently across restarts. For
example, caching services are often limited by memory size and can move infrequently used data into storage that is
slower than memory with little impact on overall performance. Ephemeral volumes are designed for these use cases.
Because volumes follow the Pod's lifetime and get created and deleted along with the Pod, Pods can be stopped and
restarted without being limited to where some persistent volume is available.
Some application need additional storage but don't care whether that data is stored persistently across restarts. For example, caching services are often limited by memory size and can move infrequently used data into storage that is slower than memory with little impact on overall performance. Ephemeral volumes are designed for these use cases.

Because volumes follow the Pod's lifetime and get created and deleted along with the Pod, Pods can be stopped and restarted without being limited to where some persistent volume is available.

Although there are several option of ephemeral volumes, here we are using generic ephemeral volumes, which can be
provided by all storage drivers that also support persistent volumes. Generic ephemeral volumes are similar to emptyDir
volumes in the sense that they provide a per-pod directory for scratch data that is usually empty after provisioning.
But they may also have additional features:
Although there are several option of ephemeral volumes, here we are using generic ephemeral volumes, which can be provided by all storage drivers that also support persistent volumes. Generic ephemeral volumes are similar to emptyDir volumes in the sense that they provide a per-pod directory for scratch data that is usually empty after provisioning. But they may also have additional features:

* Storage can be local or network-attached.
* Volumes can have a fixed size that Pods are not able to exceed.

The code below gives an example of ephemeral volume definition:

````
```json
{
"name": "ephemeral", # unique name
"mountPath": "/tmp/ephemeral" # mounting path,
"mountPropagationMode": 0, # mount propagation mode - None
"volumeType": 2, # volume type - ephemeral
"storage": "5Gi", # disk size
"storageClass": "default" # storage class - optional
"accessMode": 0 # access mode RWO - optional
"name": "ephemeral", # unique name
"mountPath": "/tmp/ephemeral" # mounting path,
"mountPropagationMode": 0, # mount propagation mode - None
"volumeType": 2, # volume type - ephemeral
"storage": "5Gi", # disk size
"storageClass": "default", # storage class - optional
"accessMode": 0 # access mode RWO - optional
}
````
```

## Config map volumes

A ConfigMap provides a way to inject configuration data into pods. The data stored in a ConfigMap can be referenced in
a volume of type configMap and then consumed by containerized applications running in a pod.
A ConfigMap provides a way to inject configuration data into pods. The data stored in a ConfigMap can be referenced in a volume of type configMap and then consumed by containerized applications running in a pod.

When referencing a ConfigMap, you provide the name of the ConfigMap in the volume. You can customize the path to use
for a specific entry in the ConfigMap.
When referencing a ConfigMap, you provide the name of the ConfigMap in the volume. You can customize the path to use for a specific entry in the ConfigMap.

The code below gives an example of config map volume definition:

````
```json
{
"name":"code-sample", # Unique name
"mountPath":"/home/ray/samples", # mounting path
Expand All @@ -106,17 +97,15 @@ The code below gives an example of config map volume definition:
"sample_code.py":"sample_code.py"
}
}
````
```

## Secret volumes

A secret volume is used to pass sensitive information, such as passwords, to Pods. You can store secrets in the
Kubernetes API and mount them as files for use by pods without coupling to Kubernetes directly. Secret volumes are
backed by tmpfs (a RAM-backed filesystem) so they are never written to non-volatile storage.
A secret volume is used to pass sensitive information, such as passwords, to Pods. You can store secrets in the Kubernetes API and mount them as files for use by pods without coupling to Kubernetes directly. Secret volumes are backed by tmpfs (a RAM-backed filesystem) so they are never written to non-volatile storage.

The code below gives an example of secret volume definition:

````
```json
{
"name":"important-secret", # Unique name
"mountPath":"/home/ray/sensitive", # mounting path
Expand All @@ -126,22 +115,19 @@ The code below gives an example of secret volume definition:
"subPath": "password"
}
}
````
```

## Emptydir volumes

An emptyDir volume is first created when a Pod is assigned to a node, and exists as long as that Pod is running on
that node. As the name says, the emptyDir volume is initially empty. All containers in the Pod can read and write the
same files in the emptyDir volume, though that volume can be mounted at the same or different paths in each container.
When a Pod is removed from a node for any reason, the data in the emptyDir is deleted permanently.
An emptyDir volume is first created when a Pod is assigned to a node, and exists as long as that Pod is running on that node. As the name says, the emptyDir volume is initially empty. All containers in the Pod can read and write the same files in the emptyDir volume, though that volume can be mounted at the same or different paths in each container. When a Pod is removed from a node for any reason, the data in the emptyDir is deleted permanently.

The code below gives an example of empydir volume definition:

````
```json
{
"name": "emptyDir", # unique name
"mountPath": "/tmp/emptydir" # mounting path,
"volumeType": 5, # vlume type - ephemeral
"storage": "5Gi", # max storage size - optional
"name": "emptyDir", # unique name
"mountPath": "/tmp/emptydir" # mounting path,
"volumeType": 5, # vlume type - ephemeral
"storage": "5Gi", # max storage size - optional
}
````
1 change: 1 addition & 0 deletions apiserver/pkg/model/volumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ func PopulateVolumes(podTemplate *v1.PodTemplateSpec) []*api.Volume {
MountPath: mount.MountPath,
MountPropagationMode: GetVolumeMountPropagation(mount),
VolumeType: api.Volume_PERSISTENT_VOLUME_CLAIM,
Source: vol.VolumeSource.PersistentVolumeClaim.ClaimName,
ReadOnly: vol.VolumeSource.PersistentVolumeClaim.ReadOnly,
})
continue
Expand Down
3 changes: 2 additions & 1 deletion apiserver/pkg/model/volumes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ var podTemplateTest = v1.PodTemplateSpec{
Name: "pvc",
VolumeSource: v1.VolumeSource{
PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
ClaimName: "pvc",
blublinsky marked this conversation as resolved.
Show resolved Hide resolved
ClaimName: "pvcclaim",
ReadOnly: false,
},
},
Expand Down Expand Up @@ -145,6 +145,7 @@ var expectedVolumes = []*api.Volume{
{
Name: "pvc",
MountPath: "/tmp/pvc",
Source: "pvcclaim",
VolumeType: api.Volume_PERSISTENT_VOLUME_CLAIM,
MountPropagationMode: api.Volume_BIDIRECTIONAL,
ReadOnly: false,
Expand Down
2 changes: 1 addition & 1 deletion apiserver/pkg/util/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,7 @@ func buildVols(apiVolumes []*api.Volume) ([]v1.Volume, error) {
Name: rayVol.Name,
VolumeSource: v1.VolumeSource{
PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
ClaimName: rayVol.Name,
ClaimName: rayVol.Source,
ReadOnly: rayVol.ReadOnly,
},
},
Expand Down
3 changes: 2 additions & 1 deletion apiserver/pkg/util/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ var testFileVolume = &api.Volume{
var testPVCVolume = &api.Volume{
Name: "test-pvc",
VolumeType: api.Volume_PERSISTENT_VOLUME_CLAIM,
Source: "my-pvc",
MountPath: "/pvc/dir",
ReadOnly: true,
}
Expand Down Expand Up @@ -261,7 +262,7 @@ func TestBuildVolumes(t *testing.T) {
Name: testPVCVolume.Name,
VolumeSource: v1.VolumeSource{
PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
ClaimName: testPVCVolume.Name,
ClaimName: testPVCVolume.Source,
ReadOnly: testPVCVolume.ReadOnly,
},
},
Expand Down
4 changes: 2 additions & 2 deletions apiserver/test/cluster/cluster/cluster
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ curl -X POST 'localhost:8888/apis/v1alpha2/namespaces/default/clusters' \
"clusterSpec": {
"headGroupSpec": {
"computeTemplate": "default-template",
"image": "rayproject/ray:2.6.3-py310",
"image": "rayproject/ray:2.7.0-py310",
"serviceType": "NodePort",
"rayStartParams": {
"dashboard-host": "0.0.0.0",
Expand All @@ -27,7 +27,7 @@ curl -X POST 'localhost:8888/apis/v1alpha2/namespaces/default/clusters' \
{
"groupName": "small-wg",
"computeTemplate": "default-template",
"image": "rayproject/ray:2.6.3-py310",
"image": "rayproject/ray:2.7.0-py310",
"replicas": 1,
"minReplicas": 0,
"maxReplicas": 5,
Expand Down
Empty file added clients/__init__.py
blublinsky marked this conversation as resolved.
Show resolved Hide resolved
Empty file.
11 changes: 11 additions & 0 deletions clients/python-apiserver-client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Python client for KubeRay API server

This Python client is currently only supporting Ray cluster mangement through usage of the `API server` Ray API. It implements all of the current functionality of the API server (and the operator) and provide pythonic APIs to the capabilities.
blublinsky marked this conversation as resolved.
Show resolved Hide resolved

The package supports well documented in the code Python objects that can be used to build and recieve payloads for creation, listing and delition of [template](https://ray-project.github.io/kuberay/components/apiserver/#compute-template) and Ray clusters.
blublinsky marked this conversation as resolved.
Show resolved Hide resolved

The main class of the package is [KubeRayAPIs](python_client/kuberay_apis.py) that implements all of the functionality. It leverages [templates](python_client/params/templates.py) and [cluster](python_client/params/cluster.py) definitions, allowing to specify all required parameters as straight Python classes. Additional (intermediate) definitons are provided (see [environment variables](python_client/params/environmentvariables.py), [volumes](python_client/params/volumes.py), [head group](python_client/params/headnode.py) and [worker group](python_client/params/workernode.py))

Test files [parameters_test](api_params_test.py) and [api_test](kuberay_api_test.py) exersize the packeage functionality and can also be used as a guide for API usage.

Note that [api_test](kuberay_api_test.py) requires creation of the additional [configmap](../../apiserver/test/job/code.yaml) in the default namespace
Empty file.
Loading