Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions guidebooks/ml/jupyterlab/start/examples/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.ipynb_checkpoints/
__pycache__/
219 changes: 219 additions & 0 deletions guidebooks/ml/jupyterlab/start/examples/example.ipynb

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions guidebooks/ml/jupyterlab/start/examples/mymodule.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""
Module function
"""

def say_hi():
print("Hi from '%s'" % (__name__))
21 changes: 21 additions & 0 deletions guidebooks/ml/jupyterlab/start/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Run a JupyterLab Server

[JupyterLab](https://jupyterlab.readthedocs.io/en/stable/index.html) is an open source platform to manage Jupyter notebooks
from a web console with ease. Jupyter notebooks are interactive Python sessions that allow users to build Python scripts
in a *comparmentalized* way, with the data living throughout the notebook execution.

=== "Run Locally"
Start a JupyterLab server on your computer
--8<-- "./local"

=== "Run on a Kubernetes Cluster"
Start a JupyterLab server on a Kubernetes cluster
--8<-- "./kubernetes"

=== "Shut down a Kubernetes Cluster"
Stop a Kubernetes cluster that maybe running a Jupyter server
:import{ml/ray/stop/kubernetes}

=== "Shut down a JupyterLab server"
Stop a JupyterLab server
:import{ml/jupyterlab/stop/kubernetes}
10 changes: 10 additions & 0 deletions guidebooks/ml/jupyterlab/start/kubernetes/chart/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: v2
name: jupyterlab
description: A Helm chart for deployments of JupyterLab on Kubernetes.
type: application

# Chart version
version: 0.1.0

# JupyterLab version
appVersion: "latest"
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.clusterName }}-jupyterlab
labels:
app: jupyterlab-deployment
spec:
replicas: 1
selector:
matchLabels:
app: jupyterlab-pod
template:
metadata:
labels:
app: jupyterlab-pod
spec:
restartPolicy: Always
containers:
- name: jupyterlab
image: {{ .Values.rayImage }}
command: ["/bin/bash", "-c", "--"]
args: ["conda install -c conda-forge vim; pip install jupyterlab jupyterlab-vim; ray start --address={{ .Values.clusterName }}-ray-head:{{ .Values.rayHeadPort }}; sleep infinity;"]
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8888
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: v1
kind: Service
metadata:
name: {{ .Values.clusterName }}-jupyterlab
labels:
app: jupyterlab-deployment
spec:
ports:
- port: 8888
protocol: TCP
selector:
app: jupyterlab-pod
3 changes: 3 additions & 0 deletions guidebooks/ml/jupyterlab/start/kubernetes/chart/values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
clusterName: mycluster
rayHeadPort: 6379
rayImage: rayproject/ray:1.13.1-py37
6 changes: 6 additions & 0 deletions guidebooks/ml/jupyterlab/start/kubernetes/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
imports:
- ./ray-server
- ./jupyter-server
---

24 changes: 24 additions & 0 deletions guidebooks/ml/jupyterlab/start/kubernetes/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#
# Helm deployment of Ray server with JupyterLab
#

GITHUB=github.com
ORG=${JUPYTERLAB_CHART_ORG-guidebooks}
REPO=${JUPYTERLAB_CHART_REPO-store}
BRANCH=${JUPYTERLAB_CHART_BRANCH}
SUBDIR=${JUPYTERLAB_CHART_SUBDIR-guidebooks/ml/jupyterlab/start/kubernetes/chart}

JUPYTERLAB_CLONE_TEMPDIR=$(mktemp -d)

if [ -n "$BRANCH" ]; then
BRANCH_OPT="-b ${BRANCH}"
fi

git clone --filter=tree:0 --depth 1 --sparse https://${GITHUB}/${ORG}/${REPO}.git ${BRANCH_OPT} ${JUPYTERLAB_CLONE_TEMPDIR} && \
cd ${JUPYTERLAB_CLONE_TEMPDIR} && \
git sparse-checkout init --cone && \
git sparse-checkout set ${SUBDIR}

helm --kube-context ${KUBE_CONTEXT} --namespace ${KUBE_NS} \
upgrade --install --wait \
jupyterlab ${JUPYTERLAB_CLONE_TEMPDIR}/${SUBDIR}
79 changes: 79 additions & 0 deletions guidebooks/ml/jupyterlab/start/kubernetes/jupyter-server.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
---
imports:
- ml/ray/cluster/head
---

```shell
export RAY_KUBE_CLUSTER_NAME=$(kubectl get ${KUBE_CONTEXT_ARG} ${KUBE_NS_ARG} pod --no-headers -l ray-node-type=head -o custom-columns=NAME:.metadata.labels.ray-cluster-name | head -1 )
```

# Start the JupyterLab server, create working directory, and copy everything in the local working directory to the server working directory

```shell
---
validate: |
if [ -n "${KUBE_CONTEXT}" ] && [ -n "${KUBE_NS}" ]; then kubectl get ${KUBE_CONTEXT_ARG} ${KUBE_NS_ARG} deploy ${RAY_KUBE_CLUSTER_NAME}-jupyterlab; else exit 1; fi
---

--8<-- "./install.sh"
```

```shell
kubectl wait ${KUBE_CONTEXT_ARG} ${KUBE_NS_ARG} deploy/${RAY_KUBE_CLUSTER_NAME}-jupyterlab --for=condition=Available

JUPYTERLAB_POD=$(python3 -c "pod = '''$(kubectl get ${KUBE_CONTEXT_ARG} ${KUBE_NS_ARG} pods --selector app=jupyterlab-pod | grep Running)'''.split(); print(pod[0]) if len(pod) > 0 else print()")

echo -n "Installing JupyterLab..."

while [ $(kubectl exec ${KUBE_CONTEXT_ARG} ${KUBE_NS_ARG} $JUPYTERLAB_POD -- which jupyter-lab &> /dev/null && echo 1 || echo 0) -eq 0 ]
do
echo -n "."
done

echo

# This trick is used because 'kubectl cp <source>/* <pod>:<dest>' doesn't work for me
kubectl exec ${KUBE_CONTEXT_ARG} ${KUBE_NS_ARG} $JUPYTERLAB_POD -- mkdir -p /home/ray/work
tar -zcvf .work.tar -C $CUSTOM_WORKING_DIR .
kubectl cp ${KUBE_CONTEXT_ARG} ${KUBE_NS_ARG} .work.tar $JUPYTERLAB_POD:/home/ray/work
kubectl exec ${KUBE_CONTEXT_ARG} ${KUBE_NS_ARG} $JUPYTERLAB_POD -- bash -c -- "tar -xvf /home/ray/work/.work.tar -C /home/ray/work; rm /home/ray/work/.work.tar"
```

```shell
export JUPYTERLAB_POD=$(python3 -c "pod = '''$(kubectl get ${KUBE_CONTEXT_ARG} ${KUBE_NS_ARG} pods --selector app=jupyterlab-pod | grep Running)'''.split(); print(pod[0]) if len(pod) > 0 else print()")
```

# Port-forward to the Jupyter-lab server

```shell.async
date > /tmp/port-forward-jupyterlab

NUM_SERVERS=0

while [ "${NUM_SERVERS}" = "0" ];
do
SERVER_LIST=$(kubectl exec ${KUBE_CONTEXT_ARG} ${KUBE_NS_ARG} $JUPYTERLAB_POD -- jupyter server list)
NUM_SERVERS=$(kubectl exec ${KUBE_CONTEXT_ARG} ${KUBE_NS_ARG} $JUPYTERLAB_POD -- python3 -c "response = '''${SERVER_LIST}'''.split('\n'); print(len(response) - 1)")
echo "Waiting for server to start..." >> /tmp/port-forward-jupyterlab
sleep 1
done

kubectl port-forward ${KUBE_CONTEXT_ARG} ${KUBE_NS_ARG} service/${RAY_KUBE_CLUSTER_NAME}-jupyterlab 8888:8888 >> /tmp/port-forward-jupyterlab
```

# Initiate Jupyter-lab server on the pod

```shell
kubectl exec ${KUBE_CONTEXT_ARG} ${KUBE_NS_ARG} -it $JUPYTERLAB_POD -- jupyter-lab --port=8888 --no-browser --notebook-dir=/home/ray/work
```

# On completion of the Jupyter-lab cluster work, copy everything back to the local working directory

```shell
# This trick is used because 'kubectl cp <pod>:<source>/* <dest>' doesn't work for me
kubectl exec ${KUBE_CONTEXT_ARG} ${KUBE_NS_ARG} $JUPYTERLAB_POD -- tar -zcvf .work.tar -C /home/ray/work .
kubectl cp ${KUBE_CONTEXT_ARG} ${KUBE_NS_ARG} $JUPYTERLAB_POD:/home/ray/.work.tar $CUSTOM_WORKING_DIR/.work.tar
kubectl exec ${KUBE_CONTEXT_ARG} ${KUBE_NS_ARG} $JUPYTERLAB_POD -- rm /home/ray/.work.tar
tar -xvf $CUSTOM_WORKING_DIR/.work.tar -C $CUSTOM_WORKING_DIR .
rm $CUSTOM_WORKING_DIR/.work.tar
```
14 changes: 14 additions & 0 deletions guidebooks/ml/jupyterlab/start/kubernetes/ray-server.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
imports:
- ml/ray/start/kubernetes
- kubernetes/kubectl
- kubernetes/helm3
- kubernetes/context
- kubernetes/choose/ns
---

# JupyterLab on a Kubernetes cluster

A JupyterLab server will run on a Kubernetes cluster

--8<-- "../util/working-directory.md"
26 changes: 26 additions & 0 deletions guidebooks/ml/jupyterlab/start/local/image.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# "Set docker executable"
```shell
export DOCKER=docker
```

# If 'docker' is not available use 'podman'
```shell
---
validate: which docker
---
export DOCKER=podman
```

# If 'docker' is not available use 'podman'
```shell
---
validate: which podman
---
echo "No container builder (e.g., docker, podman) was found"
exit 1
```

# "Pulling image"
```bash
$DOCKER pull docker.io/metalcycling/jupyterlab
```
39 changes: 39 additions & 0 deletions guidebooks/ml/jupyterlab/start/local/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
imports:
- ./local/image.md
---

# JupyterLab on a local server

A JupyterLab server will run on your local computer

--8<-- "../util/working-directory.md"

```shell.async
$DOCKER run --privileged=true \
--rm --net=host \
-v $CUSTOM_WORKING_DIR:/home/ray/code \
-u root \
--name jupyterlab \
docker.io/metalcycling/jupyterlab:latest jupyter-lab \
--notebook-dir=/home/ray/code --port=8888 --no-browser --allow-root
```

```shell
while [ "$($DOCKER ps -q -f name=jupyterlab)" = "" ]
do
sleep 1
done

sleep 1

server_data=$($DOCKER exec jupyterlab jupyter server list --json)
url=$($DOCKER exec jupyterlab python3 -c "false = False; print(${server_data}['url'])")
token=$($DOCKER exec jupyterlab python3 -c "false = False; print(${server_data}['token'])")
xdg-open ${url}lab?token=${token}

while true
do
sleep 1
done
```
4 changes: 4 additions & 0 deletions guidebooks/ml/jupyterlab/start/util/working-directory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
=== "What working directory would you like to use? [default: ./]"
```shell
export CUSTOM_WORKING_DIR=${choice}
```
14 changes: 14 additions & 0 deletions guidebooks/ml/jupyterlab/stop/kubernetes/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
imports:
- kubernetes/helm3
- kubernetes/context
- kubernetes/choose/ns
---

# Stop The JupyterLab Server in Kubernetes

Stop The JupyterLab Server in Kubernetes.

```shell
helm ${KUBE_CONTEXT_ARG_HELM} ${KUBE_NS_ARG} uninstall jupyterlab || exit 0
```
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ spec:
containers:
- name: ray-head
image: {{ .Values.image }}
imagePullPolicy: IfNotPresent
imagePullPolicy: {{ .Values.imagePullPolicy }}
command: [ "/bin/bash", "-c", "--" ]
args:
- {{ print "ray start --head --port=6379 --redis-shard-ports=6380,6381 --num-cpus=" .Values.podTypes.rayHeadType.CPUInteger " --num-gpus=" .Values.podTypes.rayHeadType.GPU " --object-manager-port=22345 --node-manager-port=22346 --dashboard-host=0.0.0.0 --block" }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ spec:
targetPort: 6379
selector:
component: ray-head
{{end}}
{{end}}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ spec:
containers:
- name: ray-worker
image: {{ .Values.image }}
imagePullPolicy: IfNotPresent
imagePullPolicy: {{ .Values.imagePullPolicy }}
command: ["/bin/bash", "-c", "--"]
args:
- {{ print "ray start --num-cpus=" .Values.podTypes.rayWorkerType.CPUInteger " --num-gpus=" .Values.podTypes.rayWorkerType.GPU " --address=" (include "ray.headService" .) ":6379 --object-manager-port=22345 --node-manager-port=22346 --block" }}
Expand Down
2 changes: 2 additions & 0 deletions guidebooks/ml/ray/start/kubernetes/chart/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ failsafes:
# It's recommended to build custom dependencies for your workload into this image,
# taking one of the offical `rayproject/ray` images as base.
image: rayproject/ray:latest
# Define if images should be pulled or taken if present
imagePullPolicy: IfNotPresent
# If a node is idle for this many minutes, it will be removed.
idleTimeoutMinutes: 5
# serviceAccountName is used for the Ray head and each Ray worker.
Expand Down
5 changes: 3 additions & 2 deletions guidebooks/ml/ray/start/kubernetes/install-via-helm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ if [ "$KUBE_POD_MANAGER" = mcad ] || [ "$KUBE_POD_MANAGER" = kubernetes ]; then
ORG=${RAY_CHART_ORG-guidebooks}
REPO=${RAY_CHART_REPO-store}
BRANCH=${RAY_CHART_BRANCH}
SUBDIR=guidebooks/ml/ray/start/kubernetes/chart
SUBDIR=${RAY_CHART_SUBDIR-guidebooks/ml/ray/start/kubernetes/chart}

if [ "$KUBE_POD_MANAGER" = mcad ]
then MCAD_ENABLED=true
Expand Down Expand Up @@ -77,4 +77,5 @@ cd $REPO/$SUBDIR && \
--set operatorNamespace=${KUBE_NS} \
${startupProbe} \
--set clusterOnly=${CLUSTER_ONLY-false} ${SKIP_CRDS} \
--set image=${RAY_IMAGE}
--set image=${RAY_IMAGE} \
--set imagePullPolicy=${IMAGE_PULL_POLICY}
1 change: 1 addition & 0 deletions guidebooks/util/jq.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
```

=== "Linux"
<!-- FIXME: this is debian/ubuntu-specific. -->
```shell
---
validate: which jq
Expand Down