Jupyterlab on top of the hub and k8s

Hi,

I’ve been following this guide on deploying the hub on top of kubernetes: Zero to JupyterHub with Kubernetes — Zero to JupyterHub with Kubernetes documentation

I had 2 questions:

  1. How can I use Jupyter lab instead of the single notebook on landing page? (/lab doesn’t show anything).
  2. How do I customize the lab deployment to come with pre-installed pip packages and extensions? It seems with the helm command it just deployed the chart from some distribution or repo.
  3. If I want to add users, do I need to edit the chart every time? Is there a way to automate it?

Thanks!!

1 Like

Hi!

  1. Could you tell us which version of Z2JH you’re using, and show us your configuration with secrets redacted?
  2. You can use a custom container image for your user environment, see Customizing User Environment — Zero to JupyterHub with Kubernetes documentation
  3. JupyterHub maintains a database, as long as it’s on a persistent volume you shouldn’t have to re-add any users. If you want to add users later you should be able to do so as an admin, or by configuring an authenticator that allows users to sign themselves up

For installation I’ve used this repo https://jupyterhub.github.io/helm-chart/
And version 1.2.0.
The Kubernetes cluster is the default aws one I’ve used Kubernetes 1.20 as well.

For the third point, I actually have a users DB that people can sign up through the main website, so ideally once they sign up there, it’ll create an entry for them on the hub DB, or alternatively, can I connect it with the cognito pool somehow?

OAuthenticator can be configured to work with AWS Cognito:
https://oauthenticator.readthedocs.io/en/latest/getting-started.html#aws-cognito-setup

Is this config.py coming from the helm repo?

Also any thoughts on how to get a Jupyter lab?

You can set any JupyterHub config in hub.config:

hub:
  config:
    JupyterHub:
      authenticator_class: "generic"
    OAuthenticator:
      oauth_callback_url = "https://[your-host]/hub/oauth_callback"
      client_id = "[your app ID]"
      ...

If JupyterLab is available in the image, you can follow the instructions for selecting Lab by default:

singleuser:
  defaultUrl: "/lab"
  extraEnv:
    JUPYTERHUB_SINGLEUSER_APP: "jupyter_server.serverapp.ServerApp"

If that doesn’t work (e.g. leads to blank page or 404), it means the JupyterLab server extension is not available in the env, and you might need to make sure it’s installed.

Ok I think that might be my issue, After doing helm add repo and update,
I ran: helm install jupyterhub/jupyterhub --version 1.2.0 --generate-name

So I assume it ran without any config.yaml file/ran with the default one?
It’s also a bit unclear where does the hub.config comes into play and where jupyterhub_config.py from the cognito setup kicks in?

When trying to change the url from:
http://my-host.com/user/jovyan1/tree?
to
http://my-host.com/lab/user/jovyan1

I get a 404 so I assume the extension isn’t available, how do I install it?
I think I saw somewhere that the JupyterLab is the default on Jhub 2.0, which I believe is the version I installed so I’m not sure why it’s not there.

This is what I get when checking the versions:


Selected Jupyter core packages...
IPython          : 7.29.0
ipykernel        : 6.4.2
ipywidgets       : not installed
jupyter_client   : 7.0.6
jupyter_core     : 4.9.1
jupyter_server   : 1.11.1
jupyterlab       : 3.2.1
nbclient         : 0.5.4
nbconvert        : 6.2.0
nbformat         : 5.1.3
notebook         : 6.4.5
qtconsole        : not installed
traitlets        : 5.1.1

Awesome, so I think initially I just installed without the values config.yaml file and that is what was missing. Also, so for every python class I can overwrite through this config, the lab works and now I’m doing the cognito, I assume it’ll look like that in the end:

  defaultUrl: "/lab"
  extraEnv:
    JUPYTERHUB_SINGLEUSER_APP: "jupyter_server.serverapp.ServerApp"

hub:
  config:
    JupyterHub:
      authenticator_class: "generic"
    OAuthenticator:
      oauth_callback_url = "https://some-host/hub/oauth_callback"
      client_id = "[your app ID]"
      client_secret = "[your app Password]"
    GenericOAuthenticator:
      login_service = "AWSCognito"
      username_key = "login"
      authorize_url = "https://your-AWSCognito-domain/oauth2/authorize"
      token_url = ""https://your-AWSCognito-domain/oauth2/token"
      userdata_url = "https://your-AWSCognito-domain/oauth2/userInfo"

I’m having an error after adding the values to the yaml:
[C 2022-03-30 11:47:52.169 JupyterHub application:89] Bad config encountered during initialization: The 'authenticator_class' trait of <jupyterhub.app.JupyterHub object at 0x7f74201da0a0> instance must be a type, but 'generic' could not be imported

  • I think there should be a change to the docs here, since “generic” in the authenticator_class doesn’t work by default. I solved it by using "oauthenticator.generic.GenericOAuthenticator"

Sorry, it should be generic-oauth

I do see the cognito button, whenever I’m logging in it freezes until it times out.
I think it’s related to the fact that inside cognito HTTPS is required over HTTP, so I defined the URL in it to: https://ID.elb.amazonaws.com/hub/oauth_callback
I think that’s the reason it freeze, any thoughts there?

I also saw there’s a guide to enable SSL with a custom domain here, is there a way to enforce HTTPS on the elb without a custom domain?

I did try adding manually created SSL which works without the cognito (even though insecure) and then I tried adding cognito. With that the Cognito doesn’t timeout after logged in (like happened with regular http) with the user but now, the redirect is giving a 403 error.

Any idea what’s going on?

Can you turn on debug logging and show us your hub logs?

Yes, so just did, and logged in with cognito, here’s what I’m getting - Is it possible since this user was registering in a webapp, this user doesn’t exist on the cluster and that’s why it’s 403? (*edit: It’s not the case since registering through the cluster also gives the 403 after the authentication code) If so how do I make it create one or make sure it doesn’t crash:

[I 2022-04-01 06:44:25.704 JupyterHub log:189] 302 GET /hub/ -> /hub/login?next=%2Fhub%2F 
[D 2022-04-01 06:44:26.180 JupyterHub log:189] 200 GET /hub/health  0.65ms
[I 2022-04-01 06:44:26.400 JupyterHub log:189] 200 GET /hub/login?next=%2Fhub%2F 
[D 2022-04-01 06:44:28.180 JupyterHub log:189] 200 GET /hub/health  0.65ms
[I 2022-04-01 06:44:28.769 JupyterHub oauth2:111] OAuth redirect: 'https://LB.us-east-2.elb.amazonaws.com/hub/oauth_callback'
[D 2022-04-01 06:44:28.770 JupyterHub base:526] Setting cookie oauthenticator-state: {'httponly': True, 'secure': True, 'expires_days': 1}
[I 2022-04-01 06:44:28.771 JupyterHub log:189] 302 GET /hub/oauth_login?next=%2Fhub%2F -> https://jhub.auth.us-east-1.amazoncognito.com/oauth2/authorize?response_type=code&redirect_uri=https%3A%2F%2FLB.us-east-2.elb.amazonaws.com%2Fhub%2Foauth_callback&client_id=206vbnjevf8ou73a292ssh0tj1&state=[secret]  1.87ms
[D 2022-04-01 06:44:30.180 JupyterHub log:189] 200 GET /hub/health  0.66ms
[D 2022-04-01 06:44:32.180 JupyterHub log:189] 200 GET /hub/health 0.64ms
[D 2022-04-01 06:44:34.180 JupyterHub log:189] 200 GET /hub/health  0.80ms
[D 2022-04-01 06:44:35.830 JupyterHub proxy:832] Proxy: Fetching GET http://proxy-api:8001/api/routes
[I 2022-04-01 06:44:35.833 JupyterHub proxy:347] Checking routes
[D 2022-04-01 06:44:36.180 JupyterHub log:189] 200 GET /hub/health  0.58ms
[E 2022-04-01 06:44:36.828 JupyterHub generic:178] OAuth user contains no key login: {'sub': 'dc3fdc0a-0097-49bf-8be6-ad1568ab4513', 'email_verified': 'true', 'email': 'EMAIL', 'username': 'USER'}
[W 2022-04-01 06:44:36.828 JupyterHub base:768] Failed login for unknown user
[D 2022-04-01 06:44:36.828 JupyterHub base:1285] No template for 403
[W 2022-04-01 06:44:36.849 JupyterHub log:189] 403 GET /hub/oauth_callback?code=[secret]&state=[secret]  349.84ms
[D 2022-04-01 06:44:38.180 JupyterHub log:189] 200 GET /hub/health  0.66ms

It looks like you’re trying to use the login field, but it’s not present in the response. Try another field from the response, e.g. email or username?

1 Like

Yes this was it!
I’ve changed it into email and it solved the issue.

Is there a way for me to connect it with this webapp?
Like after users log in and authenticate they’ll have a link to the hub which gets this dictionary somehow?

You can try setting c.Authenticator.auto_login = True

If that doesn’t give you your desired behaviour you’ll have to write your own JupyterHub authenticator that gets the information from your app.