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.
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 # 0.11.1 is latest stable release at the time of this writing FROM jupyterhub/k8s-hub:0.11.1 COPY ./service-fastapi /usr/src/fastapi RUN python3 -m pip install -r /usr/src/fastapi/requirements.txt
# 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