Services#
JupyterHub services (not to be confused with Kubernetes Service objects) are processes that interact with the JupyterHub API. nbgrader and culling idle Notebooks are examples of production services, and there are minimal examples of “hello world” services in the Jupyterhub examples repo.
Services can be run externally from the Hub, meaning they are started and stopped independently of the Hub and must know about things like their Hub authentication token on their own. Alternatively, a service can be Hub-managed, where the Hub starts and stops the process and passes key information to the service via environment variables.
Hub-managed services in z2jh#
A Hub-managed service will run in the same container/pod as the Hub itself. First, you’ll need to install or copy the appropriate files for the service into your Hub image, either by creating a custom image derived from jupyterhub/k8s-hub
or the hub.extraFiles configuration. Keep in mind that your Hub container may need to install dependency libraries like flask or fastapi, depending on the service. In those cases, you’ll need a custom image.
In addition to the code for the service, you need to modify the Hub Kubernetes Service object to include multiple ports, and update the Hub Network Policy. If you want to allow access from all sources, you can use hub.networkPolicy.allowedIngressPorts. Otherwise if you want to more precisely control access, you can use hub.networkPolicy.ingress.
Example service#
In the following snippet, I’m using a custom image that copies over the application code and installs the dependencies listed in the fastapi service example.
# Dockerfile
# 3.1.0 is latest stable release at the time of this writing
# Find all tags in https://quay.io/repository/jupyterhub/k8s-hub?tab=tags
FROM quay.io/jupyterhub/k8s-hub:3.1.0
# Depending on version, the k8s-hub image may have installed
# pip packages as root, forcing you to install as root as well
USER root
COPY ./service-fastapi /usr/src/fastapi
RUN python3 -m pip install -r /usr/src/fastapi/requirements.txt
USER ${NB_USER}
# config.yaml
hub:
image:
name: myregistry/my-custom-hub-image
tag: latest
services:
fastapi:
url: http://hub:8181
command:
- /home/jovyan/.local/bin/uvicorn
- app:app
- --port
- "8181"
- --host
- "0.0.0.0"
- --app-dir
- /usr/src/fastapi
oauth_redirect_uri: https://jupyterhub.mycloud.com/services/fastapi/oauth_callback
environment:
PUBLIC_HOST: https://jupyterhub.mycloud.com
networkPolicy:
ingress:
- ports:
- port: 8181
from:
- podSelector:
matchLabels:
hub.jupyter.org/network-access-hub: "true"
service:
extraPorts:
- port: 8181
targetPort: 8181
name: fastapi
# The proxy.chp.networkPolicy.egress configuration below is required if the
# service should be accessible for users. If it shouldn't be, you should instead
# set the chart configuration services.fastapi.display to false as otherwise
# JupyterHub will provide a broken link in the Services menu for users to go to
# /services/fastapi/.
proxy:
chp:
networkPolicy:
egress:
- to:
- podSelector:
matchLabels:
app: jupyterhub
component: hub
ports:
- port: 8181