You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Describe the bug
I try to run a dockerized Jupyterhub with ContaindDS Dashboard using traefik as reverse proxy. Everything works fine except the creation of a containds dashbord, failing with a HTTP 500 error. I'm not very experianced so any hint what I'm doing wrong would be welcome.
To Reproduce
I use a .ipynb notebook which I could watch with voila within my user notebook for testing. When I try to use the dashboard interface to turn this testnotebook into a ContainDS Dashboard I get the HTTP 500 error.
Screenshots
Configuration
I used standard Docker Files for Jupyterhub and Jupyterlab (for Jupyterhub: jupyterhub/jupyterhub:2.0.1 or jupyterhub/jupyterhub:1.5.0; for Jupyterlab jupyter/scipy-notebook:hub-2.0.1 or a jupyter/scipy-notebook:hub-1.5.0), added the necessary ContainDS packages ( voila,streamlit,dash,cdsdashboards,jhsingle-native-proxy, jupyter-containds ) via pip install and created images for Jupyterhub and Jupyterlab. Those images are used in a docker_compose container for the Jupyterhub/Jupyterlab services . The traefik reverse proxy is running in a seperate container and provides the network for the jupyter container (Full setup see https://github.com/tstreibl/Jupyterhub_Traefik_ContainDS_Test; readme in doc folder contains more details).
During the final build phase (log says "In do_final_build") the containds container fails, because the "jhsingle_native_proxy.main" module could not be found, although I pip installed it in the jupyterhub and in the jupyterlab images. For that reason the containds container never shows up on the network, which results in a timeout and probably the http 500 error.
I have no idea if I used the wrong docker files for jupyterhub/jupyterlab, if I messed up building the images, especially the pip installations or if it's a network issue concerning traefik and the way the traefik network is provided to jupyterhub.
Log from containds dashboard container which gets spawned and fails
# see https://hub.docker.com/r/jupyterhub/jupyterhub/tags#FROM jupyterhub/jupyterhub:1.5.0
FROM jupyterhub/jupyterhub:2.0.1
COPY jupyterhub_config.py .#Example see https://stackoverflow.com/questions/27701930/how-to-add-users-to-docker-container #system user tstreibl and normal user testuser
RUN useradd -r -m -s /bin/bash -g users -G sudo,users -p meinpasswort tstreibl
#RUN useradd -m -s /bin/bash -g users -p meinpasswort tstreibl
RUN useradd -m -s /bin/bash -g users -p testuserpasswort testuser
USER root
RUN apt-get -y update && apt-get install
# voila-gridstack would be an option
RUN pip3 install --no-cache-dir \
dockerspawner \
voila \
streamlit \
dash \
cdsdashboards \
jhsingle-native-proxy \
jupyter-containds \
oauthenticator
#USER tstreibl # does not work, seems to be necessary that at the end user is root
Docker File to create the jupyterlab image
#see https://hub.docker.com/r/jupyter/scipy-notebook/tags#FROM jupyter/scipy-notebook:hub-1.5.0
FROM jupyter/scipy-notebook:hub-2.0.1
#FROM jupyter/scipy-notebook:latest
USER root
# vermutlich braucht man keines der Zusatzpackages; sagemath ist aber ein nettes addon# APT packages
RUN apt-get update && \
apt-get install -y --no-install-recommends \
fonts-dejavu \
tzdata \
gfortran \
gcc \
scilab \
pari-gp \
libpari-dev \
sagemath \
sagemath-jupyter \
libgmp-dev \
&& apt-get clean && \
rm -rf /var/lib/apt/lists/*
USER $NB_UID#tornado is already installed#jhsingle-native-proxy seems to be required for cdsdashboards but is not automatically installed
RUN pip3 install --no-cache-dir \
voila \
streamlit \
dash \
cdsdashboards \
jupyter-containds \
jhsingle-native-proxy \
bqplot && \
fix-permissions "${CONDA_DIR}"&& \
fix-permissions "/home/${NB_USER}"# RUN conda install --quiet --yes \# tornado \# voila \# streamlit \# dash \# cdsdashboards \# jupyter-containds \# jhsingle-native-proxy \# bqplot && \# fix-permissions $CONDA_DIR
USER $NB_UID#seems to be mandatory that the user is not root at the end
Docker-Compose file for the jpyterhub and jupyterlab services
version: "3.7"networks:
#Enable connection with Traefik traefik:
external: truejupyter_net: # entspricht ${INTERNAL_NETWORK}name: "jupyter_net"external: falsedriver: bridge # ohne den Bridge Mode funktioniert gar nichtsvolumes:
jupyterhub_data:
jupyterhub_config:
services:
jupyterhub:
container_name: jupyterhubvolumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- jupyterhub_data:/srv/jupyterhub # this volume must be deleted when changing jupyterhub_config.py otherwise changes won't reflect
- jupyterhub_config:/etc/jupyterhub # all configurations
- "/home/tilo/traefik/letsencrypt/certs/jupyter.tilostreibl.de:/certs:ro"networks:
- traefik
- ${INTERNAL_NETWORK} # - jupyter_netports:
- "8000:8000"# - "8001:8001"# - "8081:8081"
- "8888:8888"# necessary?env_file:
- ./.envenvironment:
TZ: Europe/Stockholm #set the time zone in the container HOST: "${HOST}"COMPOSE_PROJECT_NAME: "${COMPOSE_PROJECT_NAME}"DOCKER_JUPYTER_CONTAINER: "${DOCKER_JUPYTER_CONTAINER}"#must match the image name build in jupyterlab serviceDOCKER_NOTEBOOK_DIR: "${DOCKER_NOTEBOOK_DIR}"# directory im Container innerhalb des für jupyterhub generierten binds, wo die jupyter notebooks der User gespeichert werden #- DOCKER_JUPYTER_CONTAINER=jupyterlab_imgHUB_IP: jupyterhub #must match container_name (0.0.0.0 does not work)labels:
- "traefik.enable=true"
- "traefik.docker.network=${INTERNAL_NETWORK}"
- "traefik.frontend.rule=Host:${HOST}"
- "providers.docker=true"# Route HTTPS
- "traefik.http.routers.jupyterhub-secure.entrypoints=web-secure"
- "traefik.http.routers.jupyterhub-secure.rule=Host(`${HOST}`)"# Enable TLS
- "traefik.http.routers.jupyterhub-secure.tls=true"# Enable Let's Encrypt HTTP challenge
- "traefik.http.routers.traefik-secure-secured.tls.certresolver=letsencrypthttpchallenge"
- "traefik.http.routers.jupyterhub-secure.tls.certresolver=letsencrypthttpchallenge"image: jupyterhub_img:latestbuild:
context: ./jupyterhubrestart: on-failurejupyterlab:
container_name: jupyterlab-throawaybuild:
context: ./jupyterlab restart: on-failureimage: ${DOCKER_JUPYTER_CONTAINER}:latestnetworks:
- ${INTERNAL_NETWORK}command: echo # to stop the container being run from docker - the hub will start the containerenv_file:
- ./.envenvironment:
TZ: Europe/Stockholm #set the time zone in the containerDOCKER_NOTEBOOK_DIR: "${DOCKER_NOTEBOOK_DIR}"# directory im Container innerhalb des für jupyterhub generierten binds, wo die jupyter notebooks der User gespeichert werden GRANT_SUDO: 'yes'CHOWN_HOME: 'yes'CHOWN_HOME_OPTS: '-R'JUPYTERHUB_ANYONE: 1JUPYTER_ENABLE_LAB: 'yes'#see https://github.com/jupyter/docker-stacks/issues/1217NB_GID: 1000# entspricht Group "users", der default eingerichtete javyan user gehört zu dieser Gruppelabels:
# Connect to Traefik
- "traefik.enable=true"
- "traefik.frontend.rule=Host:${HOST}"
- "traefik.docker.network= ${INTERNAL_NETWORK}"# Route HTTPS
- "traefik.http.routers.jupyterlab-secure.entrypoints=web-secure"
- "traefik.http.routers.jupyterlab-secure.rule=Host(`${HOST}`)"# Enable TLS
- "traefik.http.routers.jupyterlab-secure.tls=true"# Enable Let's Encrypt HTTP challenge
- "traefik.http.routers.jupyterlab-secure.tls.certresolver=letsencrypthttpchallenge"# Enable HSTS headers
- "traefik.http.middlewares.hstsheaders.headers.stsSeconds=315360000"
- "traefik.http.middlewares.hstsheaders.headers.forceSTSHeader=true"
- "traefik.http.middlewares.hstsheaders.headers.stsPreload=true"
- "traefik.http.middlewares.hstsheaders.headers.stsIncludeSubdomains=true"
Docker-Compose file for the traefic reverse proxy
version: "3.7"networks:
#Allow back-ends to communicate with thistraefik:
external: truename: traefik services:
traefik:
image: "traefik:latest"env_file:
- ./.envcontainer_name: "traefik"restart: alwayscommand:
#Only if you want to use the Traefik Dashboard
- "--log.level=DEBUG"
- "--api.insecure=false"
- "--api.dashboard=true"# Define Docker as the provider here
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"#The location of where we will store our dynamic file with various configurations possible "on the fly"
- "--providers.file.directory=/etc/traefik/dynamic"#Entrypoint -> is a front-end named "web" on HTTP Port 80
- "--entrypoints.web.address=:80"#Entrypoint -> is a front-end named "web-secure" on HTTPS Port 443
- "--entrypoints.web-secure.address=:443"#HTTP challenge as our method to acquire SSL certificates
- "--certificatesresolvers.letsencrypthttpchallenge.acme.httpchallenge=true"
- "--certificatesresolvers.letsencrypthttpchallenge.acme.httpchallenge.entrypoint=web"#Define Let's Encrypt as the issuer#- "--certificatesresolvers.letsencrypthttpchallenge.acme.email=webmaster@tilostreibl.de"
- "--certificatesresolvers.letsencrypthttpchallenge.acme.email=${EMAIL}"#- "--certificatesresolvers.letsencrypthttpchallenge.acme.onhostrule=true"# Location of the acme.json file
- "--certificatesresolvers.letsencrypthttpchallenge.acme.storage=/letsencrypt/acme.json"labels:
- "traefik.enable=true"
- "traefik.frontend.rule=Host:${DOMAIN}"
- "traefik.docker.network=traefik"#This will enable SSL
- "traefik.http.routers.traefik-secure.tls=true"#Enable Let's Encrypt HTTP challenge
- "traefik.http.routers.traefik-secure.tls.certresolver=letsencrypthttpchallenge"#Use the web-secure as our entrypoint at 443
- "traefik.http.routers.traefik-secure.entrypoints=web-secure"#The router here is just called traefik-secure and the FQDN rule
- "traefik.http.routers.traefik-secure.rule=Host(`${DASHBOARD}`)"#Enable traefik-auth middleware to use
- "traefik.http.routers.traefik-secure.middlewares=traefik-auth"#Refer to traefik's dashboard service
- "traefik.http.routers.traefik-secure.service=api@internal"#Hashed Password for the dashboard
- "traefik.http.middlewares.traefik-auth.basicauth.users=admin:${ADMIN_PASS}"#Global redirection: http to https
- traefik.http.routers.http-catchall.rule=HostRegexp(`{host:(www\.)?.+}`)
- traefik.http.routers.http-catchall.entrypoints=web
- traefik.http.routers.http-catchall.middlewares=wwwtohttps#Global redirection: https (www.) to https
- traefik.http.routers.wwwsecure-catchall.rule=HostRegexp(`{host:(www\.).+}`)
- traefik.http.routers.wwwsecure-catchall.entrypoints=web-secure
- traefik.http.routers.wwwsecure-catchall.tls=true
- traefik.http.routers.wwwsecure-catchall.middlewares=wwwtohttps#middleware: http(s)://(www.) to https://
- traefik.http.middlewares.wwwtohttps.redirectregex.regex=^https?://(?:www\.)?(.+)
- traefik.http.middlewares.wwwtohttps.redirectregex.replacement=https://$${1}
- traefik.http.middlewares.wwwtohttps.redirectregex.permanent=true#Specifying the Ports Traefik will listen onports:
- "80:80"
- "443:443"#The network Traefik will use is just traefiknetworks:
- "traefik"volumes:
#Docker socket
- "/var/run/docker.sock:/var/run/docker.sock:ro"#Let's Encrypt certificates in ./letsencrypt/acme.json
- "./letsencrypt:/letsencrypt"#Mount the dynamic file configuration
- ./dynamic-config.yaml:/etc/traefik/dynamic/dynamic-config.yaml#wandelt das Letsencrypt Zertifikat von Traefic aus der Datei acme.json in ander Zertifikat Formate im Verzeichnis dump um#wird für jupyter gebraucht, weil man dort keine acme.json einlesen kann, sondern die einzelnen privatekey.key und certificate.crt benötigt#Details: https://github.com/DanielHuisman/traefik-certificate-extractor#Details: https://github.com/ldez/traefik-certs-dumper/issues/46certdumper:
image: ldez/traefik-certs-dumper:latestlogging: #man kann den Log Output nicht konfiguruieren, daher vorerst diese Methode um die Logs der anderen Apps besser zu sehendriver: nonecommand: "file --watch --domain-subdir=true --version v2"volumes:
- "./letsencrypt/acme.json:/acme.json:ro"
- "./letsencrypt/certs:/dump"
jupyterhub_config.py
#JupyterHub configuration###If you update this file, do not forget to delete the `jupyterhub_data` volume before restarting the jupyterhub service:####docker volume rm jupyterhub_jupyterhub_data#### or, if you changed the COMPOSE_PROJECT_NAME to <name>:####docker volume rm <name>_jupyterhub_data##importos, sysimportshutil#print shows up in logs with "flush=True"print("This is a testoutput from jupyterhub_config.py using print",flush=True)
c.JupyterHub.log_level=10#Files are created from the certdumper docker service (see docker-compose for traefic)#traefic and letsencrypt provides automatically an acme.json file#the certdumper docker service only converts the acme.json file into the key and cert files#would be much easier if we could load the acme.json directly at this place c.JupyterHub.ssl_key='/certs/privatekey.key'#aus dem Laufwerk des Containersc.JupyterHub.ssl_cert='/certs/certificate.crt'c.JupyterHub.trusted_downstream_ips= [os.environ['HOST_IP']]
c.JupyterHub.cleanup_proxy=Truec.JupyterHub.cleanup_servers=Truec.JupyterHub.hub_ip='0.0.0.0'#os.environ['HUB_IP'] works alsoc.JupyterHub.hub_connect_ip=os.environ['HUB_IP'] #mandatory#Default: 8081 #c.JupyterHub.hub_port = 8081c.CDSDashboardsConfig.builder_class='cdsdashboards.builder.dockerbuilder.DockerBuilder'##Genericc.JupyterHub.admin_access=Truec.Spawner.default_url='/lab'#{username} will be expanded to the user’s usernamec.JupyterHub.shutdown_on_logout=True# von mir; Session nach logout zu machen##Authenticatorfromoauthenticator.githubimportLocalGitHubOAuthenticatorc.JupyterHub.authenticator_class='oauthenticator.LocalGitHubOAuthenticator'# GitHubOAuthenticatorc.Authenticator.auto_login_oauth2_authorize=Falsec.Authenticator.oauth_callback_url=os.environ['oauth_callback_url']
c.Authenticator.client_id=os.environ['client_id']
c.Authenticator.client_secret=os.environ['client_secret']
c.Authenticator.allowed_users= {'tstreibl','testuser'}
c.Authenticator.admin_users= {'tstreibl'}
c.Authenticator.create_system_users=True#Enabling ContainDS Dashboard; see https://cdsdashboards.readthedocs.io/en/stable/chapters/setup/docker.html#installing-cdsdashboardsfromcdsdashboards.appimportCDS_TEMPLATE_PATHSfromcdsdashboards.hubextensionimportcds_extra_handlers#from cdsdashboards.app import CDSDashboardsConfig c.JupyterHub.template_paths=CDS_TEMPLATE_PATHSc.JupyterHub.extra_handlers=cds_extra_handlers#c.VariableMixin.proxy_force_alive = True#c.VariableMixin.proxy_last_activity_interval = 300#c.VariableMixin.proxy_request_timeout = 0importsecretsos.environ['JPY_COOKIE_SECRET'] =secrets.token_hex(16)
c.JupyterHub.cookie_secret=bytes.fromhex(os.environ['JPY_COOKIE_SECRET'])
c.CDSDashboardsConfig.builder_class='cdsdashboards.builder.dockerbuilder.DockerBuilder'c.CDSDashboardsConfig.allow_custom_conda_env=Falsec.CDSDashboardsConfig.include_auth_state=Truec.CDSDashboardsConfig.include_servers=Truec.CDSDashboardsConfig.include_servers_state=Truec.JupyterHub.spawner_class='cdsdashboards.hubextension.spawners.variabledocker.VariableDockerSpawner'c.Spawner.debug=Truec.JupyterHub.allow_named_servers=Truec.Spawner.image=os.environ['DOCKER_JUPYTER_CONTAINER']
#servername = os.environ['HOST'] c.Spawner.extra_host_config= {'network_mode': os.environ['INTERNAL_NETWORK']}
c.Spawner.hub_ip_connect=os.environ['HUB_IP']
c.Spawner.network_name=os.environ['INTERNAL_NETWORK'] #"jupyter_net"c.Spawner.use_internal_ip=Truec.Spawner.remove=False# remove user containers when done. True works better but difficult to debugc.Spawner.debug=Truenotebook_dir=os.environ.get('DOCKER_NOTEBOOK_DIR')
c.Spawner.notebook_dir=notebook_dirc.Spawner.extra_create_kwargs= {'user': 'root'} #jovyanc.Spawner.environment= {
'GRANT_SUDO': '1',
'UID': '0', # workaround https://github.com/jupyter/docker-stacks/pull/420
}
c.Spawner.name_template="{prefix}-{username}-{servername}"c.Spawner.volumes= {"{prefix}-{username}-{servername}": notebook_dir }
c.Spawner.cpu_limit=1c.Spawner.mem_limit='10G'
The text was updated successfully, but these errors were encountered:
I'm having the same issue with a TLJH deployment on a VM running Ubuntu 20.02.
I've used cdsdashboards==0.5.7 since there is remark in the changelog when user DockerSpawner, but nu luck unfortunately.
I was struggling with the folder rights to write to folder after mounting volumes. I saw a tip somewhere on github (sorry can't find where at the moment) to include a pre_spawn_hook to create folder and alter the ownership. Further it advised to add c.DockerSpawner.extra_create_kwargs = {"user": "root"}. After commenting this out the containers successfully started for dashboards.
Something like @maarten-betman's solution kind of worked (in my case, I had spawner.extra_container_spec = {'user': '0'} in my pre_spawn_hook) in that I didn't encounter the "module not found issue". However, this solution was not satisfactory because the files in the server's containers weren't being mounted properly.
It seems that by using root as the user, the conda environment wasn't being sourced, and so the command python3 being used didn't have the jhsingle module. However, the command python does have the jhsingle module. Hence, I added the following command to my jupyterhub_config.py to use python instead of python3:
Describe the bug
I try to run a dockerized Jupyterhub with ContaindDS Dashboard using traefik as reverse proxy. Everything works fine except the creation of a containds dashbord, failing with a HTTP 500 error. I'm not very experianced so any hint what I'm doing wrong would be welcome.
To Reproduce
I use a .ipynb notebook which I could watch with voila within my user notebook for testing. When I try to use the dashboard interface to turn this testnotebook into a ContainDS Dashboard I get the HTTP 500 error.
Screenshots
Configuration
I used standard Docker Files for Jupyterhub and Jupyterlab (for Jupyterhub: jupyterhub/jupyterhub:2.0.1 or jupyterhub/jupyterhub:1.5.0; for Jupyterlab jupyter/scipy-notebook:hub-2.0.1 or a jupyter/scipy-notebook:hub-1.5.0), added the necessary ContainDS packages ( voila,streamlit,dash,cdsdashboards,jhsingle-native-proxy, jupyter-containds ) via pip install and created images for Jupyterhub and Jupyterlab. Those images are used in a docker_compose container for the Jupyterhub/Jupyterlab services . The traefik reverse proxy is running in a seperate container and provides the network for the jupyter container (Full setup see https://github.com/tstreibl/Jupyterhub_Traefik_ContainDS_Test; readme in doc folder contains more details).
classes used:
During the final build phase (log says "In do_final_build") the containds container fails, because the "jhsingle_native_proxy.main" module could not be found, although I pip installed it in the jupyterhub and in the jupyterlab images. For that reason the containds container never shows up on the network, which results in a timeout and probably the http 500 error.
I have no idea if I used the wrong docker files for jupyterhub/jupyterlab, if I messed up building the images, especially the pip installations or if it's a network issue concerning traefik and the way the traefik network is provided to jupyterhub.
Log from containds dashboard container which gets spawned and fails
log from jupyterlab container waiting for the containds dashboard container to show up
modules installed in the jupyterlab container
Docker File to create the jupyterhub image
Docker File to create the jupyterlab image
Docker-Compose file for the jpyterhub and jupyterlab services
Docker-Compose file for the traefic reverse proxy
jupyterhub_config.py
The text was updated successfully, but these errors were encountered: