How to deploy jupyterlab on k8s

I use k8s + jupyterhub for deployment, but the page displayed after logging in is the notebook page. I hope the page after logging in is the jupyterlab page, which is displayed in jupyterhub_ Try to modify c.spaowner.default in file_ Url = ‘/ Lab’ and c.kubespawner.default_ Url = ‘/ Lab’, but it doesn’t work. Does anyone know how to log in to jupyterlab after k8s deployed jupyterhub?

Hi! Could you tell us a bit more about your deployment, including how was your Kubernetes cluster setup, what version of the Z2JH helm chart are you using, and show us your Z2JH config with secrets redacted? Thanks!

@manics Hello, thank you for your answer!
I didn’t deploy with helm.The jupyterhub is started using anaconda and then connected to the k8s cluster.
K8s cluster
Kubedm is used for deployment, and the restriction parameter – cggroup driver = cgroupfs is used.

Client Version: version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.2", GitCommit:"092fbfbf53427de67cac1e9fa54aaa09a28371d7", GitTreeState:"clean", BuildDate: "2021-06-16T12:59:11Z", GoVersion:"go1.16.5", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.2", GitCommit:"092fbfbf53427de67cac1e9fa54aaa09a28371d7", GitTreeState:"clean", BuildDate:"2021-06-16T12:53:14Z", GoVersion:"go1.16.5", Compiler:"gc", Platform:"linux/amd64"}

Docker vesion:

 Version:           18.09.7
 API version:       1.39
 Go version:        go1.10.8
 Git commit:        2d0083d
 Built:             Thu Jun 27 17:56:06 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
  Version:          18.09.7
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.8
  Git commit:       2d0083d
  Built:            Thu Jun 27 17:26:28 2019
  OS/Arch:          linux/amd64
  Experimental:     false

Jupyterhub component version:

jupyterhub                         1.4.2
jupyterhub-dummyauthenticator      0.3.1
jupyterhub-kubespawner             1.1.0 configure:

import os
import socket
c.JupyterHub.admin_access = True
c.JupyterHub.allow_named_servers = True
c.JupyterHub.authenticator_class = 'dummy'
c.JupyterHub.bind_url = ''
c.JupyterHub.cleanup_servers = False
if os.environ.get("CI"):
    # In the CI system we use k3s which will be accessible on localhost.
    c.JupyterHub.hub_connect_ip = ""
    # Find the IP of the machine that minikube is most likely able to talk to
    # Graciously used from
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.connect(("", 80))
    host_ip = s.getsockname()[0]

    c.JupyterHub.hub_connect_ip = host_ip
c.JupyterHub.hub_ip = ''
c.JupyterHub.spawner_class = 'kubespawner.KubeSpawner'
c.Spawner.http_timeout = 300
c.Authenticator.admin_users = {'root'}
c.Authenticator.allowed_users = {'root','limy'}
c.KubeSpawner.start_timeout = 60 * 5
c.KubeSpawner.image = 'jupyterhub/singleuser:1.0.0'
c.KubeSpawner.service_account = 'default'
c.KubeSpawner.storage_pvc_ensure = False
c.KubeSpawner.cpu_guarantee = 1
c.KubeSpawner.cpu_limit = 3
c.KubeSpawner.mem_guarantee = '2G'
c.KubeSpawner.mem_limit = '4G'
# c.Spawner.default_url = '/lab'
c.KubeSpawner.default_url = '/lab'
c.KubeSpawner.image_pull_policy = 'IfNotPresent'
c.KubeSpawner.namespace = 'jupyterhub-k8s'
# c.Spawner.notebook_dir = '/opt/{username}'
c.KubeSpawner.notebook_dir = '/opt/{username}'


The Helm chart is well tested, supported, and documented, so if you’re able to switch to it things will be easier to figure out.

If you can’t use it, then could you:

  • check that JupyterLab is running on /lab
  • show us your singleuser pod logs
  • tell us how you built and tested all your Docker images?


1 Like

@manics Hello,thank you for your answer!

check that JupyterLab is running on /lab
I don’t quite understand this sentence. Can there be a specific operation process?

singleuser pod logs:

# kubectl logs jupyter-limy -n jupyterhub-k8s
Executing the command: jupyterhub-singleuser --ip=
[W 2021-08-13 12:30:04.504 SingleUserNotebookApp configurable:190] Config option `open_browser` not recognized by `SingleUserNotebookApp`.  Did you mean `browser`?
[I 2021-08-13 12:30:05.794 SingleUserNotebookApp extension:162] JupyterLab extension loaded from /opt/conda/lib/python3.8/site-packages/jupyterlab
[I 2021-08-13 12:30:05.795 SingleUserNotebookApp extension:163] JupyterLab application directory is /opt/conda/share/jupyter/lab
[I 2021-08-13 12:30:05.799 SingleUserNotebookApp mixins:557] Starting jupyterhub-singleuser server version 1.3.0
[W 2021-08-13 12:30:05.806 SingleUserNotebookApp _version:70] jupyterhub version 1.4.2 != jupyterhub-singleuser version 1.3.0. This could cause failure to authenticate and result in redirect loops!
[I 2021-08-13 12:30:05.807 SingleUserNotebookApp notebookapp:2209] Serving notebooks from local directory: /home/jovyan
[I 2021-08-13 12:30:05.807 SingleUserNotebookApp notebookapp:2209] Jupyter Notebook 6.1.5 is running at:
[I 2021-08-13 12:30:05.807 SingleUserNotebookApp notebookapp:2209] http://jupyter-limy:8888/user/limy/
[I 2021-08-13 12:30:05.807 SingleUserNotebookApp notebookapp:2210] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[I 2021-08-13 12:30:05.812 SingleUserNotebookApp mixins:537] Updating Hub with activity every 300 seconds
[I 2021-08-13 12:30:06.169 SingleUserNotebookApp log:181] 302 GET /user/limy/ -> /user/limy/tree? (@ 0.91ms
[I 2021-08-13 12:30:06.241 SingleUserNotebookApp log:181] 302 GET /user/limy/ -> /user/limy/tree? (@ 1.26ms
[I 2021-08-13 12:30:06.370 SingleUserNotebookApp log:181] 302 GET /user/limy/tree? -> /hub/api/oauth2/authorize?client_id=jupyterhub-user-limy&redirect_uri=%2Fuser%2Flimy%2Foauth_callback&response_type=code&state=[secret] (@ 4.61ms
[I 2021-08-13 12:30:06.533 SingleUserNotebookApp auth:983] Logged-in user {'kind': 'user', 'name': 'limy', 'admin': False, 'groups': [], 'server': '/user/limy/', 'pending': None, 'created': '2021-08-13T12:29:39.830808Z', 'last_activity': '2021-08-13T12:30:06.524972Z', 'servers': None}
[I 2021-08-13 12:30:06.534 SingleUserNotebookApp log:181] 302 GET /user/limy/oauth_callback?code=[secret]&state=[secret] -> /user/limy/tree? (@ 76.21ms
[I 2021-08-13 12:30:06.628 SingleUserNotebookApp log:181] 200 GET /user/limy/tree? (limy@ 59.98ms
[I 2021-08-13 12:30:07.467 SingleUserNotebookApp log:181] 200 GET /user/limy/api/config/tree?_=1628857813211 (limy@ 3.37ms
[I 2021-08-13 12:30:07.476 SingleUserNotebookApp log:181] 200 GET /user/limy/api/config/common?_=1628857813212 (limy@ 2.95ms
[I 2021-08-13 12:30:07.505 SingleUserNotebookApp log:181] 200 GET /user/limy/api/terminals?_=1628857813213 (limy@ 1.70ms
[I 2021-08-13 12:30:07.537 SingleUserNotebookApp log:181] 200 GET /user/limy/api/sessions?_=1628857813214 (limy@ 2.64ms
[I 2021-08-13 12:30:07.545 SingleUserNotebookApp log:181] 200 GET /user/limy/api/terminals?_=1628857813215 (limy@ 1.40ms
[I 2021-08-13 12:30:07.759 SingleUserNotebookApp log:181] 200 GET /user/limy/api/contents?type=directory&_=1628857813216 (limy@ 3.18ms

Image source:
image source is the jupiterhub/singleuser: latest on the docker hub. I use the docker tag to modify the tag

This is the start-up process inside the container:

# ps -ef | grep start
jovyan       1     0  0 12:30 ?        00:00:00 tini -g --

# whereis
start-notebook: /usr/local/bin/

# cat /usr/local/bin/
set -e

if [[ "${RESTARTABLE}" == "yes" ]]; then

if [[ ! -z "${JUPYTERHUB_API_TOKEN}" ]]; then
    exec /usr/local/bin/ "$@"
elif [[ ! -z "${JUPYTER_ENABLE_LAB}" ]]; then
    . /usr/local/bin/ $wrapper jupyter lab "$@"
    . /usr/local/bin/ $wrapper jupyter notebook "$@"

# cat /usr/local/bin/
set -e

if [[ "$NOTEBOOK_ARGS $@" != *"--ip="* ]]; then

# handle some deprecated environment variables
# from DockerSpawner < 0.8.
# These won't be passed from DockerSpawner 0.9,
# so avoid specifying --arg=empty-string
if [ ! -z "$NOTEBOOK_DIR" ]; then
if [ ! -z "$JPY_PORT" ]; then
if [ ! -z "$JPY_USER" ]; then
if [ ! -z "$JPY_COOKIE_NAME" ]; then
if [ ! -z "$JPY_BASE_URL" ]; then
if [ ! -z "$JPY_HUB_PREFIX" ]; then
if [ ! -z "$JPY_HUB_API_URL" ]; then

. /usr/local/bin/ $NOTEBOOK_BIN $NOTEBOOK_ARGS "$@"

Problems found during startup:
I found that there is no way to set default_url parameters during the startup process

JupyterLab can be reached by going to http://<HUB URL or IP ADDRESS>/lab

Hello,thank you for your answer!

I cannot access the /lab program.

An exceprion occurred when i visited /lab, as follows:

404: not found
Jupyter has lots of moons, but this is not one…

The log is follows:

[JupyterHub log:189] 302 GET /lab -> /hub/lab (@ 41.06ms
[JupyterHub log:189] 404 GET /hub/lab (@ 141.99ms

@manics @sgibson91 Hi!
Can you provide a configuration file template of jupyterhub + kubernetes + jupyterlab?

@manics @sgibson91
Thank you for your help!
I found the problem. To run jupyterab on jupyterab, need to configure the c.kubespawner.cmd = ["jupyter-labhub"] parameter.

1 Like