Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
# are not set in the shell environment.

# To override these values, set the shell environment variables.
# JUPYTERHUB_VERSION=2.3.1
JUPYTERHUB_VERSION=1.5.0

# Assign a port for the hub to be hosted on.
Expand All @@ -24,7 +25,7 @@ DOCKER_NETWORK_NAME=hub-network
#DOCKER_NOTEBOOK_IMAGE=jupyter/tensorflow-notebook:4d9c9bd9ced0
# d0bfe4b38f78: tensorflow==2.4.1 python==3.9.2 lab==3.0.15 notebook==6.3.0 hub==1.4.1
# 23ac04200f8f: tensorflow==2.6.0 python==3.9.7 lab==3.2.3 notebook==6.4.5 hub==1.5.0
DOCKER_NOTEBOOK_IMAGE=jupyter/tensorflow-notebook:hub-1.5.0
DOCKER_NOTEBOOK_IMAGE=jupyter/tensorflow-notebook:hub-${JUPYTERHUB_VERSION}

# the local image we use, after pinning jupyterhub version
#LOCAL_NOTEBOOK_IMAGE=jupyterhub-user
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile.jupyterhub
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ RUN pip install psycopg2-binary~=2.7 && \
pip install --no-cache-dir \
oauthenticator==0.8.*

RUN pip install jupyterhub-hashauthenticator dockerspawner~=12.0
RUN pip install jupyterhub-hashauthenticator dockerspawner==12.1.0
RUN pip install jupyterhub-idle-culler

# Copy TLS certificate and key
Expand All @@ -19,4 +19,4 @@ RUN pip install jupyterhub-idle-culler
#RUN chmod 700 /srv/jupyterhub/secrets && \
# chmod 600 /srv/jupyterhub/secrets/*

#COPY ./userlist /srv/jupyterhub/userlist
#COPY ./userlist /srv/jupyterhub/userlist
74 changes: 63 additions & 11 deletions jupyterhub_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,17 @@ def create_volume_mount(group_id='group', mode='ro', nb_user='jovyan') -> 'Dict[
ENABLE_DROPDOWN = True
IMAGE_WHITELIST= {
'default': f"{HUB_NAME}-user",
'rstudio+shiny': "r-image",
'scipy-notebook': "jupyter/scipy-notebook",
'tensorflow-notebook': "jupyter/tensorflow-notebook",
'r-notebook': 'jupyter/r-notebook',
'base-notebook': "jupyter/base-notebook",
'gpu': f"{HUB_NAME}-gpu-user",
'RStudio & Shiny': "r-image",
}

def default_url_fn(handler):
user = handler.current_user
if user and user.admin:
return '/hub/admin'
return '/hub/home'

c.JupyterHub.default_url = default_url_fn

# Spawn single-user servers as Docker containers
from dockerspawner import DockerSpawner
Expand All @@ -100,23 +104,70 @@ def start(self):
# self.mount_config_files()
# self.grant_sudo()
# self.limit_resources()
self.enable_lab()
self.update_image_name()
self.grant_sudo() # grants sudo to all users!!!
self.grant_gpu()
# self.enable_lab()
return super().start()


def update_image_name(self):
"""
Updates the image name from dropdown list (if exists).
This is required because the `self.start()` method
updates it but we need access to the variable `self.image`
prior to startup in order to set extra_host_config (for gpus).
NOTE: If the check was based on username rather than image name,
this would not be required (but then GPUs are attached per-user)
"""
image = self.user_options.get('image')
if image:
allowed_images = self._get_allowed_images()
if allowed_images:
if image not in allowed_images:
raise web.HTTPError(
400,
"Image %s not in allowed list: %s" % (image, ', '.join(allowed_images)),
)
else:
image = allowed_images[image]

self.image = image

if self.image in (f"{HUB_NAME}-user", f"{HUB_NAME}-gpu-user"):
self.environment["VSCODE"] = "1"

if self.image == "r-image":
self.environment["RSTUDIO"] = "1"

def grant_sudo(self):
"""
Grants sudo permission to current user being spawned.
"""
self.environment['GRANT_SUDO'] = "1"
self.extra_create_kwargs = {'user': 'root'}

self.extra_create_kwargs.update({"user": "root"})

def grant_gpu(self):
if "gpu" in self.image:
import docker
self.extra_host_config.update({
"device_requests": [
docker.types.DeviceRequest(
count=-1,
capabilities=[["gpu"]],
driver="nvidia",
options={"--gpus":"all"}
)],
})

def enable_lab(self):
"""
Sets Jupyterlab as the default environment which users see.
WARNING: Will not work if ~/.jupyter/jupyter_notebook_config.py exists.
"""
self.environment['JUPYTER_ENABLE_LAB'] = 'yes'
self.default_url = '/lab'
# self.notebook_dir = '/home/jovyan/work'

def update_volumes(self, group_list):
for group_id in group_list:
Expand Down Expand Up @@ -168,7 +219,7 @@ def mount_config_files(self, username='jovyan'):
# user `jovyan`, and set the notebook directory to `/home/jovyan/work`.
# We follow the same convention.
notebook_dir = os.environ.get('DOCKER_NOTEBOOK_DIR') or '/home/jovyan/work'
#c.DockerSpawner.notebook_dir = notebook_dir
# c.DockerSpawner.notebook_dir = notebook_dir
# Mount the real user's Docker volume on the host to the notebook user's
# notebook directory in the container
c.DockerSpawner.volumes = { 'hub-user-{username}': notebook_dir }
Expand All @@ -185,7 +236,8 @@ def mount_config_files(self, username='jovyan'):
# User containers will access hub by container name on the Docker network
c.JupyterHub.hub_ip = HUB_NAME
# The hub will be hosted at example.com/HUB_NAME/
c.JupyterHub.base_url = u'/%s/'%HUB_NAME
# c.JupyterHub.base_url = u'/%s/'%HUB_NAME
c.JupyterHub.base_url = u'/'
#c.JupyterHub.hub_port = 8001

## Authentication
Expand Down Expand Up @@ -236,7 +288,7 @@ def mount_config_files(self, username='jovyan'):


# https://github.com/jupyterhub/jupyterhub-idle-culler
if os.environ['CULL_IDLE']:
if os.environ['CULL_IDLE'] == "true":
c.JupyterHub.services = [
{
"name": "jupyterhub-idle-culler-service",
Expand Down
6 changes: 6 additions & 0 deletions makefile
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ notebook_image: pull singleuser/Dockerfile
--build-arg DOCKER_NOTEBOOK_IMAGE=$(DOCKER_NOTEBOOK_IMAGE) \
singleuser

gpu_notebook_image: singleuser/Dockerfile.gpu
docker build -t $(HUB_NAME)-gpu-user:latest -f singleuser/Dockerfile.gpu \
--build-arg JUPYTERHUB_VERSION=$(JUPYTERHUB_VERSION) \
--build-arg DOCKER_NOTEBOOK_IMAGE=cschranz/gpu-jupyter:v1.4_cuda-11.2_ubuntu-20.04_slim \
singleuser

build: check-files network volumes secrets/oauth.env secrets/postgres.env
docker-compose build

Expand Down
41 changes: 22 additions & 19 deletions singleuser/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ FROM $DOCKER_NOTEBOOK_IMAGE
ARG JUPYTERHUB_VERSION

USER root

RUN apt-get update && \
apt-get install -y --no-install-recommends \
dvipng \
Expand All @@ -25,10 +26,10 @@ COPY install_dev_tools.sh /tmp/
RUN /tmp/install_dev_tools.sh

# Final cleaning and user customizations
USER $NB_UID
# USER $NB_UID
RUN \
fix-permissions $CONDA_DIR && \
fix-permissions /home/$NB_USER
fix-permissions $CONDA_DIR && \
fix-permissions /home/$NB_USER

USER $NB_UID
# RUN mamba install xeus-python -y
Expand All @@ -46,22 +47,6 @@ COPY install_monitoring.sh /tmp/
COPY install_hugo.sh /tmp/
COPY install_geckodriver.sh /tmp/

USER root
## CONFIG
# Copy over config which creates launcher icons in jupyterlab
COPY jupyter_notebook_config.py /home/jovyan/.jupyter/
RUN mkdir -p /home/$NB_USER/.jupyter/lab/workspaces/
COPY ./jupyterlab_settings /home/$NB_USER/.jupyter/lab/user-settings/@jupyterlab
RUN chmod -R 777 /home/$NB_USER/.jupyter/lab

USER $NB_UID

# USER SETTINGS
RUN echo "export EDITOR=/usr/bin/vim" >> /home/$NB_USER/.bashrc
RUN echo "export PAGER=less" >> /home/$NB_USER/.bashrc

# remember git login credentials
RUN git config --global credential.helper "cache --timeout 144000"

USER root
COPY install_vscode.sh /tmp/
Expand All @@ -76,3 +61,21 @@ RUN code-server --install-extension eamodio.gitlens
RUN code-server --install-extension mechatroner.rainbow-csv
# RUN code-server --install-extension golang.go
RUN echo '{ "python.defaultInterpreterPath": "conda", "telemetry.enableTelemetry": false, "telemetry.telemetryLevel": "off",}' > /home/$NB_USER/.local/share/code-server/User/settings.json


USER root
## CONFIG
# Copy over config which creates launcher icons in jupyterlab
COPY jupyter_notebook_config.py /home/$NB_USER/.jupyter/
RUN mkdir -p /home/$NB_USER/.jupyter/lab/workspaces/
COPY ./jupyterlab_settings /home/$NB_USER/.jupyter/lab/user-settings/@jupyterlab
RUN chown -R $NB_USER:$NB_GUID /home/$NB_USER/.jupyter/lab
USER $NB_UID

# USER SETTINGS
RUN echo "export EDITOR=/usr/bin/vim" >> /home/$NB_USER/.bashrc
RUN echo "export PAGER=less" >> /home/$NB_USER/.bashrc

# remember git login credentials
RUN git config --global credential.helper "cache --timeout 144000"
RUN pip install jupyterhub==$JUPYTERHUB_VERSION
10 changes: 9 additions & 1 deletion singleuser/Dockerfile-R
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,13 @@ RUN conda clean --all -f -y && \
fix-permissions $CONDA_DIR && \
fix-permissions /home/$NB_USER

USER $NB_UID
# CMD R
USER root
## CONFIG
# Copy over config which creates launcher icons in jupyterlab
COPY jupyter_notebook_config.py /home/$NB_USER/.jupyter/
RUN mkdir -p /home/$NB_USER/.jupyter/lab/workspaces/
COPY ./jupyterlab_settings /home/$NB_USER/.jupyter/lab/user-settings/@jupyterlab
RUN chown -R $NB_USER:$NB_GUID /home/$NB_USER/.jupyter/lab

USER $NB_UID
88 changes: 88 additions & 0 deletions singleuser/Dockerfile.gpu
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
ARG DOCKER_NOTEBOOK_IMAGE
FROM $DOCKER_NOTEBOOK_IMAGE
ARG JUPYTERHUB_VERSION

USER root
RUN apt-key del 7fa2af80 && \
cd /tmp/ && \
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/cuda-keyring_1.0-1_all.deb && \
dpkg -i cuda-keyring_1.0-1_all.deb && \
rm cuda-keyring_1.0-1_all.deb && \
sed -i '/developer\.download\.nvidia\.com\/compute\/cuda\/repos/d' /etc/apt/sources.list && \
rm -f /etc/apt/sources.list.d/cuda*.list /etc/apt/sources.list.d/nvidia-ml.list

RUN apt-get update && \
apt-get install -y --no-install-recommends \
dvipng \
fonts-lato \
fonts-dejavu \
gcc \
gfortran \
ghostscript \
imagemagick \
lmodern \
&& \
apt-get -qq purge && \
apt-get -qq clean && \
rm -rf /var/lib/apt/lists/*


# Dev tools
USER root
COPY install_dev_tools.sh /tmp/
RUN /tmp/install_dev_tools.sh

# Final cleaning and user customizations
# USER $NB_UID
RUN \
fix-permissions $CONDA_DIR && \
fix-permissions /home/$NB_USER

USER $NB_UID
# RUN mamba install xeus-python -y
RUN pip install jupyter_server_proxy
RUN pip install black flake8 autopep8 isort pre-commit

COPY install_jupyter_nbextensions.sh /tmp/
# RUN /tmp/install_jupyter_nbextensions.sh

COPY install_language_server.sh /tmp/
RUN /tmp/install_language_server.sh

COPY install_monitoring.sh /tmp/
# RUN /tmp/install_monitoring.sh
COPY install_hugo.sh /tmp/
COPY install_geckodriver.sh /tmp/


USER root
COPY install_vscode.sh /tmp/
RUN /tmp/install_vscode.sh

USER $NB_UID
RUN mkdir -p /home/$NB_USER/.local/share/code-server/User/
RUN code-server --install-extension ms-python.python
RUN code-server --install-extension ms-toolsai.jupyter
RUN code-server --install-extension hookyqr.beautify
RUN code-server --install-extension eamodio.gitlens
RUN code-server --install-extension mechatroner.rainbow-csv
# RUN code-server --install-extension golang.go
RUN echo '{ "python.defaultInterpreterPath": "conda", "telemetry.enableTelemetry": false, "telemetry.telemetryLevel": "off",}' > /home/$NB_USER/.local/share/code-server/User/settings.json


USER root
## CONFIG
# Copy over config which creates launcher icons in jupyterlab
COPY jupyter_notebook_config.py /home/$NB_USER/.jupyter/
RUN mkdir -p /home/$NB_USER/.jupyter/lab/workspaces/
COPY ./jupyterlab_settings /home/$NB_USER/.jupyter/lab/user-settings/@jupyterlab
RUN chown -R $NB_USER:$NB_GUID /home/$NB_USER/.jupyter/lab
USER $NB_UID

# USER SETTINGS
RUN echo "export EDITOR=/usr/bin/vim" >> /home/$NB_USER/.bashrc
RUN echo "export PAGER=less" >> /home/$NB_USER/.bashrc

# remember git login credentials
RUN git config --global credential.helper "cache --timeout 144000"
RUN pip install jupyterhub==$JUPYTERHUB_VERSION
2 changes: 1 addition & 1 deletion singleuser/install_vscode.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ apt-get update && \
curl && \
echo "getting latest install script" && \
curl -fsSL https://code-server.dev/install.sh > install.sh && \
sh install.sh --version 4.7.0 && \
sh install.sh --version 4.5.2 && \
rm install.sh && \
apt-get -qq purge curl && \
apt-get -qq purge && \
Expand Down
38 changes: 23 additions & 15 deletions singleuser/jupyter_notebook_config.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
import os

c.LatexConfig.latex_command = 'pdflatex'
c.NotebookApp.default_url = '/lab'
if os.environ.get("VSCODE", None):
c.NotebookApp.default_url = '/vscode'
if os.environ.get("RSTUDIO", None):
c.NotebookApp.default_url = '/rstudio'

# Jupyterlab icons can be created here to launch apps
# that are included in the user's image.
c.ServerProxy.servers = {
'vscode': {
'command': [
'code-server',
'--auth', 'none',
'--bind-addr', '0.0.0.0',
'--port', '5000'
],
'port': 5000,
'absolute_url': False,
'new_browser_tab': True,
'launcher_entry': {
'title': 'VSCode',
},
if os.environ.get("VSCODE", None):
c.ServerProxy.servers = {
'vscode': {
'command': [
'code-server',
'--auth', 'none',
'--bind-addr', '0.0.0.0',
'--port', '5000'
],
'port': 5000,
'absolute_url': False,
'new_browser_tab': True,
'launcher_entry': {
'title': 'VSCode',
},
}
}
}