-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
44d7e0f
commit 1ef435a
Showing
9 changed files
with
444 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
# Deploy `tljh_repo2docker` as a hub-managed service | ||
|
||
A guide to help you add `tljh_repo2docker` service to a JupyterHub deployment from scratch. | ||
|
||
> [!NOTE] | ||
> In this guide, we assume you have experience with setting up JupyterHub on Kubernetes. We will use [Zero to JupyterHub](https://z2jh.jupyter.org/en/latest/index.html#zero-to-jupyterhub-with-kubernetes) as the base JupyterHub deployment. | ||
## Create a new JupyterHub docker image. | ||
|
||
Since we are going to use `tljh_repo2docker` as a hub-managed service, the python package needs to be installed into the base JupyterHub image. We will build a custom image based on the [zero-to-jupyterhub image](https://quay.io/repository/jupyterhub/k8s-hub). Here is a minimal docker file to build the custom image: | ||
|
||
```docker | ||
FROM quay.io/jupyterhub/k8s-hub:3.3.7 | ||
USER root | ||
RUN python3 -m pip install "tljh-repo2docker>=2.0.0a1" | ||
USER jovyan | ||
``` | ||
|
||
Then you can build and push the image to the registry of your choice: | ||
|
||
```bash | ||
docker build . -t k8s-hub-tljh:xxx | ||
``` | ||
## Installing JupyterHub and tljh_repo2docker with Helm chart. | ||
|
||
With a Kubernetes cluster available and Helm installed, we can install our custom JupyterHub image in the Kubernetes cluster using the JupyterHub Helm chart. You can find a chart template at [example/tljh_r2d]('./tljh_r2d'). | ||
|
||
### Using local build-backend via `repo2docker`. | ||
|
||
To build images using the local docker engine, modify the `value.yaml` file with the following content: | ||
|
||
```yaml | ||
# values.yaml | ||
jupyterhub: | ||
enabled: true | ||
hub: | ||
image: | ||
name: k8s-hub-tljh | ||
tag: xxx | ||
extraFiles: | ||
my_jupyterhub_config: | ||
mountPath: /usr/local/etc/jupyterhub/jupyterhub_config.d/jupyterhub_config.py | ||
``` | ||
Now install the chart with the JupyterHub config from `jupyterhub_config_local.py`: | ||
|
||
```bash | ||
helm upgrade --install tljh . --wait --set-file jupyterhub.hub.extraFiles.my_jupyterhub_config.stringData=./jupyterhub_config_local.py | ||
``` | ||
|
||
### Using binderhub service as build-backend. | ||
|
||
To use binderhub as the build-backend, you need to deploy [binderhub service](https://binderhub-service.readthedocs.io/en/latest/tutorials/install.html) and config `tljh-repo2docker` to use this service. Here is an example of the configuration: | ||
|
||
```yaml | ||
#values.yaml | ||
jupyterhub: | ||
enabled: true | ||
hub: | ||
image: | ||
name: k8s-hub-binhderhub-tljh | ||
tag: xxx | ||
config: | ||
BinderSpawner: | ||
auth_enabled: true | ||
extraFiles: | ||
my_jupyterhub_config: | ||
mountPath: /usr/local/etc/jupyterhub/jupyterhub_config.d/jupyterhub_config.py | ||
binderhub-service: | ||
config: | ||
BinderHub: | ||
base_url: /services/binder | ||
use_registry: true | ||
image_prefix: "" | ||
enable_api_only_mode: true | ||
buildPodsRegistryCredentials: | ||
server: "https://index.docker.io/v1/" # Set image registry for pushing images | ||
``` | ||
|
||
Now install the chart with the JupyterHub config from `jupyterhub_config_binderhub.py` and with image registry credentials passed via command line: | ||
|
||
```bash | ||
helm upgrade --install tljh . --wait --set-file jupyterhub.hub.extraFiles.my_jupyterhub_config.stringData=./jupyterhub_config_binderhub.py --set binderhub-service.buildPodsRegistryCredentials.password=xxx --set binderhub-service.buildPodsRegistryCredentials.username=xxx | ||
``` | ||
|
||
Now you should have a working instance of JupyterHub with `tljh_repo2docker` service deployed. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
FROM quay.io/jupyterhub/k8s-hub:3.3.7 | ||
|
||
USER root | ||
RUN python3 -m pip install "tljh-repo2docker>=2.0.0a1" | ||
|
||
USER jovyan |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Patterns to ignore when building packages. | ||
# This supports shell glob matching, relative path matching, and | ||
# negation (prefixed with !). Only one pattern per line. | ||
.DS_Store | ||
# Common VCS dirs | ||
.git/ | ||
.gitignore | ||
.bzr/ | ||
.bzrignore | ||
.hg/ | ||
.hgignore | ||
.svn/ | ||
# Common backup files | ||
*.swp | ||
*.bak | ||
*.tmp | ||
*.orig | ||
*~ | ||
# Various IDEs | ||
.project | ||
.idea/ | ||
*.tmproj | ||
.vscode/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
dependencies: | ||
- name: jupyterhub | ||
repository: https://hub.jupyter.org/helm-chart/ | ||
version: 3.3.7 | ||
- name: binderhub-service | ||
repository: https://2i2c.org/binderhub-service | ||
version: 0.1.0-0.dev.git.201.h161a088 | ||
digest: sha256:db05fc18bdb7cbcf06ea8881ed72391383ed0524def10d76b62b9d1880abac51 | ||
generated: "2024-05-02T20:34:11.347162518+02:00" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
apiVersion: v2 | ||
name: tljh_r2d | ||
description: A Helm chart for Kubernetes | ||
|
||
# A chart can be either an 'application' or a 'library' chart. | ||
# | ||
# Application charts are a collection of templates that can be packaged into versioned archives | ||
# to be deployed. | ||
# | ||
# Library charts provide useful utilities or functions for the chart developer. They're included as | ||
# a dependency of application charts to inject those utilities and functions into the rendering | ||
# pipeline. Library charts do not define any templates and therefore cannot be deployed. | ||
type: application | ||
|
||
# This is the chart version. This version number should be incremented each time you make changes | ||
# to the chart and its templates, including the app version. | ||
# Versions are expected to follow Semantic Versioning (https://semver.org/) | ||
version: 0.1.0 | ||
|
||
# This is the version number of the application being deployed. This version number should be | ||
# incremented each time you make changes to the application. Versions are not expected to | ||
# follow Semantic Versioning. They should reflect the version the application is using. | ||
# It is recommended to use it with quotes. | ||
appVersion: "1.16.0" | ||
|
||
dependencies: | ||
- name: jupyterhub | ||
version: "3.3.7" | ||
repository: https://hub.jupyter.org/helm-chart/ | ||
condition: jupyterhub.enabled | ||
# Optional binderhub build backend | ||
- name: binderhub-service | ||
version : "0.1.0-0.dev.git.201.h161a088" | ||
repository: https://2i2c.org/binderhub-service |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
""" | ||
This file is only used for local development | ||
and overrides some of the default values from the plugin. | ||
""" | ||
|
||
from kubespawner import KubeSpawner | ||
from pathlib import Path | ||
from tljh_repo2docker import TLJH_R2D_ADMIN_SCOPE | ||
from tornado import web | ||
from traitlets import Bool, Unicode | ||
from traitlets.config import Configurable | ||
import sys | ||
|
||
|
||
""" | ||
Helpers for creating BinderSpawners | ||
This file is defined in binderhub/binderspawner_mixin.py and is copied to here | ||
""" | ||
|
||
|
||
class BinderSpawnerMixin(Configurable): | ||
""" | ||
Mixin to convert a JupyterHub container spawner to a BinderHub spawner | ||
Container spawner must support the following properties that will be set | ||
via spawn options: | ||
- image: Container image to launch | ||
- token: JupyterHub API token | ||
""" | ||
|
||
def __init__(self, *args, **kwargs): | ||
# Is this right? Is it possible to having multiple inheritance with both | ||
# classes using traitlets? | ||
# https://stackoverflow.com/questions/9575409/calling-parent-class-init-with-multiple-inheritance-whats-the-right-way | ||
# https://github.com/ipython/traitlets/pull/175 | ||
super().__init__(*args, **kwargs) | ||
|
||
auth_enabled = Bool( | ||
False, | ||
help=""" | ||
Enable authenticated binderhub setup. | ||
Requires `jupyterhub-singleuser` to be available inside the repositories | ||
being built. | ||
""", | ||
config=True, | ||
) | ||
|
||
cors_allow_origin = Unicode( | ||
"", | ||
help=""" | ||
Origins that can access the spawned notebooks. | ||
Sets the Access-Control-Allow-Origin header in the spawned | ||
notebooks. Set to '*' to allow any origin to access spawned | ||
notebook servers. | ||
See also BinderHub.cors_allow_origin in binderhub config | ||
for controlling CORS policy for the BinderHub API endpoint. | ||
""", | ||
config=True, | ||
) | ||
|
||
def get_args(self): | ||
if self.auth_enabled: | ||
args = super().get_args() | ||
else: | ||
args = [ | ||
"--ip=0.0.0.0", | ||
f"--port={self.port}", | ||
f"--NotebookApp.base_url={self.server.base_url}", | ||
f"--NotebookApp.token={self.user_options['token']}", | ||
"--NotebookApp.trust_xheaders=True", | ||
] | ||
if self.default_url: | ||
args.append(f"--NotebookApp.default_url={self.default_url}") | ||
|
||
if self.cors_allow_origin: | ||
args.append("--NotebookApp.allow_origin=" + self.cors_allow_origin) | ||
# allow_origin=* doesn't properly allow cross-origin requests to single files | ||
# see https://github.com/jupyter/notebook/pull/5898 | ||
if self.cors_allow_origin == "*": | ||
args.append("--NotebookApp.allow_origin_pat=.*") | ||
args += self.args | ||
# ServerApp compatibility: duplicate NotebookApp args | ||
for arg in list(args): | ||
if arg.startswith("--NotebookApp."): | ||
args.append(arg.replace("--NotebookApp.", "--ServerApp.")) | ||
return args | ||
|
||
def start(self): | ||
if not self.auth_enabled: | ||
if "token" not in self.user_options: | ||
raise web.HTTPError(400, "token required") | ||
if "image" not in self.user_options: | ||
raise web.HTTPError(400, "image required") | ||
if "image" in self.user_options: | ||
self.image = self.user_options["image"] | ||
return super().start() | ||
|
||
def get_env(self): | ||
env = super().get_env() | ||
if "repo_url" in self.user_options: | ||
env["BINDER_REPO_URL"] = self.user_options["repo_url"] | ||
for key in ( | ||
"binder_ref_url", | ||
"binder_launch_host", | ||
"binder_persistent_request", | ||
"binder_request", | ||
): | ||
if key in self.user_options: | ||
env[key.upper()] = self.user_options[key] | ||
return env | ||
|
||
|
||
class BinderSpawner(BinderSpawnerMixin, KubeSpawner): | ||
pass | ||
|
||
|
||
HERE = Path(__file__).parent | ||
|
||
c.JupyterHub.spawner_class = BinderSpawner | ||
|
||
c.JupyterHub.allow_named_servers = True | ||
|
||
c.JupyterHub.services.extend( | ||
[ | ||
{"name": "binder", "url": "http://tljh-binderhub-service"}, | ||
{ | ||
"name": "tljhrepo2docker", | ||
"url": "http://r2d-svc:6789", | ||
"command": [ | ||
sys.executable, | ||
"-m", | ||
"tljh_repo2docker", | ||
"--ip", | ||
"0.0.0.0", | ||
"--port", | ||
"6789", | ||
"--TljhRepo2Docker.binderhub_url", | ||
"http://tljh-binderhub-service/services/binder", | ||
], | ||
"oauth_no_confirm": True, | ||
"oauth_client_allowed_scopes": [ | ||
TLJH_R2D_ADMIN_SCOPE, | ||
], | ||
}, | ||
] | ||
) | ||
|
||
c.JupyterHub.custom_scopes = { | ||
TLJH_R2D_ADMIN_SCOPE: { | ||
"description": "Admin access to myservice", | ||
}, | ||
} | ||
|
||
c.JupyterHub.load_roles = [ | ||
{ | ||
"description": "Role for tljh_repo2docker service", | ||
"name": "tljh-repo2docker-service", | ||
"scopes": [ | ||
"read:users", | ||
"read:roles:users", | ||
"admin:servers", | ||
"access:services!service=binder", | ||
], | ||
"services": ["tljhrepo2docker"], | ||
}, | ||
{ | ||
"name": "tljh-repo2docker-service-admin", | ||
"users": [], # List of users having admin right on tljh-repo2docker | ||
"scopes": [TLJH_R2D_ADMIN_SCOPE], | ||
}, | ||
{ | ||
"name": "user", | ||
"scopes": [ | ||
"self", | ||
# access to the env page | ||
"access:services!service=tljhrepo2docker", | ||
], | ||
}, | ||
] |
Oops, something went wrong.