Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jupyter Notebook deprecation -> default to JupyterLab #1575

Merged
merged 10 commits into from
Jan 20, 2022
Merged
Show file tree
Hide file tree
Changes from 8 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
1 change: 0 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,6 @@ cont-rm-all: ## remove all containers



dev/%: DARGS?=-e JUPYTER_ENABLE_LAB=yes
dev/%: PORT?=8888
dev/%: ## run a foreground container for a stack
docker run -it --rm -p $(PORT):8888 $(DARGS) $(OWNER)/$(notdir $@)
Expand Down
21 changes: 10 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ and want to launch a single Jupyter Notebook server in a container.
The [User Guide on ReadTheDocs](https://jupyter-docker-stacks.readthedocs.io/) describes additional uses and features in detail.

**Example 1:** This command pulls the `jupyter/scipy-notebook` image tagged `33add21fab64` from Docker Hub if it is not already present on the local host.
It then starts a container running a Jupyter Notebook server and exposes the server on host port 8888.
It then starts a container running a Jupyter Server and exposes the server on host port 8888.
The server logs appear in the terminal.
Visiting `http://<hostname>:8888/?token=<token>` in a browser loads the Jupyter Notebook dashboard page,
Visiting `http://<hostname>:8888/?token=<token>` in a browser loads JupyterLab,
where `hostname` is the name of the computer running docker and `token` is the secret token printed in the console.
The container remains intact for restart after the notebook server exits.

Expand All @@ -32,23 +32,23 @@ docker run -p 8888:8888 jupyter/scipy-notebook:33add21fab64
```

**Example 2:** This command performs the same operations as **Example 1**, but it exposes the server on host port 10000 instead of port 8888.
Visiting `http://<hostname>:10000/?token=<token>` in a browser loads Jupyter Notebook server,
Visiting `http://<hostname>:10000/?token=<token>` in a browser loads JupyterLab,
where `hostname` is the name of the computer running docker and `token` is the secret token printed in the console.

```bash
docker run -p 10000:8888 jupyter/scipy-notebook:33add21fab64
```

**Example 3:** This command pulls the `jupyter/datascience-notebook` image tagged `33add21fab64` from Docker Hub if it is not already present on the local host.
It then starts an _ephemeral_ container running a Jupyter Notebook server and exposes the server on host port 10000.
It then starts an _ephemeral_ container running a Jupyter Server and exposes the server on host port 10000.
The command mounts the current working directory on the host as `/home/jovyan/work` in the container.
The server logs appear in the terminal.
Visiting `http://<hostname>:10000/?token=<token>` in a browser loads JupyterLab,
where `hostname` is the name of the computer running docker and `token` is the secret token printed in the console.
Docker destroys the container after notebook server exit, but any files written to `~/work` in the container remain intact on the host.
Docker destroys the container after Jupyter Server exit, but any files written to `~/work` in the container remain intact on the host.

```bash
docker run --rm -p 10000:8888 -e JUPYTER_ENABLE_LAB=yes -v "${PWD}":/home/jovyan/work jupyter/datascience-notebook:33add21fab64
docker run --rm -p 10000:8888 -v "${PWD}":/home/jovyan/work jupyter/datascience-notebook:33add21fab64
```

## Contributing
Expand Down Expand Up @@ -76,13 +76,12 @@ We will happily grant additional permissions (e.g., ability to merge PRs) to any

## Jupyter Notebook Deprecation Notice

Following [Jupyter Notebook notice](https://github.com/jupyter/notebook#notice), we encourage users to transition to JupyterLab.
This can be done by passing the environment variable `JUPYTER_ENABLE_LAB=yes` at container startup,
Following [Jupyter Notebook notice](https://github.com/jupyter/notebook#notice), JupyterLab is now the default for all of the Jupyter Docker stack images.
It is still possible to switch back to Jupyter Notebook (or to launch a different startup command).
This can be done by passing the environment variable `JUPYTER_CMD=notebook` (or any other valid `jupyter` command) at container startup,
more information is available in the [documentation](https://jupyter-docker-stacks.readthedocs.io/en/latest/using/common.html#docker-options).

At some point, JupyterLab will become the default for all of the Jupyter Docker stack images, however a new environment variable will be introduced to switch back to Jupyter Notebook if needed.

After the change of default, and according to the Jupyter Notebook project status and its compatibility with JupyterLab,
According to the Jupyter Notebook project status and its compatibility with JupyterLab,
these Docker images may remove the classic Jupyter Notebook interface altogether in favor of another _classic-like_ UI built atop JupyterLab.

This change is tracked in the issue [#1217](https://github.com/jupyter/docker-stacks/issues/1217), please check its content for more information.
Expand Down
16 changes: 9 additions & 7 deletions base-notebook/start-notebook.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

set -e

# The Jupyter command to launch
# JupyterLab by default
JUPYTER_CMD="${JUPYTER_CMD:=lab}"

if [[ -n "${JUPYTERHUB_API_TOKEN}" ]]; then
echo "WARNING: using start-singleuser.sh instead of start-notebook.sh to start a server associated with JupyterHub."
exec /usr/local/bin/start-singleuser.sh "$@"
Expand All @@ -14,11 +18,9 @@ if [[ "${RESTARTABLE}" == "yes" ]]; then
wrapper="run-one-constantly"
fi

if [[ -n "${JUPYTER_ENABLE_LAB}" ]]; then
# shellcheck disable=SC1091,SC2086
exec /usr/local/bin/start.sh ${wrapper} jupyter lab ${NOTEBOOK_ARGS} "$@"
else
echo "WARNING: Jupyter Notebook deprecation notice https://github.com/jupyter/docker-stacks#jupyter-notebook-deprecation-notice."
# shellcheck disable=SC1091,SC2086
exec /usr/local/bin/start.sh ${wrapper} jupyter notebook ${NOTEBOOK_ARGS} "$@"
if [[ -v JUPYTER_ENABLE_LAB ]]; then
echo "WARNING: JUPYTER_ENABLE_LAB is ignored, use JUPYTER_CMD if you want to change the command used to start the server"
fi

# shellcheck disable=SC1091,SC2086
exec /usr/local/bin/start.sh ${wrapper} jupyter ${JUPYTER_CMD} ${NOTEBOOK_ARGS} "$@"
6 changes: 2 additions & 4 deletions base-notebook/test/test_container_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ def test_cli_args(container: TrackedContainer, http_client: requests.Session) ->
warnings = [
warning for warning in logs.split("\n") if warning.startswith("WARNING")
]
assert len(warnings) == 1
assert warnings[0].startswith("WARNING: Jupyter Notebook deprecation notice")
assert not warnings
assert "login_submit" not in resp.text


Expand All @@ -49,8 +48,7 @@ def test_unsigned_ssl(
warnings = [
warning for warning in logs.split("\n") if warning.startswith("WARNING")
]
assert len(warnings) == 1
assert warnings[0].startswith("WARNING: Jupyter Notebook deprecation notice")
assert not warnings


def test_uid_change(container: TrackedContainer) -> None:
Expand Down
67 changes: 44 additions & 23 deletions base-notebook/test/test_start_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,77 @@
# Distributed under the terms of the Modified BSD License.

import logging
from typing import Optional
import pytest
import requests
import re
import time

from conftest import TrackedContainer

LOGGER = logging.getLogger(__name__)


@pytest.mark.parametrize(
"env,expected_server",
"env,expected_command,expected_start,expected_warnings",
romainx marked this conversation as resolved.
Show resolved Hide resolved
[
(["JUPYTER_ENABLE_LAB=yes"], "lab"),
(None, "notebook"),
(
["JUPYTER_ENABLE_LAB=yes"],
"jupyter lab",
True,
["WARNING: JUPYTER_ENABLE_LAB is ignored"],
),
(None, "jupyter lab", True, []),
(["JUPYTER_CMD=lab"], "jupyter lab", True, []),
(["RESTARTABLE=yes"], "run-one-constantly jupyter lab", True, []),
(["JUPYTER_CMD=notebook"], "jupyter notebook", True, []),
(["JUPYTER_CMD=server"], "jupyter server", True, []),
(["JUPYTER_CMD=nbclassic"], "jupyter nbclassic", True, []),
(
["JUPYTERHUB_API_TOKEN=my_token"],
"jupyterhub-singleuser",
False,
["WARNING: using start-singleuser.sh"],
),
],
)
def test_start_notebook(
romainx marked this conversation as resolved.
Show resolved Hide resolved
container: TrackedContainer,
http_client: requests.Session,
env,
expected_server: str,
env: Optional[list[str]],
expected_command: str,
expected_start: bool,
expected_warnings: list[str],
) -> None:
"""Test the notebook start-notebook script"""
LOGGER.info(
f"Test that the start-notebook launches the {expected_server} server from the env {env} ..."
f"Test that the start-notebook launches the {expected_command} server from the env {env} ..."
)
c = container.run(
tty=True,
environment=env,
command=["start-notebook.sh"],
)
resp = http_client.get("http://localhost:8888")
# sleeping some time to let the server start
time.sleep(3)
logs = c.logs(stdout=True).decode("utf-8")
LOGGER.debug(logs)
assert "ERROR" not in logs
if expected_server != "notebook":
assert "WARNING" not in logs
else:
warnings = [
warning for warning in logs.split("\n") if warning.startswith("WARNING")
]
assert len(warnings) == 1
assert warnings[0].startswith("WARNING: Jupyter Notebook deprecation notice")
assert resp.status_code == 200, "Server is not listening"
# checking that the expected command is launched
assert (
f"Executing the command: jupyter {expected_server}" in logs
), f"Not the expected command (jupyter {expected_server}) was launched"
# Checking warning messages
if not env:
msg = "WARNING: Jupyter Notebook deprecation notice"
assert msg in logs, f"Expected warning message {msg} not printed"
f"Executing the command: {expected_command}" in logs
), f"Not the expected command ({expected_command}) was launched"
# checking errors and warnings in logs
assert "ERROR" not in logs, "ERROR(s) found in logs"
for exp_warning in expected_warnings:
assert exp_warning in logs, f"Expected warning {exp_warning} not found in logs"
warnings = re.findall(r"^WARNING", logs, flags=re.MULTILINE)
assert len(expected_warnings) == len(
warnings
), "Not found the number of expected warnings in logs"
# checking if the server is listening
if expected_start:
resp = http_client.get("http://localhost:8888")
assert resp.status_code == 200, "Server is not listening"


def test_tini_entrypoint(
Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Visiting ``http://<hostname>:10000/lab?token=<token>`` in a browser loads Jupyte
where ``hostname`` is the name of the computer running docker and ``token`` is the secret token printed in the console.
Docker destroys the container after notebook server exit, but any files written to ``~/work`` in the container remain intact on the host.::

docker run --rm -p 10000:8888 -e JUPYTER_ENABLE_LAB=yes -v "${PWD}":/home/jovyan/work jupyter/datascience-notebook:33add21fab64
romainx marked this conversation as resolved.
Show resolved Hide resolved
docker run --rm -p 10000:8888 -v "${PWD}":/home/jovyan/work jupyter/datascience-notebook:33add21fab64

CPU Architectures
-----------------
Expand Down
41 changes: 39 additions & 2 deletions docs/using/common.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ You do so by passing arguments to the `docker run` command.
(The `start-notebook.sh` script will `su ${NB_USER}` after adding `${NB_USER}` to sudoers.)
**You should only enable `sudo` if you trust the user or if the container is running on an isolated host.**
- `-e GEN_CERT=yes` - Instructs the startup script to generates a self-signed SSL certificate and configure Jupyter Notebook to use it to accept encrypted HTTPS connections.
- `-e JUPYTER_ENABLE_LAB=yes` - Instructs the startup script to run `jupyter lab` instead of the default `jupyter notebook` command.
- `-e JUPYTER_CMD=<jupyter command>` - Instructs the startup script to run `jupyter ${JUPYTER_CMD}` instead of the default `jupyter lab` command.
See [Switching back to classic notebook or using a different startup command][switch_back] for available options.
Useful in container orchestration environments where setting environment variables is easier than change command line parameters.
- `-e RESTARTABLE=yes` - Runs Jupyter in a loop so that quitting Jupyter does not cause the container to exit.
This may be useful when you need to install extensions that require restarting Jupyter.
Expand Down Expand Up @@ -130,7 +131,41 @@ For additional information about using SSL, see the following:

## Alternative Commands

### start.sh
### Switching back to classic notebook or using a different startup command

JupyterLab built on top of Jupyter Server is now the default for all images of the stack.
However, it is still possible to switch back to the classic notebook or to use a different startup command.
This can be done by setting the environment variable `JUPYTER_CMD` at container startup.
The table below shows some options.

| `JUPYTER_CMD` | Backend | Frontend |
| --------------- | ---------------- | ---------------- |
| `lab` (default) | Jupyter Server | JupyterLab |
| `notebook` | Jupyter Notebook | Jupyter Notebook |
| `nbclassic` | Jupyter Server | Jupyter Notebook |
| `server` | Jupyter Server | None |
| `retro`\* | Jupyter Server | RetroLab |

Notes:

- \*Not installed at this time, but it could be the case in the future or in a community stack.
- Any other valid `jupyter` command that starts the Jupyter server can be used.

Example:

```bash
# Run Jupyter Notebook classic
docker run -it --rm -p 8888:8888 -e JUPYTER_CMD=notebook \
jupyter/base-notebook
# Executing the command: jupyter notebook ...

# Run Jupyter Notebook on Jupyter Server
docker run -it --rm -p 8888:8888 -e JUPYTER_CMD=nbclassic
jupyter/base-notebook
# Executing the command: jupyter nbclassic ...
```

### `start.sh`

The `start-notebook.sh` script actually inherits most of its option handling capability from a more generic `start.sh` script.
The `start.sh` script supports all of the features described above, but allows you to specify an arbitrary command to execute.
Expand Down Expand Up @@ -196,3 +231,5 @@ mamba install --quiet --yes humanize && \
fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}"
```

[switch_back]: common.html#switching-back-to-classic-notebook-or-using-a-different-startup-command
8 changes: 0 additions & 8 deletions docs/using/recipes.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,14 +137,6 @@ ENV PATH "${CONDA_DIR}/envs/${conda_env}/bin:${PATH}"
# ENV CONDA_DEFAULT_ENV ${conda_env}
```

## Run JupyterLab

JupyterLab is preinstalled as a notebook extension starting in tag
[c33a7dc0eece](https://github.com/jupyter/docker-stacks/pull/355).

Run jupyterlab using a command such as
`docker run -it --rm -p 8888:8888 -e JUPYTER_ENABLE_LAB=yes jupyter/datascience-notebook`

## Dask JupyterLab Extension

[Dask JupyterLab Extension](https://github.com/dask/dask-labextension) provides a JupyterLab extension to manage Dask clusters, as well as embed Dask's dashboard plots directly into JupyterLab panes.
Expand Down
10 changes: 0 additions & 10 deletions examples/openshift/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,16 +127,6 @@ To delete the notebook instance, run `oc delete` using a label selector for the
oc delete all,configmap --selector app=mynotebook
```

## Enabling Jupyter Lab Interface

To enable the Jupyter Lab interface for a deployed notebook set the `JUPYTER_ENABLE_LAB` environment variable.

```bash
oc set env dc/mynotebook JUPYTER_ENABLE_LAB=true
```

Setting the environment variable will trigger a new deployment and the Jupyter Lab interface will be enabled.

## Adding Persistent Storage

You can upload notebooks and other files using the web interface of the notebook.
Expand Down