Parameterize healthcheck by internal port (#1859)

* Use the JUPYTER_PORT environment variable to configure server port

- Remove port setting in jupyter_server_config.py
- Declare the $JUPYTER_PORT env on the base Dockerfile
- Use it for HEALTHCHECK

* Add test case for JUPYTER_PORT env variable

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Update documentation

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Update style

* Better wording

* Better wording

* Add test for custom internal port

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Parametrize internal port test case

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Try to fix test

* Better tests

Co-authored-by: Muhammad Aji Muharrom <ajimuharrom@uchicago.edu>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Ayaz Salikhov <mathbunnyru@users.noreply.github.com>
Co-authored-by: Ayaz Salikhov <mathbunnyru@gmail.com>
This commit is contained in:
Muhammad Aji Muharrom
2023-01-24 01:19:39 -06:00
committed by GitHub
parent e014bb8ec5
commit 0d324bc0b3
5 changed files with 51 additions and 5 deletions

View File

@@ -47,7 +47,8 @@ RUN mamba install --quiet --yes \
fix-permissions "${CONDA_DIR}" && \ fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}" fix-permissions "/home/${NB_USER}"
EXPOSE 8888 ENV JUPYTER_PORT=8888
EXPOSE $JUPYTER_PORT
# Configure container startup # Configure container startup
CMD ["start-notebook.sh"] CMD ["start-notebook.sh"]
@@ -70,7 +71,7 @@ RUN sed -re "s/c.ServerApp/c.NotebookApp/g" \
# https://github.com/jupyter/docker-stacks/issues/915#issuecomment-1068528799 # https://github.com/jupyter/docker-stacks/issues/915#issuecomment-1068528799
HEALTHCHECK --interval=5s --timeout=3s --start-period=5s --retries=3 \ HEALTHCHECK --interval=5s --timeout=3s --start-period=5s --retries=3 \
CMD wget -O- --no-verbose --tries=1 --no-check-certificate \ CMD wget -O- --no-verbose --tries=1 --no-check-certificate \
http${GEN_CERT:+s}://localhost:8888${JUPYTERHUB_SERVICE_PREFIX:-/}api || exit 1 http${GEN_CERT:+s}://localhost:${JUPYTER_PORT}${JUPYTERHUB_SERVICE_PREFIX:-/}api || exit 1
# Switch back to jovyan to avoid accidental container runs as root # Switch back to jovyan to avoid accidental container runs as root
USER ${NB_UID} USER ${NB_UID}

View File

@@ -9,7 +9,6 @@ from jupyter_core.paths import jupyter_data_dir
c = get_config() # noqa: F821 c = get_config() # noqa: F821
c.ServerApp.ip = "0.0.0.0" c.ServerApp.ip = "0.0.0.0"
c.ServerApp.port = 8888
c.ServerApp.open_browser = False c.ServerApp.open_browser = False
# to output both image/svg+xml and application/pdf plot formats in the notebook file # to output both image/svg+xml and application/pdf plot formats in the notebook file

View File

@@ -22,10 +22,16 @@ You can pass [Jupyter server options](https://jupyter-server.readthedocs.io/en/l
2. To set the [base URL](https://jupyter-server.readthedocs.io/en/latest/operators/public-server.html#running-the-notebook-with-a-customized-url-prefix) of the notebook server, you can run the following: 2. To set the [base URL](https://jupyter-server.readthedocs.io/en/latest/operators/public-server.html#running-the-notebook-with-a-customized-url-prefix) of the notebook server, you can run the following:
```bash ```bash
docker run -it --rm -p 8888:8888 jupyter/base-notebook \ docker run -it --rm -p 8888:8888 --no-healthcheck jupyter/base-notebook \
start-notebook.sh --NotebookApp.base_url=/customized/url/prefix/ start-notebook.sh --NotebookApp.base_url=/customized/url/prefix/
``` ```
Note: We pass the `--no-healthcheck` parameter when setting a custom `base_url` for the Jupyter server,
because our current implementation for doing healthcheck assumes the `base_url` to be `/` (the default).
Without using this parameter, the container may run, but it's state will be "unhealthy".
Alternatively, you can [use your own command for healthcheck](https://docs.docker.com/engine/reference/run/#healthcheck)
using the `--health-cmd` parameter.
## Docker Options ## Docker Options
You may instruct the `start-notebook.sh` script to customize the container environment before launching the notebook server. You may instruct the `start-notebook.sh` script to customize the container environment before launching the notebook server.
@@ -123,6 +129,8 @@ You do so by passing arguments to the `docker run` command.
The variables are unset after the hooks have been executed but before the command provided to the startup script runs. The variables are unset after the hooks have been executed but before the command provided to the startup script runs.
- `-e NOTEBOOK_ARGS="--log-level='DEBUG' --dev-mode"` - Adds custom options to add to `jupyter` commands. - `-e NOTEBOOK_ARGS="--log-level='DEBUG' --dev-mode"` - Adds custom options to add to `jupyter` commands.
This way, the user could use any option supported by `jupyter` subcommand. This way, the user could use any option supported by `jupyter` subcommand.
- `-e JUPYTER_PORT=8117` - Changes the port in the container that Jupyter is using to the value of the `${JUPYTER_PORT}` environment variable.
This may be useful if you run multiple instances of Jupyter in swarm mode and want to use a different port for each instance.
## Startup Hooks ## Startup Hooks

View File

@@ -78,3 +78,39 @@ def test_unsigned_ssl(
assert "ERROR" not in logs assert "ERROR" not in logs
warnings = TrackedContainer.get_warnings(logs) warnings = TrackedContainer.get_warnings(logs)
assert not warnings assert not warnings
@pytest.mark.parametrize(
"env",
[
{},
{"JUPYTER_PORT": 1234, "DOCKER_STACKS_JUPYTER_CMD": "lab"},
{"JUPYTER_PORT": 2345, "DOCKER_STACKS_JUPYTER_CMD": "notebook"},
{"JUPYTER_PORT": 3456, "DOCKER_STACKS_JUPYTER_CMD": "server"},
{"JUPYTER_PORT": 4567, "DOCKER_STACKS_JUPYTER_CMD": "nbclassic"},
{"JUPYTER_PORT": 5678, "RESTARTABLE": "yes"},
{"JUPYTER_PORT": 6789},
{"JUPYTER_PORT": 7890, "DOCKER_STACKS_JUPYTER_CMD": "notebook"},
],
)
def test_custom_internal_port(
container: TrackedContainer,
http_client: requests.Session,
env: dict[str, str],
) -> None:
"""Container should be accessible from the host
when using custom internal port"""
host_port = find_free_port()
internal_port = env.get("JUPYTER_PORT", 8888)
running_container = container.run_detached(
command=["start-notebook.sh", "--NotebookApp.token=''"],
environment=env,
ports={internal_port: host_port},
)
resp = http_client.get(f"http://localhost:{host_port}")
resp.raise_for_status()
logs = running_container.logs().decode("utf-8")
LOGGER.debug(logs)
assert "ERROR" not in logs
warnings = TrackedContainer.get_warnings(logs)
assert not warnings

View File

@@ -17,10 +17,12 @@ LOGGER = logging.getLogger(__name__)
[ [
None, None,
["DOCKER_STACKS_JUPYTER_CMD=lab"], ["DOCKER_STACKS_JUPYTER_CMD=lab"],
["RESTARTABLE=yes"],
["DOCKER_STACKS_JUPYTER_CMD=notebook"], ["DOCKER_STACKS_JUPYTER_CMD=notebook"],
["DOCKER_STACKS_JUPYTER_CMD=server"], ["DOCKER_STACKS_JUPYTER_CMD=server"],
["DOCKER_STACKS_JUPYTER_CMD=nbclassic"], ["DOCKER_STACKS_JUPYTER_CMD=nbclassic"],
["RESTARTABLE=yes"],
["JUPYTER_PORT=8171"],
["JUPYTER_PORT=8117", "DOCKER_STACKS_JUPYTER_CMD=notebook"],
], ],
) )
def test_health(container: TrackedContainer, env: Optional[list[str]]) -> None: def test_health(container: TrackedContainer, env: Optional[list[str]]) -> None: