init
This commit is contained in:
75
spawnerdockerfile/Dockerfile
Normal file
75
spawnerdockerfile/Dockerfile
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
# Copyright (c) Jupyter Development Team.
|
||||||
|
# Distributed under the terms of the Modified BSD License.
|
||||||
|
ARG REGISTRY=quay.io
|
||||||
|
ARG OWNER=jupyter
|
||||||
|
ARG BASE_CONTAINER=$REGISTRY/$OWNER/docker-stacks-foundation
|
||||||
|
FROM $BASE_CONTAINER
|
||||||
|
|
||||||
|
LABEL maintainer="Jupyter Project <jupyter@googlegroups.com>"
|
||||||
|
|
||||||
|
# Fix: https://github.com/hadolint/hadolint/wiki/DL4006
|
||||||
|
# Fix: https://github.com/koalaman/shellcheck/wiki/SC3014
|
||||||
|
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||||
|
|
||||||
|
USER root
|
||||||
|
|
||||||
|
# Install all OS dependencies for the Server that starts but lacks all
|
||||||
|
# features (e.g., download as all possible file formats)
|
||||||
|
RUN apt-get update --yes && \
|
||||||
|
apt-get install --yes --no-install-recommends \
|
||||||
|
fonts-liberation \
|
||||||
|
# - pandoc is used to convert notebooks to html files
|
||||||
|
# it's not present in the aarch64 Ubuntu image, so we install it here
|
||||||
|
pandoc \
|
||||||
|
# - run-one - a wrapper script that runs no more
|
||||||
|
# than one unique instance of some command with a unique set of arguments,
|
||||||
|
# we use `run-one-constantly` to support the `RESTARTABLE` option
|
||||||
|
run-one && \
|
||||||
|
apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
USER ${NB_UID}
|
||||||
|
|
||||||
|
# Install JupyterLab, Jupyter Notebook, JupyterHub and NBClassic
|
||||||
|
# Generate a Jupyter Server config
|
||||||
|
# Cleanup temporary files
|
||||||
|
# Correct permissions
|
||||||
|
# Do all this in a single RUN command to avoid duplicating all of the
|
||||||
|
# files across image layers when the permissions change
|
||||||
|
WORKDIR /tmp
|
||||||
|
RUN mamba install --yes \
|
||||||
|
'jupyterlab' \
|
||||||
|
'notebook' \
|
||||||
|
'jupyterhub' \
|
||||||
|
'nbclassic' && \
|
||||||
|
jupyter server --generate-config && \
|
||||||
|
mamba clean --all -f -y && \
|
||||||
|
npm cache clean --force && \
|
||||||
|
jupyter lab clean && \
|
||||||
|
rm -rf "/home/${NB_USER}/.cache/yarn" && \
|
||||||
|
fix-permissions "${CONDA_DIR}" && \
|
||||||
|
fix-permissions "/home/${NB_USER}"
|
||||||
|
|
||||||
|
ENV JUPYTER_PORT=8888
|
||||||
|
EXPOSE $JUPYTER_PORT
|
||||||
|
|
||||||
|
# Configure container startup
|
||||||
|
CMD ["start-notebook.py"]
|
||||||
|
|
||||||
|
# Copy local files as late as possible to avoid cache busting
|
||||||
|
COPY start-notebook.py start-notebook.sh start-singleuser.py start-singleuser.sh /usr/local/bin/
|
||||||
|
COPY jupyter_server_config.py docker_healthcheck.py /etc/jupyter/
|
||||||
|
|
||||||
|
# Fix permissions on /etc/jupyter as root
|
||||||
|
USER root
|
||||||
|
RUN fix-permissions /etc/jupyter/
|
||||||
|
|
||||||
|
# HEALTHCHECK documentation: https://docs.docker.com/engine/reference/builder/#healthcheck
|
||||||
|
# This healtcheck works well for `lab`, `notebook`, `nbclassic`, `server`, and `retro` jupyter commands
|
||||||
|
# https://github.com/jupyter/docker-stacks/issues/915#issuecomment-1068528799
|
||||||
|
HEALTHCHECK --interval=5s --timeout=3s --start-period=5s --retries=3 \
|
||||||
|
CMD /etc/jupyter/docker_healthcheck.py || exit 1
|
||||||
|
|
||||||
|
# Switch back to jovyan to avoid accidental container runs as root
|
||||||
|
USER ${NB_UID}
|
||||||
|
|
||||||
|
WORKDIR "${HOME}"
|
||||||
23
spawnerdockerfile/README.md
Normal file
23
spawnerdockerfile/README.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Base Jupyter Notebook Stack
|
||||||
|
|
||||||
|
> **Images hosted on Docker Hub are no longer updated. Please, use [quay.io image](https://quay.io/repository/jupyter/base-notebook)**
|
||||||
|
|
||||||
|
[](https://hub.docker.com/r/jupyter/base-notebook/)
|
||||||
|
[](https://hub.docker.com/r/jupyter/base-notebook/)
|
||||||
|
[](https://hub.docker.com/r/jupyter/base-notebook/ "jupyter/base-notebook image size")
|
||||||
|
|
||||||
|
GitHub Actions in the <https://github.com/jupyter/docker-stacks> project builds and pushes this image to the Registry.
|
||||||
|
|
||||||
|
Please visit the project documentation site for help to use and contribute to this image and others.
|
||||||
|
|
||||||
|
- [Jupyter Docker Stacks on ReadTheDocs](https://jupyter-docker-stacks.readthedocs.io/en/latest/index.html)
|
||||||
|
- [Selecting an Image :: Core Stacks :: jupyter/base-notebook](https://jupyter-docker-stacks.readthedocs.io/en/latest/using/selecting.html#jupyter-base-notebook)
|
||||||
|
|
||||||
|
# 构建docker-compose spawner镜像的Dockerfile
|
||||||
|
|
||||||
|
构建基[础镜像参考](https://github.com/jupyter/docker-stacks)
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cp docker-stacks/images/base-notebook/* ./spawnerdockerfile/
|
||||||
|
docker buildx build -t hotwa/notebook:latest . -f Dockerfile.base-notebook --load
|
||||||
|
```
|
||||||
26
spawnerdockerfile/docker_healthcheck.py
Executable file
26
spawnerdockerfile/docker_healthcheck.py
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# Copyright (c) Jupyter Development Team.
|
||||||
|
# Distributed under the terms of the Modified BSD License.
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
# Several operations below deliberately don't check for possible errors
|
||||||
|
# As this is a healthcheck, it should succeed or raise an exception on error
|
||||||
|
|
||||||
|
runtime_dir = Path("/home/") / os.environ["NB_USER"] / ".local/share/jupyter/runtime/"
|
||||||
|
json_file = next(runtime_dir.glob("*server-*.json"))
|
||||||
|
|
||||||
|
url = json.loads(json_file.read_bytes())["url"]
|
||||||
|
url = url + "api"
|
||||||
|
|
||||||
|
proxies = {
|
||||||
|
"http": "",
|
||||||
|
"https": "",
|
||||||
|
}
|
||||||
|
|
||||||
|
r = requests.get(url, proxies=proxies, verify=False) # request without SSL verification
|
||||||
|
r.raise_for_status()
|
||||||
|
print(r.content)
|
||||||
58
spawnerdockerfile/jupyter_server_config.py
Normal file
58
spawnerdockerfile/jupyter_server_config.py
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# Copyright (c) Jupyter Development Team.
|
||||||
|
# Distributed under the terms of the Modified BSD License.
|
||||||
|
# mypy: ignore-errors
|
||||||
|
import os
|
||||||
|
import stat
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from jupyter_core.paths import jupyter_data_dir
|
||||||
|
|
||||||
|
c = get_config() # noqa: F821
|
||||||
|
c.ServerApp.ip = "0.0.0.0"
|
||||||
|
c.ServerApp.open_browser = False
|
||||||
|
|
||||||
|
# to output both image/svg+xml and application/pdf plot formats in the notebook file
|
||||||
|
c.InlineBackend.figure_formats = {"png", "jpeg", "svg", "pdf"}
|
||||||
|
|
||||||
|
# https://github.com/jupyter/notebook/issues/3130
|
||||||
|
c.FileContentsManager.delete_to_trash = False
|
||||||
|
|
||||||
|
# Generate a self-signed certificate
|
||||||
|
OPENSSL_CONFIG = """\
|
||||||
|
[req]
|
||||||
|
distinguished_name = req_distinguished_name
|
||||||
|
[req_distinguished_name]
|
||||||
|
"""
|
||||||
|
if "GEN_CERT" in os.environ:
|
||||||
|
dir_name = Path(jupyter_data_dir())
|
||||||
|
dir_name.mkdir(parents=True, exist_ok=True)
|
||||||
|
pem_file = dir_name / "notebook.pem"
|
||||||
|
|
||||||
|
# Generate an openssl.cnf file to set the distinguished name
|
||||||
|
cnf_file = Path(os.getenv("CONDA_DIR", "/usr/lib")) / "ssl/openssl.cnf"
|
||||||
|
if not cnf_file.exists():
|
||||||
|
cnf_file.write_text(OPENSSL_CONFIG)
|
||||||
|
|
||||||
|
# Generate a certificate if one doesn't exist on a disk
|
||||||
|
subprocess.check_call(
|
||||||
|
[
|
||||||
|
"openssl",
|
||||||
|
"req",
|
||||||
|
"-new",
|
||||||
|
"-newkey=rsa:2048",
|
||||||
|
"-days=365",
|
||||||
|
"-nodes",
|
||||||
|
"-x509",
|
||||||
|
"-subj=/C=XX/ST=XX/L=XX/O=generated/CN=generated",
|
||||||
|
f"-keyout={pem_file}",
|
||||||
|
f"-out={pem_file}",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
# Restrict access to the file
|
||||||
|
pem_file.chmod(stat.S_IRUSR | stat.S_IWUSR)
|
||||||
|
c.ServerApp.certfile = str(pem_file)
|
||||||
|
|
||||||
|
# Change default umask for all subprocesses of the Server if set in the environment
|
||||||
|
if "NB_UMASK" in os.environ:
|
||||||
|
os.umask(int(os.environ["NB_UMASK"], 8))
|
||||||
41
spawnerdockerfile/start-notebook.py
Executable file
41
spawnerdockerfile/start-notebook.py
Executable file
@@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# Copyright (c) Jupyter Development Team.
|
||||||
|
# Distributed under the terms of the Modified BSD License.
|
||||||
|
import os
|
||||||
|
import shlex
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# If we are in a JupyterHub, we pass on to `start-singleuser.py` instead so it does the right thing
|
||||||
|
if "JUPYTERHUB_API_TOKEN" in os.environ:
|
||||||
|
print(
|
||||||
|
"WARNING: using start-singleuser.py instead of start-notebook.py to start a server associated with JupyterHub."
|
||||||
|
)
|
||||||
|
command = ["/usr/local/bin/start-singleuser.py"] + sys.argv[1:]
|
||||||
|
os.execvp(command[0], command)
|
||||||
|
|
||||||
|
|
||||||
|
# Wrap everything in start.sh, no matter what
|
||||||
|
command = ["/usr/local/bin/start.sh"]
|
||||||
|
|
||||||
|
# If we want to survive restarts, tell that to start.sh
|
||||||
|
if os.environ.get("RESTARTABLE") == "yes":
|
||||||
|
command.append("run-one-constantly")
|
||||||
|
|
||||||
|
# We always launch a jupyter subcommand from this script
|
||||||
|
command.append("jupyter")
|
||||||
|
|
||||||
|
# Launch the configured subcommand. Note that this should be a single string, so we don't split it
|
||||||
|
# We default to lab
|
||||||
|
jupyter_command = os.environ.get("DOCKER_STACKS_JUPYTER_CMD", "lab")
|
||||||
|
command.append(jupyter_command)
|
||||||
|
|
||||||
|
# Append any optional NOTEBOOK_ARGS we were passed in. This is supposed to be multiple args passed
|
||||||
|
# on to the notebook command, so we split it correctly with shlex
|
||||||
|
if "NOTEBOOK_ARGS" in os.environ:
|
||||||
|
command += shlex.split(os.environ["NOTEBOOK_ARGS"])
|
||||||
|
|
||||||
|
# Pass through any other args we were passed on the command line
|
||||||
|
command += sys.argv[1:]
|
||||||
|
|
||||||
|
# Execute the command!
|
||||||
|
os.execvp(command[0], command)
|
||||||
5
spawnerdockerfile/start-notebook.sh
Executable file
5
spawnerdockerfile/start-notebook.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Shim to emit warning and call start-notebook.py
|
||||||
|
echo "WARNING: Use start-notebook.py instead"
|
||||||
|
|
||||||
|
exec /usr/local/bin/start-notebook.py "$@"
|
||||||
23
spawnerdockerfile/start-singleuser.py
Executable file
23
spawnerdockerfile/start-singleuser.py
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# Copyright (c) Jupyter Development Team.
|
||||||
|
# Distributed under the terms of the Modified BSD License.
|
||||||
|
import os
|
||||||
|
import shlex
|
||||||
|
import sys
|
||||||
|
|
||||||
|
command = ["/usr/local/bin/start.sh", "jupyterhub-singleuser"]
|
||||||
|
|
||||||
|
# set default ip to 0.0.0.0
|
||||||
|
if "--ip=" not in os.environ.get("NOTEBOOK_ARGS", ""):
|
||||||
|
command.append("--ip=0.0.0.0")
|
||||||
|
|
||||||
|
# Append any optional NOTEBOOK_ARGS we were passed in. This is supposed to be multiple args passed
|
||||||
|
# on to the notebook command, so we split it correctly with shlex
|
||||||
|
if "NOTEBOOK_ARGS" in os.environ:
|
||||||
|
command += shlex.split(os.environ["NOTEBOOK_ARGS"])
|
||||||
|
|
||||||
|
# Pass any other args we have been passed through
|
||||||
|
command += sys.argv[1:]
|
||||||
|
|
||||||
|
# Execute the command!
|
||||||
|
os.execvp(command[0], command)
|
||||||
5
spawnerdockerfile/start-singleuser.sh
Executable file
5
spawnerdockerfile/start-singleuser.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Shim to emit warning and call start-singleuser.py
|
||||||
|
echo "WARNING: Use start-singleuser.py instead"
|
||||||
|
|
||||||
|
exec /usr/local/bin/start-singleuser.py "$@"
|
||||||
Reference in New Issue
Block a user