Showing preview only (548K chars total). Download the full file or copy to clipboard to get everything.
Repository: jupyter/docker-stacks
Branch: main
Commit: 6da149350f01
Files: 273
Total size: 487.0 KB
Directory structure:
gitextract_w6y_9n58/
├── .devcontainer/
│ ├── Dockerfile
│ └── devcontainer.json
├── .flake8
├── .gitattributes
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── blank.yml
│ │ ├── bug_report.yml
│ │ ├── config.yml
│ │ └── feature_request.yml
│ ├── actions/
│ │ ├── apply-single-tags/
│ │ │ └── action.yml
│ │ ├── create-dev-env/
│ │ │ └── action.yml
│ │ ├── free-disk-space/
│ │ │ └── action.yml
│ │ └── load-image/
│ │ └── action.yml
│ ├── dependabot.yml
│ ├── pull_request_template.md
│ └── workflows/
│ ├── contributed-recipes.yml
│ ├── docker-build-test-upload.yml
│ ├── docker-tag-merge.yml
│ ├── docker-tag-push-merge.yml
│ ├── docker-tag-push.yml
│ ├── docker-wiki-update.yml
│ ├── docker.yml
│ ├── pre-commit.yml
│ ├── registry-move.yml
│ ├── registry-overviews.yml
│ └── sphinx.yml
├── .gitignore
├── .hadolint.yaml
├── .markdownlint.yaml
├── .pre-commit-config.yaml
├── .readthedocs.yaml
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE.md
├── Makefile
├── README.md
├── SECURITY.md
├── binder/
│ ├── Dockerfile
│ └── README.ipynb
├── docs/
│ ├── conf.py
│ ├── contributing/
│ │ ├── features.md
│ │ ├── issues.md
│ │ ├── lint.md
│ │ ├── packages.md
│ │ ├── recipes.md
│ │ ├── stacks.md
│ │ └── tests.md
│ ├── index.rst
│ ├── maintaining/
│ │ ├── new-images-and-packages-policy.md
│ │ ├── tagging.md
│ │ ├── tagging_examples/
│ │ │ ├── docker_runner.py
│ │ │ └── git_helper.py
│ │ └── tasks.md
│ ├── requirements.txt
│ └── using/
│ ├── changelog.md
│ ├── common.md
│ ├── custom-images.md
│ ├── faq.md
│ ├── recipe_code/
│ │ ├── custom_environment.dockerfile
│ │ ├── dask_jupyterlab.dockerfile
│ │ ├── docker-bake.custom-python.hcl
│ │ ├── generate_matrix.py
│ │ ├── ijavascript.dockerfile
│ │ ├── jupyterhub_version.dockerfile
│ │ ├── mamba_install.dockerfile
│ │ ├── manpage_install.dockerfile
│ │ ├── microsoft_odbc.dockerfile
│ │ ├── oracledb.dockerfile
│ │ ├── pip_install.dockerfile
│ │ ├── requirements.txt
│ │ ├── rise_jupyterlab.dockerfile
│ │ ├── spellcheck_notebook_v6.dockerfile
│ │ └── xgboost.dockerfile
│ ├── recipes.md
│ ├── running.md
│ ├── selecting.md
│ ├── specifics.md
│ └── troubleshooting.md
├── examples/
│ ├── README.md
│ ├── docker-compose/
│ │ ├── README.md
│ │ ├── bin/
│ │ │ ├── letsencrypt.sh
│ │ │ ├── sl-dns.sh
│ │ │ ├── softlayer.sh
│ │ │ └── vbox.sh
│ │ └── notebook/
│ │ ├── Dockerfile
│ │ ├── build.sh
│ │ ├── down.sh
│ │ ├── env.sh
│ │ ├── letsencrypt-notebook.yml
│ │ ├── notebook.yml
│ │ ├── secure-notebook.yml
│ │ └── up.sh
│ ├── make-deploy/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── letsencrypt.makefile
│ │ ├── self-signed.makefile
│ │ ├── softlayer.makefile
│ │ └── virtualbox.makefile
│ ├── openshift/
│ │ ├── README.md
│ │ └── templates.json
│ └── source-to-image/
│ ├── README.md
│ ├── assemble
│ ├── run
│ ├── save-artifacts
│ └── templates.json
├── images/
│ ├── all-spark-notebook/
│ │ ├── .dockerignore
│ │ ├── Dockerfile
│ │ └── README.md
│ ├── base-notebook/
│ │ ├── .dockerignore
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── docker_healthcheck.py
│ │ ├── jupyter_server_config.py
│ │ ├── start-notebook.py
│ │ ├── start-notebook.sh
│ │ ├── start-singleuser.py
│ │ └── start-singleuser.sh
│ ├── datascience-notebook/
│ │ ├── .dockerignore
│ │ ├── Dockerfile
│ │ └── README.md
│ ├── docker-stacks-foundation/
│ │ ├── .dockerignore
│ │ ├── 10activate-conda-env.sh
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── fix-permissions
│ │ ├── initial-condarc
│ │ ├── run-hooks.sh
│ │ └── start.sh
│ ├── julia-notebook/
│ │ ├── .dockerignore
│ │ ├── Dockerfile
│ │ └── README.md
│ ├── minimal-notebook/
│ │ ├── .dockerignore
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── Rprofile.site
│ │ └── setup-scripts/
│ │ ├── activate_notebook_custom_env.py
│ │ ├── setup-julia-packages.bash
│ │ └── setup_julia.py
│ ├── pyspark-notebook/
│ │ ├── .dockerignore
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── ipython_kernel_config.py
│ │ └── setup_spark.py
│ ├── pytorch-notebook/
│ │ ├── .dockerignore
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── cuda12/
│ │ │ └── Dockerfile
│ │ └── cuda13/
│ │ └── Dockerfile
│ ├── r-notebook/
│ │ ├── .dockerignore
│ │ ├── Dockerfile
│ │ └── README.md
│ ├── scipy-notebook/
│ │ ├── .dockerignore
│ │ ├── Dockerfile
│ │ └── README.md
│ └── tensorflow-notebook/
│ ├── .dockerignore
│ ├── Dockerfile
│ ├── README.md
│ └── cuda/
│ ├── 20tensorboard-proxy-env.sh
│ ├── Dockerfile
│ └── nvidia-lib-dirs.sh
├── mypy.ini
├── requirements-dev.txt
├── tagging/
│ ├── README.md
│ ├── __init__.py
│ ├── apps/
│ │ ├── __init__.py
│ │ ├── apply_tags.py
│ │ ├── common_cli_arguments.py
│ │ ├── config.py
│ │ ├── merge_tags.py
│ │ ├── write_manifest.py
│ │ └── write_tags_file.py
│ ├── hierarchy/
│ │ ├── __init__.py
│ │ ├── get_manifests.py
│ │ ├── get_taggers.py
│ │ └── images_hierarchy.py
│ ├── manifests/
│ │ ├── __init__.py
│ │ ├── apt_packages.py
│ │ ├── build_info.py
│ │ ├── conda_environment.py
│ │ ├── julia_packages.py
│ │ ├── manifest_interface.py
│ │ ├── r_packages.py
│ │ └── spark_info.py
│ ├── taggers/
│ │ ├── __init__.py
│ │ ├── date.py
│ │ ├── sha.py
│ │ ├── tagger_interface.py
│ │ ├── ubuntu_version.py
│ │ └── versions.py
│ └── utils/
│ ├── __init__.py
│ ├── docker_runner.py
│ ├── get_platform.py
│ ├── get_prefix.py
│ ├── git_helper.py
│ └── quoted_output.py
├── tests/
│ ├── README.md
│ ├── __init__.py
│ ├── by_image/
│ │ ├── all-spark-notebook/
│ │ │ ├── data/
│ │ │ │ ├── local_sparkR.ipynb
│ │ │ │ └── local_sparklyr.ipynb
│ │ │ └── test_spark_r_nbconvert.py
│ │ ├── base-notebook/
│ │ │ ├── data/
│ │ │ │ └── check_listening.py
│ │ │ ├── test_container_options.py
│ │ │ ├── test_healthcheck.py
│ │ │ ├── test_ips.py
│ │ │ ├── test_notebook.py
│ │ │ ├── test_pandoc.py
│ │ │ └── test_start_container.py
│ │ ├── datascience-notebook/
│ │ │ ├── test_julia_datascience.py
│ │ │ ├── test_mimetypes.py
│ │ │ └── test_pluto_datascience.py
│ │ ├── docker-stacks-foundation/
│ │ │ ├── data/
│ │ │ │ └── run-hooks/
│ │ │ │ ├── change/
│ │ │ │ │ ├── a.sh
│ │ │ │ │ ├── b.sh
│ │ │ │ │ └── c.sh
│ │ │ │ ├── executables/
│ │ │ │ │ ├── executable.py
│ │ │ │ │ ├── non_executable.py
│ │ │ │ │ └── run-me.sh
│ │ │ │ ├── failures/
│ │ │ │ │ ├── a.sh
│ │ │ │ │ ├── b.py
│ │ │ │ │ ├── c.sh
│ │ │ │ │ └── d.sh
│ │ │ │ ├── sh-files/
│ │ │ │ │ ├── executable.sh
│ │ │ │ │ └── non-executable.sh
│ │ │ │ └── unset/
│ │ │ │ ├── a.sh
│ │ │ │ ├── b.sh
│ │ │ │ └── c.sh
│ │ │ ├── test_outdated.py
│ │ │ ├── test_package_managers.py
│ │ │ ├── test_packages.py
│ │ │ ├── test_python_version.py
│ │ │ ├── test_run_hooks.py
│ │ │ ├── test_units.py
│ │ │ └── test_user_options.py
│ │ ├── julia-notebook/
│ │ │ ├── test_julia.py
│ │ │ └── test_pluto.py
│ │ ├── minimal-notebook/
│ │ │ ├── data/
│ │ │ │ ├── notebook_math.ipynb
│ │ │ │ └── notebook_svg.ipynb
│ │ │ └── test_nbconvert.py
│ │ ├── pyspark-notebook/
│ │ │ ├── data/
│ │ │ │ ├── issue_1168.ipynb
│ │ │ │ └── local_pyspark.ipynb
│ │ │ ├── test_spark.py
│ │ │ ├── test_spark_nbconvert.py
│ │ │ └── units/
│ │ │ ├── unit_pandas_version.py
│ │ │ └── unit_spark.py
│ │ ├── pytorch-notebook/
│ │ │ └── units/
│ │ │ └── unit_pytorch.py
│ │ ├── r-notebook/
│ │ │ └── test_R_mimetypes.py
│ │ ├── scipy-notebook/
│ │ │ ├── data/
│ │ │ │ ├── cython/
│ │ │ │ │ ├── helloworld.pyx
│ │ │ │ │ └── setup.py
│ │ │ │ └── matplotlib/
│ │ │ │ ├── matplotlib_1.py
│ │ │ │ └── matplotlib_fonts_1.py
│ │ │ ├── test_cython.py
│ │ │ ├── test_extensions.py
│ │ │ ├── test_matplotlib.py
│ │ │ └── units/
│ │ │ └── unit_pandas.py
│ │ └── tensorflow-notebook/
│ │ └── units/
│ │ └── unit_tensorflow.py
│ ├── conftest.py
│ ├── hierarchy/
│ │ ├── __init__.py
│ │ ├── get_test_dirs.py
│ │ └── images_hierarchy.py
│ ├── pytest.ini
│ ├── run_tests.py
│ ├── shared_checks/
│ │ ├── R_mimetype_check.py
│ │ ├── __init__.py
│ │ ├── nbconvert_check.py
│ │ └── pluto_check.py
│ └── utils/
│ ├── __init__.py
│ ├── conda_package_helper.py
│ └── tracked_container.py
└── wiki/
├── Home.md
├── __init__.py
├── config.py
├── manifest_time.py
└── update_wiki.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .devcontainer/Dockerfile
================================================
FROM mcr.microsoft.com/devcontainers/python:3.13
COPY requirements-dev.txt /tmp/requirements-dev.txt
COPY docs/requirements.txt /tmp/requirements-docs.txt
RUN pip install --no-cache-dir -r /tmp/requirements-dev.txt && \
pip install --no-cache-dir -r /tmp/requirements-docs.txt
================================================
FILE: .devcontainer/devcontainer.json
================================================
{
"name": "Jupyter Docker Stacks",
"build": {
"context": "..",
"dockerfile": "Dockerfile"
},
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {
"moby": false
}
},
"postCreateCommand": "pre-commit install --install-hooks",
"customizations": {
"vscode": {
"extensions": [
"github.copilot-chat",
"github.copilot",
"github.vscode-github-actions",
"github.vscode-pull-request-github",
"ms-azuretools.vscode-containers",
"ms-azuretools.vscode-docker",
"ms-python.autopep8",
"ms-vscode.makefile-tools"
]
}
}
}
================================================
FILE: .flake8
================================================
[flake8]
max-line-length = 88
select = C, E, F, W, B, B950
extend-ignore = E203, E501, E704, W503
================================================
FILE: .gitattributes
================================================
* text=auto eol=lf
================================================
FILE: .github/ISSUE_TEMPLATE/blank.yml
================================================
name: "(maintainers only) Blank issue"
description: For maintainers only
labels: []
body:
- type: markdown
attributes:
value: |
This is a blank issue template for maintainers to use as needed.
- type: checkboxes
attributes:
label: Are you a maintainer?
description: Please confirm you are a maintainer before proceeding.
options:
- label: Yes, I am a maintainer
required: true
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yml
================================================
name: Bug report
description: Create a report to help us improve
labels: ["type:Bug"]
body:
- type: markdown
attributes:
value: |
Hi! Thanks for using the Jupyter Docker Stacks and taking some time to contribute to this project.
We'd appreciate it if you could check out the [Troubleshooting common problems](https://jupyter-docker-stacks.readthedocs.io/en/latest/using/troubleshooting.html) section in the documentation,
as well as [existing issues](https://github.com/jupyter/docker-stacks/issues?q=is%3Aissue) prior to submitting an issue to avoid duplication.
Please answer the following sections to help us troubleshoot the problem.
- type: dropdown
attributes:
label: What docker image(s) are you using?
description: Select as many images as applicable
multiple: true
options:
- all-spark-notebook
- base-notebook
- datascience-notebook
- docker-stacks-foundation
- julia-notebook
- minimal-notebook
- pyspark-notebook
- pytorch-notebook
- r-notebook
- scipy-notebook
- tensorflow-notebook
validations:
required: true
- type: input
attributes:
label: Host OS
placeholder: |
Example:
Ubuntu 24.04
validations:
required: true
- type: dropdown
attributes:
label: Host architecture
options:
- x86_64
- aarch64
validations:
required: true
- type: textarea
attributes:
label: What Docker command are you running?
description: |
What complete docker command do you run to launch the container (omitting sensitive values)?
placeholder: |
Example:
`docker run -it --rm -p 8888:8888 quay.io/jupyter/base-notebook`
validations:
required: true
- type: textarea
attributes:
label: How to Reproduce the problem?
description: Please provide steps to reproduce this bug (once the container is running).
placeholder: |
Example:
1. Visit <http://localhost:8888>
2. Start an R notebook
3. ...
validations:
required: true
- type: textarea
attributes:
label: Command output
render: bash session
description: |
Provide the output of the steps above, including the commands
themselves and Docker's output/traceback etc. If you're familiar with
Markdown, this block will have triple backticks added automatically
around it -- you don't have to add them.
If you want to present output from multiple commands, please present
that as a shell session (commands you run get prefixed with `$ `).
Please also ensure that the "How to reproduce" section contains matching
instructions for reproducing this.
- type: textarea
attributes:
label: Expected behavior
description: |
A clear and concise description of what you expected to happen.
placeholder: |
Example: `ggplot` output appears in my notebook.
- type: textarea
attributes:
label: Actual behavior
description: |
A clear and concise description of what the bug is.
placeholder: |
Example: No output is visible in the notebook and the Server log contains messages about ...
validations:
required: true
- type: textarea
attributes:
label: Anything else?
description: |
Links? References? Anything that will give us more context about the issue you are encountering!
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations:
required: false
- type: checkboxes
attributes:
label: Latest Docker version
description: You should try to use the latest Docker version
options:
- label: I've updated my Docker version to the latest available, and the issue persists
required: true
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: 📖 - Jupyter Docker Stacks documentation
url: https://jupyter-docker-stacks.readthedocs.io/en/latest/index.html
about: Go to the project's documentation
- name: 🔍 - Troubleshooting common problems
url: https://jupyter-docker-stacks.readthedocs.io/en/latest/using/troubleshooting.html
about: Documentation section on troubleshooting commonly encountered errors
- name: 💬 - Jupyter community Discourse
url: https://discourse.jupyter.org/
about: Interact with the rest of the Jupyter community
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.yml
================================================
name: Feature request
description: Suggest a new feature for this project
labels: ["type:Enhancement"]
body:
- type: markdown
attributes:
value: |
Hi! Thanks for using the Jupyter Docker Stacks and taking some time to contribute to this project.
We'd appreciate it if you could check out the [Suggesting a new feature](https://jupyter-docker-stacks.readthedocs.io/en/latest/contributing/features.html#suggesting-a-new-feature)
section in the documentation for our preferred processes before submitting a feature request.
- type: dropdown
attributes:
label: What docker image(s) is this feature applicable to?
description: Select as many images as applicable
multiple: true
options:
- all-spark-notebook
- base-notebook
- datascience-notebook
- docker-stacks-foundation
- julia-notebook
- minimal-notebook
- pyspark-notebook
- pytorch-notebook
- r-notebook
- scipy-notebook
- tensorflow-notebook
- new community stack
validations:
required: true
- type: textarea
attributes:
label: What change(s) are you proposing?
description: |
Be concise and feel free to add supporting links or references.
placeholder: |
Example:
- Add the [altair](https://altair-viz.github.io) package to the image.
validations:
required: true
- type: textarea
attributes:
label: How does this affect the user?
description: |
How will the proposed feature affect the user's workflow?
How will this feature make the image more robust, secure, etc.?
placeholder: |
Example:
- Altair is a declarative statistical visualization library for Python, based on Vega and Vega-Lite, and the source is available on GitHub.
- With Altair, you can spend more time understanding your data and its meaning.
- Altair's API is simple, friendly, and consistent and built on top of the powerful Vega-Lite visualization grammar.
- This elegant simplicity produces beautiful and effective visualizations with a minimal amount of code.
validations:
required: true
- type: textarea
attributes:
label: Anything else?
description: |
Links? References? Anything that will give us more context about the feature you are proposing.
validations:
required: false
================================================
FILE: .github/actions/apply-single-tags/action.yml
================================================
name: Apply single platform tags
description: Download the image tar, load it to Docker and apply tags to it
inputs:
image:
description: Image name
required: true
platform:
description: Image platform
required: true
variant:
description: Variant tag prefix
required: true
runs:
using: composite
steps:
- name: Load image to Docker 📥
uses: ./.github/actions/load-image
with:
image: ${{ inputs.image }}
platform: ${{ inputs.platform }}
variant: ${{ inputs.variant }}
- name: Download tags file 📥
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ inputs.platform }}-${{ inputs.variant }}-${{ inputs.image }}.txt
path: /tmp/jupyter/tags/
- name: Apply tags to the loaded image 🏷
run: |
python3 -m tagging.apps.apply_tags \
--registry ${{ env.REGISTRY }} \
--owner ${{ env.OWNER }} \
--image ${{ inputs.image }} \
--variant ${{ inputs.variant }} \
--platform ${{ inputs.platform }} \
--tags-dir /tmp/jupyter/tags/
shell: bash
- name: Upload SBOM for the image 🧾
uses: anchore/sbom-action@57aae528053a48a3f6235f2d9461b05fbcb7366d # v0.23.1
with:
image: ${{ env.REGISTRY }}/${{ env.OWNER }}/${{ inputs.image }}
artifact-name: ${{ inputs.image }}-${{ inputs.platform }}-${{ inputs.variant }}-sbom.spdx.json
upload-artifact-retention: 40
# This step is needed to prevent pushing non-multi-arch "latest" tag
- name: Remove the "latest" tag from the image 🗑️
run: docker image rmi ${{ env.REGISTRY }}/${{ env.OWNER }}/${{ inputs.image }}:latest
shell: bash
- name: Show Docker images 📦
run: docker image ls --all
shell: bash
================================================
FILE: .github/actions/create-dev-env/action.yml
================================================
name: Build environment
description: Create a build environment
runs:
using: composite
steps:
- name: Set Up Python 🐍
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: 3.12
- name: Install Dev Dependencies 📦
run: |
pip install --upgrade pip
pip install --upgrade -r requirements-dev.txt
shell: bash
# We need to have a recent docker version
# More info: https://github.com/jupyter/docker-stacks/pull/2255
# Can be removed after Docker Engine is updated
# https://github.com/actions/runner-images/issues/11766
- name: Set Up Docker 🐳
uses: docker/setup-docker-action@1a6edb0ba9ac496f6850236981f15d8f9a82254d # v5.0.0
with:
set-host: true
================================================
FILE: .github/actions/free-disk-space/action.yml
================================================
name: "Free Disk Space (Ubuntu)"
description: "A GitHub Action to free up disk space on an Ubuntu GitHub Actions runner."
runs:
using: "composite"
steps:
- name: Installing rmz
shell: bash
run: |
curl -fsSL --tlsv1.2 --proto '=https' https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash > /dev/null 2>&1
cargo binstall -qy rmz
ln -s ~/.cargo/bin/rmz /usr/local/bin/rmz
- name: Freeing up disk space
shell: bash
run: |
sudo rmz -f /usr/local/lib/android || true
sudo rmz -f /usr/share/dotnet || true
sudo rmz -f /opt/ghc /usr/local/.ghcup || true
sudo rmz -f /usr/share/swift || true
sudo rmz -f /usr/share/miniconda || true
sudo rmz -f "${AGENT_TOOLSDIRECTORY}" || true
================================================
FILE: .github/actions/load-image/action.yml
================================================
name: Load Docker image
description: Download the image tar and load it to Docker
inputs:
image:
description: Image name
required: true
platform:
description: Image platform
required: true
variant:
description: Variant tag prefix
required: true
runs:
using: composite
steps:
- name: Download built image 📥
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ inputs.image }}-${{ inputs.platform }}-${{ inputs.variant }}.tar.zst
path: /tmp/jupyter/images/
- name: Load downloaded image to docker 📥
run: |
zstd \
--uncompress \
--stdout \
--rm \
/tmp/jupyter/images/${{ inputs.image }}-${{ inputs.platform }}-${{ inputs.variant }}.tar.zst \
| docker load
shell: bash
- name: Show Docker images 📦
run: docker image ls --all
shell: bash
================================================
FILE: .github/dependabot.yml
================================================
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference
# We're adding `[FAST_BUILD]` prefix to commit messages (this adds it to PR title)
# This triggers a faster build, see more info in `.github/workflows/docker.yml`
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
commit-message:
prefix: "[FAST_BUILD] "
- package-ecosystem: github-actions
directory: .github/actions/apply-single-tags/
schedule:
interval: weekly
commit-message:
prefix: "[FAST_BUILD] "
- package-ecosystem: github-actions
directory: .github/actions/create-dev-env/
schedule:
interval: weekly
commit-message:
prefix: "[FAST_BUILD] "
# This action is only used for some images, so full build is required
- package-ecosystem: github-actions
directory: .github/actions/free-disk-space/
schedule:
interval: weekly
- package-ecosystem: github-actions
directory: .github/actions/load-image/
schedule:
interval: weekly
commit-message:
prefix: "[FAST_BUILD] "
================================================
FILE: .github/pull_request_template.md
================================================
## Describe your changes
## Issue ticket if applicable
<!-- Example - Fix: https://github.com/jupyter/docker-stacks/issues/0 -->
## Checklist (especially for first-time contributors)
- [ ] I have performed a self-review of my code
- [ ] If it is a core feature, I have added thorough tests
- [ ] I will try not to use force-push to make the review process easier for reviewers
- [ ] I have updated the documentation for significant changes
<!-- markdownlint-disable-file MD041 -->
================================================
FILE: .github/workflows/contributed-recipes.yml
================================================
name: Test the contributed recipes
env:
REGISTRY: quay.io
OWNER: ${{ github.repository_owner }}
on:
schedule:
# Images are rebuilt at 03:00 on Monday UTC
# So we're testing recipes one hour in advance
# They will also be tested after building images
- cron: "0 2 * * 1"
pull_request:
paths:
- ".github/workflows/contributed-recipes.yml"
- "docs/using/recipe_code/**"
push:
branches:
- main
paths:
- ".github/workflows/contributed-recipes.yml"
- "docs/using/recipe_code/**"
workflow_dispatch:
workflow_call:
inputs:
# There is no good way to detect if the workflow was called using workflow_call
# https://github.com/actions/runner/discussions/1884
called-using-workflow-call:
description: "Was the workflow called using workflow_call"
required: true
type: boolean
permissions:
contents: read
jobs:
generate-matrix:
runs-on: ubuntu-24.04
timeout-minutes: 1
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Checkout Repo ⚡️
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Calculate recipes matrix 🛠
id: set-matrix
run: docs/using/recipe_code/generate_matrix.py >> "${GITHUB_OUTPUT}"
env:
REPOSITORY_OWNER: ${{ github.repository_owner }}
build:
runs-on: ${{ matrix.runs-on }}
timeout-minutes: 10
needs: generate-matrix
if: github.repository_owner == 'jupyter' || github.repository_owner == 'mathbunnyru'
steps:
- name: Checkout Repo ⚡️
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Load image to Docker 📥
if: ${{ inputs.called-using-workflow-call && matrix.parent-image != '' }}
uses: ./.github/actions/load-image
with:
image: ${{ matrix.parent-image }}
platform: ${{ matrix.platform }}
variant: default
# Not pulling the image, because it might be loaded from previous step or will be downloaded automatically
- name: Build recipe with parent image 🛠
if: ${{ matrix.parent-image != '' }}
run: |
docker build \
--rm --force-rm \
--tag my-custom-image \
-f ./${{ matrix.dockerfile }} \
--build-arg BASE_IMAGE=${{ env.REGISTRY }}/${{ env.OWNER }}/${{ matrix.parent-image }} \
./
env:
DOCKER_BUILDKIT: 1
# Full logs for CI build
BUILDKIT_PROGRESS: plain
working-directory: docs/using/recipe_code
shell: bash
# Not pulling the image, because it might be loaded from previous step or will be downloaded automatically
- name: Build recipe without parent image 🛠
if: ${{ matrix.parent-image == '' }}
run: |
docker build \
--rm --force-rm \
--tag my-custom-image \
-f ./${{ matrix.dockerfile }} \
./
env:
DOCKER_BUILDKIT: 1
# Full logs for CI build
BUILDKIT_PROGRESS: plain
working-directory: docs/using/recipe_code
shell: bash
strategy:
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
================================================
FILE: .github/workflows/docker-build-test-upload.yml
================================================
name: Download a parent image, build a new one, and test it; upload the image, tags, build history line and manifest to GitHub artifacts
env:
REGISTRY: quay.io
OWNER: ${{ github.repository_owner }}
on:
workflow_call:
inputs:
parent-image:
description: Parent image name
required: true
type: string
parent-variant:
description: Parent variant tag prefix
required: false
type: string
default: default
image:
description: Image name
required: true
type: string
variant:
description: Variant tag prefix
required: false
type: string
default: default
platform:
description: Image platform
required: true
type: string
runs-on:
description: GitHub Actions Runner image
required: true
type: string
timeout-minutes:
description: Timeout in minutes
required: true
type: number
permissions:
contents: read
jobs:
build-test-upload:
runs-on: ${{ inputs.runs-on }}
timeout-minutes: ${{ inputs.timeout-minutes }}
steps:
- name: Checkout Repo ⚡️
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Compute commit hash tag 🏷
id: hash
run: echo "tag=${GITHUB_SHA::12}" >> "$GITHUB_OUTPUT"
shell: bash
- name: Free disk space 🧹
uses: ./.github/actions/free-disk-space
if: contains(inputs.variant, 'cuda') || inputs.image == 'datascience-notebook' || inputs.image == 'all-spark-notebook'
- name: Create dev environment 📦
uses: ./.github/actions/create-dev-env
- name: Load parent built image to Docker 📥
if: inputs.parent-image != ''
uses: ./.github/actions/load-image
with:
image: ${{ inputs.parent-image }}
platform: ${{ inputs.platform }}
variant: ${{ inputs.parent-variant }}
- name: Pull base ubuntu image 📥
if: inputs.parent-image == ''
run: docker pull ubuntu:24.04
shell: bash
- name: Build image 🛠
run: |
docker build \
--rm --force-rm \
--tag ${{ env.REGISTRY }}/${{ env.OWNER }}/${{ inputs.image }} \
images/${{ inputs.image }}/${{ inputs.variant != 'default' && inputs.variant || '.' }}/ \
--build-arg REGISTRY=${{ env.REGISTRY }} \
--build-arg OWNER=${{ env.OWNER }}
env:
DOCKER_BUILDKIT: 1
# Full logs for CI build
BUILDKIT_PROGRESS: plain
shell: bash
- name: Write tags file 🏷
run: |
python3 -m tagging.apps.write_tags_file \
--registry ${{ env.REGISTRY }} \
--owner ${{ env.OWNER }} \
--image ${{ inputs.image }} \
--variant ${{ inputs.variant }} \
--tags-dir /tmp/jupyter/tags/
shell: bash
- name: Upload tags file 💾
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
path: /tmp/jupyter/tags/${{ inputs.platform }}-${{ inputs.variant }}-${{ inputs.image }}.txt
retention-days: 3
archive: false
- name: Write manifest and build history file 🏷
run: |
python3 -m tagging.apps.write_manifest \
--registry ${{ env.REGISTRY }} \
--owner ${{ env.OWNER }} \
--image ${{ inputs.image }} \
--variant ${{ inputs.variant }} \
--hist-lines-dir /tmp/jupyter/hist_lines/ \
--manifests-dir /tmp/jupyter/manifests/ \
--repository ${{ github.repository }}
shell: bash
- name: Upload manifest file 💾
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
path: /tmp/jupyter/manifests/${{ inputs.platform }}-${{ inputs.variant }}-${{ inputs.image }}-${{ steps.hash.outputs.tag }}.md
retention-days: 3
archive: false
- name: Upload build history line 💾
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
path: /tmp/jupyter/hist_lines/${{ inputs.platform }}-${{ inputs.variant }}-${{ inputs.image }}-${{ steps.hash.outputs.tag }}.txt
retention-days: 3
archive: false
- name: Save image as a tar for later use 💾
run: |
mkdir -p /tmp/jupyter/images/
docker save \
${{ env.REGISTRY }}/${{ env.OWNER }}/${{ inputs.image }} \
| zstd > /tmp/jupyter/images/${{ inputs.image }}-${{ inputs.platform }}-${{ inputs.variant }}.tar.zst
shell: bash
- name: Upload image as artifact 💾
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
path: /tmp/jupyter/images/${{ inputs.image }}-${{ inputs.platform }}-${{ inputs.variant }}.tar.zst
retention-days: 3
archive: false
- name: Run tests ✅
run: |
python3 -m tests.run_tests \
--registry ${{ env.REGISTRY }} \
--owner ${{ env.OWNER }} \
--image ${{ inputs.image }}
shell: bash
================================================
FILE: .github/workflows/docker-tag-merge.yml
================================================
name: Merge single platform tags
env:
REGISTRY: quay.io
PUSH_TO_REGISTRY: ${{ (github.repository_owner == 'jupyter' || github.repository_owner == 'mathbunnyru') && (github.ref == 'refs/heads/main' || github.event_name == 'schedule') }}
on:
workflow_call:
inputs:
image:
description: Image name
required: true
type: string
variant:
description: Variant tag prefix
required: true
type: string
timeout-minutes:
description: Timeout in minutes
default: 5
type: number
secrets:
REGISTRY_USERNAME:
required: true
REGISTRY_TOKEN:
required: true
permissions:
contents: read
jobs:
tag-merge:
runs-on: ubuntu-24.04
timeout-minutes: ${{ inputs.timeout-minutes }}
steps:
- name: Checkout Repo ⚡️
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Create dev environment 📦
uses: ./.github/actions/create-dev-env
- name: Download aarch64 tags file 🏷
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: aarch64-${{ inputs.variant }}-${{ inputs.image }}.txt
path: /tmp/jupyter/tags/
- name: Download x86_64 tags file 🏷
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: x86_64-${{ inputs.variant }}-${{ inputs.image }}.txt
path: /tmp/jupyter/tags/
- name: Login to Registry 🔐
if: env.PUSH_TO_REGISTRY == 'true'
run: |
docker login ${{ env.REGISTRY }} \
--username ${{ secrets.REGISTRY_USERNAME }} \
--password ${{ secrets.REGISTRY_TOKEN }} || \
docker login ${{ env.REGISTRY }} \
--username ${{ secrets.REGISTRY_USERNAME }} \
--password ${{ secrets.REGISTRY_TOKEN }}
shell: bash
id: login
- name: Merge tags for the images 🔀
run: |
python3 -m tagging.apps.merge_tags \
--image ${{ inputs.image }} \
--variant ${{ inputs.variant }} \
--tags-dir /tmp/jupyter/tags/
shell: bash
- name: Logout from Registry 🔐
if: always() && env.PUSH_TO_REGISTRY == 'true' && steps.login.outcome == 'success'
run: |
docker logout ${{ env.REGISTRY }}
shell: bash
================================================
FILE: .github/workflows/docker-tag-push-merge.yml
================================================
name: Download a Docker image and its tags from GitHub artifacts, apply them, and push the image to the Registry; then merge them
on:
workflow_call:
inputs:
image:
description: Image name
required: true
type: string
variant:
description: Variant tag prefix
required: true
type: string
secrets:
REGISTRY_USERNAME:
required: true
REGISTRY_TOKEN:
required: true
permissions:
contents: read
jobs:
tag-push:
uses: ./.github/workflows/docker-tag-push.yml
with:
image: ${{ inputs.image }}
variant: ${{ inputs.variant }}
secrets:
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
tag-merge:
uses: ./.github/workflows/docker-tag-merge.yml
needs: tag-push
with:
image: ${{ inputs.image }}
variant: ${{ inputs.variant }}
secrets:
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
================================================
FILE: .github/workflows/docker-tag-push.yml
================================================
name: Download a Docker image and its tags from GitHub artifacts, apply them, and push the image to the Registry
env:
REGISTRY: quay.io
OWNER: ${{ github.repository_owner }}
PUSH_TO_REGISTRY: ${{ (github.repository_owner == 'jupyter' || github.repository_owner == 'mathbunnyru') && (github.ref == 'refs/heads/main' || github.event_name == 'schedule') }}
on:
workflow_call:
inputs:
image:
description: Image name
required: true
type: string
variant:
description: Variant tag prefix
required: true
type: string
timeout-minutes:
description: Timeout in minutes
default: 25
type: number
secrets:
REGISTRY_USERNAME:
required: true
REGISTRY_TOKEN:
required: true
permissions:
contents: read
jobs:
tag-push:
runs-on: ubuntu-24.04
timeout-minutes: ${{ inputs.timeout-minutes }}
strategy:
matrix:
platform: [aarch64, x86_64]
steps:
- name: Checkout Repo ⚡️
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Free disk space 🧹
uses: ./.github/actions/free-disk-space
if: contains(inputs.variant, 'cuda') || inputs.image == 'datascience-notebook' || inputs.image == 'all-spark-notebook'
- name: Create dev environment 📦
uses: ./.github/actions/create-dev-env
- name: Download image tar and apply tags 🏷
uses: ./.github/actions/apply-single-tags
with:
image: ${{ inputs.image }}
variant: ${{ inputs.variant }}
platform: ${{ matrix.platform }}
- name: Login to Registry 🔐
if: env.PUSH_TO_REGISTRY == 'true'
run: |
docker login ${{ env.REGISTRY }} \
--username ${{ secrets.REGISTRY_USERNAME }} \
--password ${{ secrets.REGISTRY_TOKEN }} || \
docker login ${{ env.REGISTRY }} \
--username ${{ secrets.REGISTRY_USERNAME }} \
--password ${{ secrets.REGISTRY_TOKEN }}
shell: bash
id: login
- name: Push single platform images to Registry 📤
if: env.PUSH_TO_REGISTRY == 'true'
run: |
docker push --all-tags ${{ env.REGISTRY }}/${{ env.OWNER }}/${{ inputs.image }} || \
docker push --all-tags ${{ env.REGISTRY }}/${{ env.OWNER }}/${{ inputs.image }}
shell: bash
- name: Logout from Registry 🔐
if: always() && env.PUSH_TO_REGISTRY == 'true' && steps.login.outcome == 'success'
run: |
docker logout ${{ env.REGISTRY }}
shell: bash
================================================
FILE: .github/workflows/docker-wiki-update.yml
================================================
name: Download build history lines and manifests from GitHub artifacts and push them to the GitHub wiki
# We're doing everything in one workflow on purpose
# This way we make sure we don't access wiki pages from several jobs simultaneously
env:
PUSH_TO_REGISTRY: ${{ github.ref == 'refs/heads/main' || github.event_name == 'schedule' }}
on:
workflow_call:
permissions:
contents: write
jobs:
wiki-update:
runs-on: ubuntu-24.04
timeout-minutes: 1
steps:
- name: Checkout Repo ⚡️
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Create dev environment 📦
uses: ./.github/actions/create-dev-env
- name: Compute commit hash tag 🏷
id: hash
run: echo "tag=${GITHUB_SHA::12}" >> "$GITHUB_OUTPUT"
shell: bash
- name: Download all history lines 📥
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: "*-${{ steps.hash.outputs.tag }}.txt"
path: /tmp/jupyter/hist_lines/
merge-multiple: true
- name: Download all manifests 📥
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: "*-${{ steps.hash.outputs.tag }}.md"
path: /tmp/jupyter/manifests/
merge-multiple: true
- name: Checkout Wiki Repo 📃
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: ${{ github.repository }}.wiki
path: wiki_src/
- name: Update wiki 🏷
run: |
python3 -m wiki.update_wiki \
--wiki-dir wiki_src/ \
--hist-lines-dir /tmp/jupyter/hist_lines/ \
--manifests-dir /tmp/jupyter/manifests/ \
--repository ${{ github.repository }}
shell: bash
- name: Push Wiki to GitHub 📤
if: env.PUSH_TO_REGISTRY == 'true'
uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0
with:
commit_message: "Automated wiki publish for ${{ github.sha }}"
repository: wiki_src/
================================================
FILE: .github/workflows/docker.yml
================================================
name: Docker Stacks
# [FAST_BUILD] in the PR title makes this workflow only build
# the `jupyter/docker-stacks-foundation` and `jupyter/base-notebook` images
# This allows to run CI faster if a full build is not required
# This only works for a `pull_request` event and does not affect `push` to the `main` branch
on:
schedule:
# Weekly, at 03:00 on Monday UTC
- cron: "0 3 * * 1"
pull_request:
paths:
- ".github/workflows/docker.yml"
# We use local reusable workflows to make architecture clean and simple
# https://docs.github.com/en/actions/sharing-automations/reusing-workflows
- ".github/workflows/docker-build-test-upload.yml"
- ".github/workflows/docker-tag-merge.yml"
- ".github/workflows/docker-tag-push-merge.yml"
- ".github/workflows/docker-tag-push.yml"
- ".github/workflows/docker-wiki-update.yml"
# We use local composite actions to combine multiple workflow steps within one action
# https://docs.github.com/en/actions/sharing-automations/creating-actions/about-custom-actions#composite-actions
- ".github/actions/apply-single-tags/action.yml"
- ".github/actions/create-dev-env/action.yml"
- ".github/actions/free-disk-space/action.yml"
- ".github/actions/load-image/action.yml"
- "images/**"
- "!images/*/README.md"
- "tagging/**"
- "!tagging/README.md"
- "tests/**"
- "!tests/README.md"
- "wiki/**"
- "requirements-dev.txt"
push:
branches:
- main
paths:
- ".github/workflows/docker.yml"
- ".github/workflows/docker-build-test-upload.yml"
- ".github/workflows/docker-tag-merge.yml"
- ".github/workflows/docker-tag-push-merge.yml"
- ".github/workflows/docker-tag-push.yml"
- ".github/workflows/docker-wiki-update.yml"
- ".github/actions/apply-single-tags/action.yml"
- ".github/actions/create-dev-env/action.yml"
- ".github/actions/free-disk-space/action.yml"
- ".github/actions/load-image/action.yml"
- "images/**"
- "!images/*/README.md"
- "tagging/**"
- "!tagging/README.md"
- "tests/**"
- "!tests/README.md"
- "wiki/**"
- "requirements-dev.txt"
workflow_dispatch:
# https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/control-the-concurrency-of-workflows-and-jobs
concurrency:
# Only cancel in-progress jobs or runs for the current workflow - matches against branch & tags
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
aarch64-foundation:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: ""
image: docker-stacks-foundation
platform: aarch64
runs-on: ubuntu-24.04-arm
timeout-minutes: 10
x86_64-foundation:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: ""
image: docker-stacks-foundation
platform: x86_64
runs-on: ubuntu-24.04
timeout-minutes: 10
aarch64-base:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: docker-stacks-foundation
image: base-notebook
platform: aarch64
runs-on: ubuntu-24.04-arm
timeout-minutes: 15
needs: aarch64-foundation
x86_64-base:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: docker-stacks-foundation
image: base-notebook
platform: x86_64
runs-on: ubuntu-24.04
timeout-minutes: 15
needs: x86_64-foundation
aarch64-minimal:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: base-notebook
image: minimal-notebook
platform: aarch64
runs-on: ubuntu-24.04-arm
timeout-minutes: 15
needs: aarch64-base
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
x86_64-minimal:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: base-notebook
image: minimal-notebook
platform: x86_64
runs-on: ubuntu-24.04
timeout-minutes: 15
needs: x86_64-base
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
aarch64-scipy:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: minimal-notebook
image: scipy-notebook
platform: aarch64
runs-on: ubuntu-24.04-arm
timeout-minutes: 15
needs: aarch64-minimal
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
x86_64-scipy:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: minimal-notebook
image: scipy-notebook
platform: x86_64
runs-on: ubuntu-24.04
timeout-minutes: 15
needs: x86_64-minimal
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
aarch64-r:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: minimal-notebook
image: r-notebook
platform: aarch64
runs-on: ubuntu-24.04-arm
timeout-minutes: 15
needs: aarch64-minimal
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
x86_64-r:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: minimal-notebook
image: r-notebook
platform: x86_64
runs-on: ubuntu-24.04
timeout-minutes: 15
needs: x86_64-minimal
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
aarch64-julia:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: minimal-notebook
image: julia-notebook
platform: aarch64
runs-on: ubuntu-24.04-arm
# This workflow sometimes takes quite long to build
timeout-minutes: 30
needs: aarch64-minimal
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
x86_64-julia:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: minimal-notebook
image: julia-notebook
platform: x86_64
runs-on: ubuntu-24.04
timeout-minutes: 20
needs: x86_64-minimal
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
aarch64-tensorflow:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: scipy-notebook
image: tensorflow-notebook
platform: aarch64
runs-on: ubuntu-24.04-arm
timeout-minutes: 15
needs: aarch64-scipy
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
x86_64-tensorflow:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: scipy-notebook
image: tensorflow-notebook
platform: x86_64
runs-on: ubuntu-24.04
timeout-minutes: 15
needs: x86_64-scipy
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
aarch64-tensorflow-cuda:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: scipy-notebook
image: tensorflow-notebook
variant: cuda
platform: aarch64
runs-on: ubuntu-24.04-arm
timeout-minutes: 25
needs: aarch64-scipy
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
x86_64-tensorflow-cuda:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: scipy-notebook
image: tensorflow-notebook
variant: cuda
platform: x86_64
runs-on: ubuntu-24.04
timeout-minutes: 25
needs: x86_64-scipy
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
aarch64-pytorch:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: scipy-notebook
image: pytorch-notebook
platform: aarch64
runs-on: ubuntu-24.04-arm
timeout-minutes: 20
needs: aarch64-scipy
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
x86_64-pytorch:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: scipy-notebook
image: pytorch-notebook
platform: x86_64
runs-on: ubuntu-24.04
timeout-minutes: 20
needs: x86_64-scipy
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
aarch64-pytorch-cuda12:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: scipy-notebook
image: pytorch-notebook
variant: cuda12
platform: aarch64
runs-on: ubuntu-24.04-arm
timeout-minutes: 25
needs: aarch64-scipy
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
x86_64-pytorch-cuda12:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: scipy-notebook
image: pytorch-notebook
variant: cuda12
platform: x86_64
runs-on: ubuntu-24.04
timeout-minutes: 25
needs: x86_64-scipy
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
aarch64-pytorch-cuda13:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: scipy-notebook
image: pytorch-notebook
variant: cuda13
platform: aarch64
runs-on: ubuntu-24.04-arm
timeout-minutes: 25
needs: aarch64-scipy
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
x86_64-pytorch-cuda13:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: scipy-notebook
image: pytorch-notebook
variant: cuda13
platform: x86_64
runs-on: ubuntu-24.04
timeout-minutes: 25
needs: x86_64-scipy
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
aarch64-datascience:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: scipy-notebook
image: datascience-notebook
platform: aarch64
runs-on: ubuntu-24.04-arm
# This workflow sometimes takes quite long to build
timeout-minutes: 30
needs: aarch64-scipy
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
x86_64-datascience:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: scipy-notebook
image: datascience-notebook
platform: x86_64
runs-on: ubuntu-24.04
timeout-minutes: 25
needs: x86_64-scipy
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
aarch64-pyspark:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: scipy-notebook
image: pyspark-notebook
platform: aarch64
runs-on: ubuntu-24.04-arm
timeout-minutes: 20
needs: aarch64-scipy
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
x86_64-pyspark:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: scipy-notebook
image: pyspark-notebook
platform: x86_64
runs-on: ubuntu-24.04
timeout-minutes: 15
needs: x86_64-scipy
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
aarch64-all-spark:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: pyspark-notebook
image: all-spark-notebook
platform: aarch64
runs-on: ubuntu-24.04-arm
timeout-minutes: 20
needs: aarch64-pyspark
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
x86_64-all-spark:
uses: ./.github/workflows/docker-build-test-upload.yml
with:
parent-image: pyspark-notebook
image: all-spark-notebook
platform: x86_64
runs-on: ubuntu-24.04
timeout-minutes: 15
needs: x86_64-pyspark
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
contributed-recipes:
uses: ./.github/workflows/contributed-recipes.yml
with:
called-using-workflow-call: true
# Contributed recipes only use these images
# If recipes using other images will be added, they should be added here as well
#
# contributed-recipes will give an error if the image is not yet built and uploaded
needs: [aarch64-base, x86_64-base, aarch64-minimal, x86_64-minimal]
tag-push-merge:
uses: ./.github/workflows/docker-tag-push-merge.yml
with:
image: ${{ matrix.image }}
variant: ${{ matrix.variant }}
secrets:
REGISTRY_USERNAME: ${{ secrets.QUAY_USERNAME }}
REGISTRY_TOKEN: ${{ secrets.QUAY_ROBOT_TOKEN }}
strategy:
matrix:
image:
[
docker-stacks-foundation,
base-notebook,
minimal-notebook,
scipy-notebook,
r-notebook,
julia-notebook,
tensorflow-notebook,
pytorch-notebook,
datascience-notebook,
pyspark-notebook,
all-spark-notebook,
]
variant: [default]
include:
- image: tensorflow-notebook
variant: cuda
- image: pytorch-notebook
variant: cuda12
- image: pytorch-notebook
variant: cuda13
needs:
[
contributed-recipes,
aarch64-foundation,
aarch64-base,
aarch64-minimal,
aarch64-scipy,
aarch64-r,
aarch64-julia,
aarch64-tensorflow,
aarch64-tensorflow-cuda,
aarch64-pytorch,
aarch64-pytorch-cuda12,
aarch64-pytorch-cuda13,
aarch64-datascience,
aarch64-pyspark,
aarch64-all-spark,
x86_64-foundation,
x86_64-base,
x86_64-minimal,
x86_64-scipy,
x86_64-r,
x86_64-julia,
x86_64-tensorflow,
x86_64-tensorflow-cuda,
x86_64-pytorch,
x86_64-pytorch-cuda12,
x86_64-pytorch-cuda13,
x86_64-datascience,
x86_64-pyspark,
x86_64-all-spark,
]
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
tag-push-merge-fast:
uses: ./.github/workflows/docker-tag-push-merge.yml
with:
image: ${{ matrix.image }}
variant: ${{ matrix.variant }}
secrets:
REGISTRY_USERNAME: ${{ secrets.QUAY_USERNAME }}
REGISTRY_TOKEN: ${{ secrets.QUAY_ROBOT_TOKEN }}
strategy:
matrix:
image: [docker-stacks-foundation, base-notebook]
variant: [default]
needs: [aarch64-foundation, aarch64-base, x86_64-foundation, x86_64-base]
if: contains(github.event.pull_request.title, '[FAST_BUILD]')
wiki-update:
uses: ./.github/workflows/docker-wiki-update.yml
needs: tag-push-merge
if: ${{ !contains(github.event.pull_request.title, '[FAST_BUILD]') }}
permissions:
contents: write
wiki-update-fast:
uses: ./.github/workflows/docker-wiki-update.yml
needs: tag-push-merge-fast
if: contains(github.event.pull_request.title, '[FAST_BUILD]')
permissions:
contents: write
================================================
FILE: .github/workflows/pre-commit.yml
================================================
name: Run pre-commit hooks
on:
pull_request:
push:
branches:
- main
workflow_dispatch:
permissions:
contents: read
jobs:
run-hooks:
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Checkout Repo ⚡️
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set Up Python 🐍
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: 3.12
- name: Install pre-commit 📦
run: |
pip install --upgrade pip
pip install --upgrade pre-commit
- name: Run pre-commit hooks ✅
run: pre-commit run --all-files --hook-stage manual
================================================
FILE: .github/workflows/registry-move.yml
================================================
name: Move some images from Docker Hub to Quay.io
env:
OWNER: ${{ github.repository_owner }}
PUSH_TO_REGISTRY: ${{ (github.repository_owner == 'jupyter' || github.repository_owner == 'mathbunnyru') && (github.ref == 'refs/heads/main') }}
on:
pull_request:
paths:
- ".github/workflows/registry-move.yml"
push:
branches:
- main
paths:
- ".github/workflows/registry-move.yml"
workflow_dispatch:
permissions:
contents: read
jobs:
registry-move:
# To be able to use the latest skopeo
runs-on: macos-latest
timeout-minutes: 5
if: github.repository_owner == 'jupyter' || github.repository_owner == 'mathbunnyru'
steps:
- name: Checkout Repo ⚡️
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Install skopeo and Docker 📦
run: |
brew install skopeo
brew install --cask docker
- name: Login to Quay.io 🔐
if: env.PUSH_TO_REGISTRY == 'true'
run: |
skopeo login quay.io \
--username ${{ secrets.QUAY_USERNAME }} \
--password ${{ secrets.QUAY_ROBOT_TOKEN }}
- name: Move image from Docker Hub to Quay.io 🐳
if: env.PUSH_TO_REGISTRY == 'true' && matrix.tag != 'tag-for-testing'
run: |
skopeo copy \
--multi-arch all \
docker://${{ env.OWNER }}/${{ matrix.image }}:${{ matrix.tag }} \
docker://quay.io/${{ env.OWNER }}/${{ matrix.image }}:${{ matrix.tag }}
strategy:
fail-fast: false
matrix:
image:
[
docker-stacks-foundation,
base-notebook,
minimal-notebook,
scipy-notebook,
r-notebook,
julia-notebook,
tensorflow-notebook,
pytorch-notebook,
datascience-notebook,
pyspark-notebook,
all-spark-notebook,
]
tag: [tag-for-testing]
================================================
FILE: .github/workflows/registry-overviews.yml
================================================
name: Update Registry overviews
env:
OWNER: ${{ github.repository_owner }}
on:
push:
branches:
- main
paths:
- ".github/workflows/registry-overviews.yml"
- "images/*/README.md"
workflow_dispatch:
permissions:
contents: read
jobs:
update-overview:
runs-on: ubuntu-24.04
timeout-minutes: 1
if: github.repository_owner == 'jupyter' || github.repository_owner == 'mathbunnyru'
steps:
- name: Checkout Repo ⚡️
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Push README to Registry 🐳
uses: christian-korneck/update-container-description-action@d36005551adeaba9698d8d67a296bd16fa91f8e8 # v1
env:
DOCKER_APIKEY: ${{ secrets.APIKEY__QUAY_IO }}
with:
destination_container_repo: quay.io/${{ env.OWNER }}/${{ matrix.image }}
provider: quay
readme_file: images/${{ matrix.image }}/README.md
strategy:
matrix:
image:
[
docker-stacks-foundation,
base-notebook,
minimal-notebook,
scipy-notebook,
r-notebook,
julia-notebook,
tensorflow-notebook,
pytorch-notebook,
datascience-notebook,
pyspark-notebook,
all-spark-notebook,
]
================================================
FILE: .github/workflows/sphinx.yml
================================================
name: Build Sphinx Documentation and check links
on:
schedule:
# Weekly, at 03:00 on Monday UTC
- cron: "0 3 * * 1"
pull_request:
paths:
- ".github/workflows/sphinx.yml"
- "Makefile"
- "docs/**"
# These files are also rendered as docs pages
- "README.md"
- "CHANGELOG.md"
# These files are used to generate some code snippets in the docs
- "tagging/manifests/apt_packages.py"
- "tagging/manifests/manifest_interface.py"
- "tagging/taggers/sha.py"
- "tagging/taggers/tagger_interface.py"
push:
branches:
- main
paths:
- ".github/workflows/sphinx.yml"
- "Makefile"
- "docs/**"
- "README.md"
- "CHANGELOG.md"
- "tagging/manifests/apt_packages.py"
- "tagging/manifests/manifest_interface.py"
- "tagging/taggers/sha.py"
- "tagging/taggers/tagger_interface.py"
workflow_dispatch:
permissions:
contents: read
jobs:
build-docs:
runs-on: ubuntu-24.04
timeout-minutes: 10
if: github.repository_owner == 'jupyter' || github.repository_owner == 'mathbunnyru' || github.event_name != 'schedule'
steps:
- name: Checkout Repo ⚡️
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Set Up Python 🐍
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: 3.12
- name: Install Doc Dependencies 📦
run: |
pip install --upgrade pip
pip install --upgrade -r docs/requirements.txt
- name: Build Documentation 📖
run: make docs
- name: Check Documentation URLs 🔗
run: make linkcheck-docs || make linkcheck-docs
================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# UV
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
#uv.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
.pdm.toml
.pdm-python
.pdm-build/
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
# Ruff stuff:
.ruff_cache/
# PyPI configuration file
.pypirc
##################################################################
# The content above is copied from #
# https://github.com/github/gitignore/blob/main/Python.gitignore #
# Please, add the content only below these lines #
##################################################################
# Mac OS X
.DS_Store
# VS Code project configuration
.vscode/
# PyCharm project configuration
.idea/
================================================
FILE: .hadolint.yaml
================================================
---
ignored:
- DL3006
- DL3008
- DL3013
================================================
FILE: .markdownlint.yaml
================================================
# Default state for all rules
default: true
# MD013/line-length - Line length
MD013:
# Number of characters
line_length: 200
tables: false
================================================
FILE: .pre-commit-config.yaml
================================================
---
# pre-commit is a tool to perform a predefined set of tasks manually and/or
# automatically before git commits are made.
#
# Config reference: https://pre-commit.com/#pre-commit-configyaml---top-level
#
# Common tasks
#
# - Run on all files: pre-commit run --all-files
# - Register git hooks: pre-commit install --install-hooks
#
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
exclude: ^LICENSE.md$
repos:
# Autoupdate: Python code
- repo: https://github.com/asottile/pyupgrade
rev: 75992aaa40730136014f34227e0135f63fc951b4 # frozen: v3.21.2
hooks:
- id: pyupgrade
args: [--py312-plus]
# Automatically sort python imports
- repo: https://github.com/PyCQA/isort
rev: a333737ed43df02b18e6c95477ea1b285b3de15a # frozen: 8.0.1
hooks:
- id: isort
args: [--profile, black]
# Autoformat: Python code
- repo: https://github.com/psf/black-pre-commit-mirror
rev: ea488cebbfd88a5f50b8bd95d5c829d0bb76feb8 # frozen: 26.1.0
hooks:
- id: black
args: [--target-version=py312]
# Check python code static typing
- repo: https://github.com/pre-commit/mirrors-mypy
rev: a66e98df7b4aeeb3724184b332785976d062b92e # frozen: v1.19.1
hooks:
- id: mypy
args: [--config, ./mypy.ini]
additional_dependencies:
[
"beautifulsoup4",
"numpy",
"pytest",
"requests",
"tenacity",
"urllib3",
"types-beautifulsoup4",
"types-python-dateutil",
"types-requests",
"types-tabulate",
"types-urllib3",
]
# Unfortunately, `pre-commit` only runs on modified files
# This doesn't work well with `mypy --follow-imports error`
# See: https://github.com/pre-commit/mirrors-mypy/issues/34#issuecomment-1062160321
#
# To work around this we run `mypy` only in manual mode
# So it won't run as part of `git commit` command,
# but it will still be run as part of `pre-commit` workflow and give expected results
stages: [manual]
# Autoformat: YAML, JSON, Markdown, etc.
- repo: https://github.com/rbubley/mirrors-prettier
rev: c2bc67fe8f8f549cc489e00ba8b45aa18ee713b1 # frozen: v3.8.1
hooks:
- id: prettier
# `pre-commit sample-config` default hooks
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0
hooks:
- id: check-added-large-files
- id: check-executables-have-shebangs
- id: check-shebang-scripts-are-executable
- id: end-of-file-fixer
- id: requirements-txt-fixer
- id: trailing-whitespace
# Lint: Dockerfile
- repo: https://github.com/hadolint/hadolint
rev: 4e697ba704fd23b2409b947a319c19c3ee54d24f # frozen: v2.14.0
hooks:
- id: hadolint-docker
entry: hadolint/hadolint:v2.14.0 hadolint
# Lint: Dockerfile
# We're linting .dockerfile files as well
- repo: https://github.com/hadolint/hadolint
rev: 4e697ba704fd23b2409b947a319c19c3ee54d24f # frozen: v2.14.0
hooks:
- id: hadolint-docker
name: Lint *.dockerfile Dockerfiles
entry: hadolint/hadolint:v2.12.1-beta hadolint
types: [file]
files: \.dockerfile$
# Lint: YAML
- repo: https://github.com/adrienverge/yamllint
rev: cba56bcde1fdd01c1deb3f945e69764c291a6530 # frozen: v1.38.0
hooks:
- id: yamllint
args: ["-d {extends: relaxed, rules: {line-length: disable}}", "-s"]
# Lint: Bash scripts
- repo: https://github.com/openstack/bashate
rev: 5798d24d571676fc407e81df574c1ef57b520f23 # frozen: 2.1.1
hooks:
- id: bashate
args: ["--ignore=E006"]
# Lint: Shell scripts
- repo: https://github.com/shellcheck-py/shellcheck-py
rev: 745eface02aef23e168a8afb6b5737818efbea95 # frozen: v0.11.0.1
hooks:
- id: shellcheck
args: ["-x"]
# Lint: Python
- repo: https://github.com/PyCQA/flake8
rev: d93590f5be797aabb60e3b09f2f52dddb02f349f # frozen: 7.3.0
hooks:
- id: flake8
# Lint: Markdown
- repo: https://github.com/DavidAnson/markdownlint-cli2
rev: 5387279b3b4c24822c0f86d4df4f28b37e3e8992 # frozen: v0.21.0
hooks:
- id: markdownlint-cli2
args: [--fix]
# Strip output from Jupyter notebooks
- repo: https://github.com/kynan/nbstripout
rev: f5da19ce3b7b40e97c12ee9cd8ce97f48f97ddf7 # frozen: 0.9.1
hooks:
- id: nbstripout
# nbQA provides tools from the Python ecosystem like
# pyupgrade, isort, black, and flake8, adjusted for notebooks.
- repo: https://github.com/nbQA-dev/nbQA
rev: f96ec7f3b26a32619435686eb5813235f7e3327e # frozen: 1.9.1
hooks:
- id: nbqa-pyupgrade
args: [--py312-plus]
- id: nbqa-isort
- id: nbqa-black
args: [--target-version=py312]
- id: nbqa-flake8
# Run black on python code blocks in documentation files.
- repo: https://github.com/adamchainz/blacken-docs
rev: dda8db18cfc68df532abf33b185ecd12d5b7b326 # frozen: 1.20.0
hooks:
- id: blacken-docs
# --skip-errors is added to allow us to have python syntax highlighting even if
# the python code blocks include jupyter-specific additions such as % or !
# See https://github.com/adamchainz/blacken-docs/issues/127 for an upstream
# feature request about this.
args: [--target-version=py312, --skip-errors]
# pre-commit.ci config reference: https://pre-commit.ci/#configuration
ci:
autoupdate_schedule: monthly
# Docker hooks do not work in pre-commit.ci
# See: <https://github.com/pre-commit-ci/issues/issues/11>
skip: [hadolint-docker]
================================================
FILE: .readthedocs.yaml
================================================
# Read the Docs configuration file for Sphinx projects
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Set the OS, Python version and other tools you might need
build:
os: ubuntu-22.04
tools:
python: "3.12"
# You can also specify other tool versions:
# nodejs: "20"
# rust: "1.70"
# golang: "1.20"
jobs:
post_checkout:
- git fetch --unshallow || true
# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/conf.py
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
# builder: "dirhtml"
# Fail on all warnings to avoid broken references
# fail_on_warning: true
# Optionally build your docs in additional formats such as PDF and ePub
# formats:
# - pdf
# - epub
# Optional but recommended, declare the Python requirements required
# to build your documentation
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: docs/requirements.txt
================================================
FILE: CHANGELOG.md
================================================
# Changelog
This changelog only contains breaking and/or significant changes manually introduced to this repository (using Pull Requests).
All image manifests can be found in [the wiki](https://github.com/jupyter/docker-stacks/wiki).
## 2025-12-31
Affected: `pytorch-notebook`.
- **Non-breaking:** `pytorch-notebook`: Build pytorch cuda13 image instead of cuda11 ([#2391](https://github.com/jupyter/docker-stacks/pull/2391))
## 2025-12-02
Affected: `tensorflow-notebook`, `pytorch-notebook`.
- **Non-breaking:** Enable CUDA build for ARM64 ([#2352](https://github.com/jupyter/docker-stacks/pull/2352)).
## 2025-11-29
Affected: all images.
- **Breaking:** Use Docker v29 and `docker buildx imagetools create` ([#2368](https://github.com/jupyter/docker-stacks/pull/2368)).
## 2025-11-24
Affected: all images.
- **Non-breaking:** Add Dev Container support ([#2358](https://github.com/jupyter/docker-stacks/pull/2358)).
- **Non-breaking:** Add recipe on running Jupyter Docker Stacks with Singularity ([#2357](https://github.com/jupyter/docker-stacks/pull/2357)).
## 2025-11-06
Affected: `scipy-notebook`.
- **Breaking:** `scipy-notebook`: Remove facets package installation ([#2347](https://github.com/jupyter/docker-stacks/pull/2347)).
## 2025-09-16
Affected: all images.
- **Non-breaking:** Publish SBOM using anchore/sbom-action ([#2317](https://github.com/jupyter/docker-stacks/pull/2317)).
## 2025-08-15
Affected: all images.
- **Breaking:** `docker-stacks-foundation`: switch to Python 3.13 ([#2163](https://github.com/jupyter/docker-stacks/pull/2163)).
## 2025-04-13
Affected: `tensorflow-notebook`.
- **Non-breaking:** `tesnorflow-notebook`: Install latest tensorflow ([#2263](https://github.com/jupyter/docker-stacks/pull/2263)).
## 2025-04-12
Affected: all images.
- **Non-breaking:** `docker-stacks-foundation`: Pin libxml2 to avoid ABI breakage ([#2283](https://github.com/jupyter/docker-stacks/pull/2283)).
## 2025-04-11
Affected: all images.
- **Non-breaking:** Make docker tag-push depend on contributed recipes in CI ([#2282](https://github.com/jupyter/docker-stacks/pull/2282)).
## 2025-04-01
Affected: all images.
- **Non-breaking:** Apply and merge tags in the same place ([#2274](https://github.com/jupyter/docker-stacks/pull/2274)).
## 2025-03-23
Affected: `tensorflow-notebook`.
- **Non-breaking:** `tensorflow-notebook`: Use mamba to install jupyter-server-proxy ([#2262](https://github.com/jupyter/docker-stacks/pull/2262)).
## 2025-03-22
Affected: all images.
- **Non-breaking:** Use tty for running docker commands by default ([#2260](https://github.com/jupyter/docker-stacks/pull/2260)).
- **Non-breaking:** Improve logs around running docker ([#2261](https://github.com/jupyter/docker-stacks/pull/2261)).
## 2025-03-21
Affected: all images.
- **Non-breaking:** Refactor TrackedContainer run_detached/exec_cmd functions ([#2256](https://github.com/jupyter/docker-stacks/pull/2256)).
- **Non-breaking:** Do not allocate TTY in tests if not needed ([#2257](https://github.com/jupyter/docker-stacks/pull/2257)).
- **Non-breaking:** `base-notebook`: Flush output in Python before running execvp ([#2258](https://github.com/jupyter/docker-stacks/pull/2258)).
## 2025-03-20
Affected: all images except `docker-stacks-foundation`.
- **Non-breaking:** `base-notebook`: Refactor healthcheck tests to use one function ([#2254](https://github.com/jupyter/docker-stacks/pull/2254)).
- **Non-breaking:** `base-notebook`: Test server listening on IPv4/IPv6 ([#2255](https://github.com/jupyter/docker-stacks/pull/2255)).
## 2025-03-12
Affected: all images.
- **Non-breaking:** Add `conda` and `mamba` version taggers ([#2251](https://github.com/jupyter/docker-stacks/pull/2251)).
- **Non-breaking:** Make taggers and manifests functions ([#2252](https://github.com/jupyter/docker-stacks/pull/2252)).
## 2025-02-21
Affected: all images.
- **Non-breaking:** Better tagging directory structure ([#2228](https://github.com/jupyter/docker-stacks/pull/2228)).
- **Non-breaking:** Better testing directory structure ([#2231](https://github.com/jupyter/docker-stacks/pull/2231)).
## 2025-02-18
Affected: all images.
- **Non-breaking:** switch from `ubuntu-22.04-arm` to `ubuntu-24.04-arm` runners ([#2209](https://github.com/jupyter/docker-stacks/pull/2209)).
- **Non-breaking:** don't create extra free space in runners for cuda images ([#2218](https://github.com/jupyter/docker-stacks/pull/2218)).
- **Non-breaking:** revert "Pin some packages to fix `r-notebook` and `datascience-notebook` under aarch64" ([#2220](https://github.com/jupyter/docker-stacks/pull/2220)).
- **Non-breaking:** Simplify and improve `test_packages.py` ([#2219](https://github.com/jupyter/docker-stacks/pull/2219)).
- **Non-breaking:** Use Python 3.12 for internal code ([#2222](https://github.com/jupyter/docker-stacks/pull/2222)).
## 2025-02-17
Affected: all images.
- **Non-breaking:** build contributed recipes in PRs ([#2212](https://github.com/jupyter/docker-stacks/pull/2212), [#2213](https://github.com/jupyter/docker-stacks/pull/2213)).
- **Non-breaking:** remove information about Docker Hub images from Quay.io READMEs ([#2211](https://github.com/jupyter/docker-stacks/pull/2211)).
- **Non-breaking:** first upload artifacts and then run tests to make sure we can easily debug broken images ([#2214](https://github.com/jupyter/docker-stacks/pull/2214)).
- **Non-Breaking:** aarch64 `r-notebook`, `datascience-notebook`: pin some packages to fix `r-notebook` and `datascience-notebook` under aarch64 ([#2215](https://github.com/jupyter/docker-stacks/pull/2215)).
- **Non-breaking:** don't use matrix.image-variant, use 2 separate variables ([#2217](https://github.com/jupyter/docker-stacks/pull/2217)).
## 2025-02-11
Affected: all images.
- **Non-breaking:** start using `ubuntu-22.04-arm` GitHub-hosted `aarch64` runners ([#2202](https://github.com/jupyter/docker-stacks/pull/2202)).
## 2024-12-03
Affected: all images.
- **Breaking:** `docker-stacks-foundation`: switch to `mamba` v2 ([#2147](https://github.com/jupyter/docker-stacks/pull/2147)).
More information about changes made: <https://mamba.readthedocs.io/en/latest/developer_zone/changes-2.0.html>.
## 2024-11-08
Affected: all images except `docker-stacks-foundation`.
- **Breaking:** `base-notebook`: stop installing `nodejs` from `conda-forge` ([#2172](https://github.com/jupyter/docker-stacks/pull/2172)).
Reason: It isn't a direct dependency on anything in the images anymore, and increased the image size by ~150MB.
## 2024-11-06
Affected: all images except `docker-stacks-foundation`.
- **Non-breaking:** `base-notebook`: install `jupyterhub-base` and `nodejs` packages instead of `jupyterhub` package ([#2171](https://github.com/jupyter/docker-stacks/pull/2171)).
## 2024-10-23
Affected: all images.
- **Breaking:** `docker-stacks-foundation`: switch to Python 3.12 ([#2072](https://github.com/jupyter/docker-stacks/pull/2072)).
## 2024-10-22
Affected: `pyspark-notebook` and `all-spark-notebook` images.
- **Breaking:** `pyspark-notebook`: start using Spark 4.0.0 preview versions ([#2159](https://github.com/jupyter/docker-stacks/pull/2159)).
`sparklyr` doesn't seem to support Spark v4 yet when using Spark locally.
Reason: Spark v3 is not compatible with Python 3.12, and [the voting group has decided](https://github.com/jupyter/docker-stacks/pull/2072#issuecomment-2414123851) to switch to Spark v4 preview version.
## 2024-10-09
Affected: users building a custom set of images.
- **Breaking:** rename: `ROOT_CONTAINER`->`ROOT_IMAGE`, `BASE_CONTAINER`->`BASE_IMAGE` ([#2154](https://github.com/jupyter/docker-stacks/issues/2154), [#2155](https://github.com/jupyter/docker-stacks/pull/2155)).
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Project `jupyter/docker-stacks` Code of Conduct
Please see the [Project Jupyter Code of Conduct](https://github.com/jupyter/governance/blob/HEAD/conduct/code_of_conduct.md).
================================================
FILE: CONTRIBUTING.md
================================================
Thanks for contributing!
Please see the **Contributor Guide** section in [the documentation](https://jupyter-docker-stacks.readthedocs.io/en/latest/)
for information about how to contribute
[issues](https://jupyter-docker-stacks.readthedocs.io/en/latest/contributing/issues.html),
[features](https://jupyter-docker-stacks.readthedocs.io/en/latest/contributing/features.html),
[recipes](https://jupyter-docker-stacks.readthedocs.io/en/latest/contributing/recipes.html),
[tests](https://jupyter-docker-stacks.readthedocs.io/en/latest/contributing/tests.html),
and [community-maintained stacks](https://jupyter-docker-stacks.readthedocs.io/en/latest/contributing/stacks.html).
## Our Copyright Policy
Jupyter uses a shared copyright model. Each contributor maintains copyright
over their contributions to Jupyter. But, it is important to note that these
contributions are typically only changes to the repositories. Thus, the Jupyter
source code, in its entirety is not the copyright of any single person or
institution. Instead, it is the collective copyright of the entire Jupyter
Development Team. If individual contributors want to maintain a record of what
changes/contributions they have specific copyright on, they should indicate
their copyright in the commit message of the change, when they commit the
change to one of the Jupyter repositories.
With this in mind, the following banner should be used in any source code file
to indicate the copyright and license terms:
```text
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
```
<!-- markdownlint-disable-file MD041 -->
================================================
FILE: LICENSE.md
================================================
BSD 3-Clause License
Copyright (c) 2001-2015, IPython Development Team
Copyright (c) 2015-, Jupyter Development Team
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: Makefile
================================================
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
.PHONY: docs help test
SHELL:=bash
REGISTRY?=quay.io
OWNER?=jupyter
# Enable BuildKit for Docker build
export DOCKER_BUILDKIT:=1
# All the images listed in the build dependency order
ALL_IMAGES:= \
docker-stacks-foundation \
base-notebook \
minimal-notebook \
scipy-notebook \
r-notebook \
julia-notebook \
tensorflow-notebook \
pytorch-notebook \
datascience-notebook \
pyspark-notebook \
all-spark-notebook
# https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
help:
@echo "jupyter/docker-stacks"
@echo "====================="
@echo "Replace % with a stack directory name (e.g., make build/minimal-notebook)"
@echo
@grep -E '^[a-zA-Z0-9_%/-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
# Note that `ROOT_IMAGE` and `PYTHON_VERSION` arguments are only applicable to the `docker-stacks-foundation` image
build/%: DOCKER_BUILD_ARGS?=
build/%: ROOT_IMAGE?=ubuntu:24.04
build/%: PYTHON_VERSION?=3.13
build/%: ## build the latest image for a stack using the system's architecture
docker build $(DOCKER_BUILD_ARGS) --rm --force-rm \
--tag "$(REGISTRY)/$(OWNER)/$(notdir $@)" \
"./images/$(notdir $@)" \
--build-arg REGISTRY="$(REGISTRY)" \
--build-arg OWNER="$(OWNER)" \
--build-arg ROOT_IMAGE="$(ROOT_IMAGE)" \
--build-arg PYTHON_VERSION="$(PYTHON_VERSION)"
@echo -n "Built image size: "
@docker images "$(REGISTRY)/$(OWNER)/$(notdir $@):latest" --format "{{.Size}}"
build-all: $(foreach I, $(ALL_IMAGES), build/$(I)) ## build all stacks
check-outdated/%: ## check the outdated mamba/conda packages in a stack and produce a report
pytest tests/by_image/docker-stacks-foundation/test_outdated.py \
--registry "$(REGISTRY)" \
--owner "$(OWNER)" \
--image "$(notdir $@)"
check-outdated-all: $(foreach I, $(ALL_IMAGES), check-outdated/$(I)) ## check all the stacks for outdated packages
cont-stop-all: ## stop all containers
@echo "Stopping all containers ..."
-docker stop --time 0 $(shell docker ps --all --quiet) 2> /dev/null
cont-rm-all: ## remove all containers
@echo "Removing all containers ..."
-docker rm --force $(shell docker ps --all --quiet) 2> /dev/null
cont-clean-all: cont-stop-all cont-rm-all ## clean all containers (stop + rm)
docs: ## build HTML documentation
sphinx-build -W --keep-going --color docs/ docs/_build/
linkcheck-docs: ## check for broken links
sphinx-build -W --keep-going --color -b linkcheck docs/ docs/_build/
hook/%: VARIANT?=default
hook/%: REPOSITORY?=$(OWNER)/docker-stacks
hook/%: ## run post-build hooks for an image
python3 -m tagging.apps.write_tags_file \
--registry "$(REGISTRY)" \
--owner "$(OWNER)" \
--image "$(notdir $@)" \
--variant "$(VARIANT)" \
--tags-dir /tmp/jupyter/tags/
python3 -m tagging.apps.write_manifest \
--registry "$(REGISTRY)" \
--owner "$(OWNER)" \
--image "$(notdir $@)" \
--variant "$(VARIANT)" \
--hist-lines-dir /tmp/jupyter/hist_lines/ \
--manifests-dir /tmp/jupyter/manifests/ \
--repository "$(REPOSITORY)"
python3 -m tagging.apps.apply_tags \
--registry "$(REGISTRY)" \
--owner "$(OWNER)" \
--image "$(notdir $@)" \
--variant "$(VARIANT)" \
--platform "$(shell uname -m)" \
--tags-dir /tmp/jupyter/tags/
hook-all: $(foreach I, $(ALL_IMAGES), hook/$(I)) ## run post-build hooks for all images
img-list: ## list jupyter images
@echo "Listing $(OWNER) images ..."
docker images "$(OWNER)/*"
docker images "*/$(OWNER)/*"
img-rm-dang: ## remove dangling images (tagged None)
@echo "Removing dangling images ..."
-docker rmi --force $(shell docker images -f "dangling=true" --quiet) 2> /dev/null
img-rm-jupyter: ## remove jupyter images
@echo "Removing $(OWNER) images ..."
-docker rmi --force $(shell docker images --quiet "$(OWNER)/*") 2> /dev/null
-docker rmi --force $(shell docker images --quiet "*/$(OWNER)/*") 2> /dev/null
img-rm: img-rm-dang img-rm-jupyter ## remove dangling and jupyter images
pull/%: ## pull a jupyter image
docker pull "$(REGISTRY)/$(OWNER)/$(notdir $@)"
pull-all: $(foreach I, $(ALL_IMAGES), pull/$(I)) ## pull all images
push/%: ## push all tags for a jupyter image
docker push --all-tags "$(REGISTRY)/$(OWNER)/$(notdir $@)"
push-all: $(foreach I, $(ALL_IMAGES), push/$(I)) ## push all tagged images
run-shell/%: ## run a bash in interactive mode in a stack
docker run -it --rm "$(REGISTRY)/$(OWNER)/$(notdir $@)" $(SHELL)
run-sudo-shell/%: ## run bash in interactive mode as root in a stack
docker run -it --rm --user root "$(REGISTRY)/$(OWNER)/$(notdir $@)" $(SHELL)
test/%: ## run tests against a stack
python3 -m tests.run_tests \
--registry "$(REGISTRY)" \
--owner "$(OWNER)" \
--image "$(notdir $@)"
test-all: $(foreach I, $(ALL_IMAGES), test/$(I)) ## test all stacks
================================================
FILE: README.md
================================================
# Jupyter Docker Stacks
[](https://github.com/jupyter/docker-stacks/actions/workflows/docker.yml?query=branch%3Amain "Docker images build status")
[](https://jupyter-docker-stacks.readthedocs.io/en/latest/ "Documentation build status")
[](https://results.pre-commit.ci/latest/github/jupyter/docker-stacks/main "pre-commit.ci build status")
[](https://discourse.jupyter.org/ "Jupyter Discourse Forum")
[](https://mybinder.org/v2/gh/jupyter/docker-stacks/main?urlpath=lab/tree/README.ipynb "Launch a quay.io/jupyter/base-notebook container on mybinder.org")
Jupyter Docker Stacks are a set of ready-to-run [Docker images](https://quay.io/organization/jupyter) containing Jupyter applications and interactive computing tools.
You can use a stack image to do any of the following (and more):
- Start a personal Jupyter Server with the JupyterLab frontend (default)
- Run JupyterLab for a team using JupyterHub
- Start a personal Jupyter Server with the Jupyter Notebook frontend in a local Docker container
- Write your own project Dockerfile
## Quick Start
You can [try the quay.io/jupyter/base-notebook image](https://mybinder.org/v2/gh/jupyter/docker-stacks/main?urlpath=lab/tree/README.ipynb) on <https://mybinder.org>.
Otherwise, the examples below may help you get started if you [have Docker installed](https://docs.docker.com/get-started/get-docker/),
know [which Docker image](https://jupyter-docker-stacks.readthedocs.io/en/latest/using/selecting.html) you want to use, and want to launch a single Jupyter Application in a container.
The [User Guide on ReadTheDocs](https://jupyter-docker-stacks.readthedocs.io/en/latest/) describes additional uses and features in detail.
```{note}
Since `2023-10-20` our images are only pushed to `Quay.io` registry.
Older images are available on Docker Hub, but they will no longer be updated.
```
### Example 1
This command pulls the `jupyter/scipy-notebook` image tagged `2025-12-31` from Quay.io if it is not already present on the local host.
It then starts a container running a Jupyter Server with the JupyterLab frontend and exposes the container's internal port `8888` to port `10000` of the host machine:
```bash
docker run -p 10000:8888 quay.io/jupyter/scipy-notebook:2025-12-31
```
You can modify the port on which the container's port is exposed by [changing the value of the `-p` option](https://docs.docker.com/engine/containers/run/#exposed-ports) to `-p 8888:8888`.
Visiting `http://<hostname>:10000/?token=<token>` in a browser loads JupyterLab,
where:
- The `hostname` is the name of the computer running Docker
- The `token` is the secret token printed in the console.
The container remains intact for restart after the Server exits.
### Example 2
This command pulls the `jupyter/datascience-notebook` image tagged `2025-12-31` from Quay.io if it is not already present on the local host.
It then starts an _ephemeral_ container running a Jupyter Server with the JupyterLab frontend and exposes the server on host port 10000.
```bash
docker run -it --rm -p 10000:8888 -v "${PWD}":/home/jovyan/work quay.io/jupyter/datascience-notebook:2025-12-31
```
The use of the `-v` flag in the command mounts the current working directory on the host (`${PWD}` in the example command) 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.
Due to the usage of [the `--rm` flag](https://docs.docker.com/reference/cli/docker/container/run/#rm)
Docker automatically cleans up the container and removes the file system when the container exits,
but any changes made to the `~/work` directory and its files in the container will remain intact on the host.
[The `-i` flag](https://docs.docker.com/reference/cli/docker/container/run/#interactive) keeps the container's `STDIN` open, and lets you send input to the container through standard input.
[The `-t` flag](https://docs.docker.com/reference/cli/docker/container/run/#tty) attaches a pseudo-TTY to the container.
```{note}
By default, [jupyter's root_dir](https://jupyter-server.readthedocs.io/en/latest/other/full-config.html) is `/home/jovyan`.
So, new notebooks will be saved there, unless you change the directory in the file browser.
To change the default directory, you must specify `ServerApp.root_dir` by adding this line to the previous command: `start-notebook.py --ServerApp.root_dir=/home/jovyan/work`.
```
## Choosing Jupyter frontend
JupyterLab is the default for all the Jupyter Docker Stacks images.
It is still possible to switch back to Jupyter Notebook (or to launch a different startup command).
You can achieve this by passing the environment variable `DOCKER_STACKS_JUPYTER_CMD=notebook` (or any other valid `jupyter` subcommand) at container startup;
more information is available in the [documentation](https://jupyter-docker-stacks.readthedocs.io/en/latest/using/common.html#alternative-commands).
## Resources
- [Documentation on ReadTheDocs](https://jupyter-docker-stacks.readthedocs.io/en/latest/)
- [Issue Tracker on GitHub](https://github.com/jupyter/docker-stacks/issues)
- [Jupyter Discourse Forum](https://discourse.jupyter.org/)
- [Jupyter Website](https://jupyter.org)
- [Images on Quay.io](https://quay.io/organization/jupyter)
## Acknowledgments
- Starting from `2022-07-05`, `aarch64` self-hosted runners were sponsored by [`@mathbunnyru`](https://github.com/mathbunnyru/).
Please, consider [sponsoring his work](https://github.com/sponsors/mathbunnyru) on GitHub
- Starting from `2023-10-31`, `aarch64` self-hosted runners are sponsored by an amazing [`2i2c non-profit organization`](https://2i2c.org)
- Starting from `2025-02-11`, we use GitHub-hosted `aarch64` runners
## CPU Architectures
- We publish containers for both `x86_64` and `aarch64` platforms
- Single-platform images have either `aarch64-` or `x86_64-` tag prefixes, for example, `quay.io/jupyter/base-notebook:aarch64-python-3.11.6`
- Starting from `2022-09-21`, we create multi-platform images (except `tensorflow-notebook`)
- Starting from `2023-06-01`, we create a multi-platform `tensorflow-notebook` image as well
- Starting from `2024-02-24`, we create CUDA enabled variants of `pytorch-notebook` image for `x86_64` platform
- Starting from `2024-03-26`, we create CUDA enabled variant of `tensorflow-notebook` image for `x86_64` platform
## Using old images
[](https://www.python.org/downloads/ "Python versions supported")
This project only builds one set of images at a time.
If you want to use the older `Ubuntu` and/or `Python` version, you can use the following images:
| Build Date | Ubuntu | Python | Tag |
| ------------ | ------ | ------ | -------------- |
| 2022-10-09 | 20.04 | 3.7 | `1aac87eb7fa5` |
| 2022-10-09 | 20.04 | 3.8 | `a374cab4fcb6` |
| 2022-10-09 | 20.04 | 3.9 | `5ae537728c69` |
| 2022-10-09 | 20.04 | 3.10 | `f3079808ca8c` |
| 2022-10-09 | 22.04 | 3.7 | `b86753318aa1` |
| 2022-10-09 | 22.04 | 3.8 | `7285848c0a11` |
| 2022-10-09 | 22.04 | 3.9 | `ed2908bbb62e` |
| 2023-05-30 | 22.04 | 3.10 | `4d70cf8da953` |
| 2024-08-26 | 22.04 | 3.11 | `00987883e58d` |
| 2024-10-22 | 24.04 | 3.11 | `b74418220768` |
| 2025-08-11 | 24.04 | 3.12 | `82d322f00937` |
| weekly build | 24.04 | 3.13 | `latest` |
## Contributing
Please see the [the documentation](https://jupyter-docker-stacks.readthedocs.io/en/latest/)
for information about how to contribute
[issues](https://jupyter-docker-stacks.readthedocs.io/en/latest/contributing/issues.html),
[features](https://jupyter-docker-stacks.readthedocs.io/en/latest/contributing/features.html),
[recipes](https://jupyter-docker-stacks.readthedocs.io/en/latest/contributing/recipes.html),
[tests](https://jupyter-docker-stacks.readthedocs.io/en/latest/contributing/tests.html),
and [community-maintained stacks](https://jupyter-docker-stacks.readthedocs.io/en/latest/contributing/stacks.html).
## LICENSE
This project is licensed under the terms of the Modified BSD License (also known as New or Revised or 3-Clause BSD).
## About the Jupyter Development Team
The Jupyter Development Team is the set of all contributors to the Jupyter project.
This includes all of the Jupyter subprojects.
The core team that coordinates development on GitHub can be found here:
<https://github.com/jupyter/>.
## Our Copyright Policy
Jupyter uses a shared copyright model. Each contributor maintains copyright
over their contributions to Jupyter. But, it is important to note that these
contributions are typically only changes to the repositories. Thus, the Jupyter
source code, in its entirety is not the copyright of any single person or
institution. Instead, it is the collective copyright of the entire Jupyter
Development Team. If individual contributors want to maintain a record of what
changes/contributions they have specific copyright on, they should indicate
their copyright in the commit message of the change, when they commit the
change to one of the Jupyter repositories.
With this in mind, the following banner should be used in any source code file
to indicate the copyright and license terms:
```text
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
```
## Alternatives
- [b-data](https://github.com/b-data)'s JupyterLab docker stacks - For
[R](https://github.com/b-data/jupyterlab-r-docker-stack),
[Python](https://github.com/b-data/jupyterlab-python-docker-stack),
[MAX/Mojo](https://github.com/b-data/jupyterlab-mojo-docker-stack) and
[Julia](https://github.com/b-data/jupyterlab-julia-docker-stack).
With [code-server](https://github.com/coder/code-server) next to JupyterLab.
Just Python – no [Conda](https://github.com/conda/conda) /
[Mamba](https://github.com/mamba-org/mamba).
- [rocker/binder](https://rocker-project.org/images/versioned/binder.html) -
From the R focused [rocker-project](https://rocker-project.org),
lets you run both RStudio and Jupyter either standalone or in a JupyterHub
- [jupyter/repo2docker](https://github.com/jupyterhub/repo2docker) -
Turn git repositories into Jupyter-enabled Docker Images
- [openshift/source-to-image](https://github.com/openshift/source-to-image) -
A tool for building artifacts from source code and injecting them into docker images
- [jupyter-on-openshift/jupyter-notebooks](https://github.com/jupyter-on-openshift/jupyter-notebooks) -
OpenShift compatible S2I builder for basic notebook images
================================================
FILE: SECURITY.md
================================================
# Security Policy
## Supported Versions
Jupyter Docker Stacks only provides security updates for the latest version of each image.
## Reporting a Vulnerability
The Jupyter Vulnerability Handling Process is described in detail in the [security documentation](https://github.com/jupyter/security/blob/main/docs/vulnerability-handling.md).
================================================
FILE: binder/Dockerfile
================================================
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
# https://quay.io/repository/jupyter/base-notebook?tab=tags
ARG REGISTRY=quay.io
ARG OWNER=jupyter
ARG BASE_IMAGE=$REGISTRY/$OWNER/base-notebook:2025-12-31
FROM $BASE_IMAGE
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"]
ENV TAG="2025-12-31"
COPY --chown=${NB_UID}:${NB_GID} binder/README.ipynb "${HOME}"/README.ipynb
RUN jupyter labextension disable "@jupyterlab/apputils-extension:announcements"
================================================
FILE: binder/README.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# jupyter/base-notebook on Binder\n",
"\n",
"Run the cells below to inspect what's in the [jupyter/base-notebook](https://jupyter-docker-stacks.readthedocs.io/en/latest/using/selecting.html#jupyter-base-notebook) image from the Jupyter Docker Stacks project.\n",
"\n",
"You can launch the classic notebook interface in Binder by replacing `lab/tree/*` with `tree/` in the JupyterLab URL."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"\n",
"print(\n",
" f\"This container is using tag {os.environ['TAG']} of the jupyter/base-notebook image\"\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The Server is running as the following user."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!id"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here's the contents of that user's home directory, the default notebook directory for the server."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!ls -al"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`mamba` is available in the user's path."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!which mamba"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The user has read/write access to the root mamba environment."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!ls -l /opt/conda"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The following packages are mamba-installed in the base image to support [Jupyter Notebook](https://github.com/jupyter/notebook), [JupyterLab](https://github.com/jupyterlab/jupyterlab), and their use in [JupyterHub](https://github.com/jupyterhub/jupyterhub) environments (e.g., [MyBinder](https://mybinder.org/))."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!mamba list"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Other images in the [jupyter/docker-stacks project](https://github.com/jupyter/docker-stacks) include additional libraries. See the [Jupyter Docker Stacks documentation](https://jupyter-docker-stacks.readthedocs.io/en/latest/) for full details."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.4"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
================================================
FILE: docs/conf.py
================================================
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
project = "docker-stacks"
copyright = "2025, Project Jupyter"
author = "Project Jupyter"
version = "latest"
release = "latest"
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
extensions = []
templates_path = ["_templates"]
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
language = "en"
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
html_theme = "alabaster"
html_static_path = ["_static"]
# The file above was generated using sphinx 8.1.3 with this command:
# sphinx-quickstart --project "docker-stacks" --author "Project Jupyter" -v "latest" -r "latest" -l en --no-sep --no-makefile --no-batchfile
# These are custom options for this project
html_theme = "sphinx_book_theme"
html_title = "Docker Stacks documentation"
html_logo = "_static/jupyter-logo.svg"
html_theme_options = {
"logo": {
"text": html_title,
},
"navigation_with_keys": False,
"path_to_docs": "docs",
"repository_branch": "main",
"repository_url": "https://github.com/jupyter/docker-stacks",
"use_download_button": True,
"use_edit_page_button": True,
"use_issues_button": True,
"use_repository_button": True,
}
html_last_updated_fmt = "%Y-%m-%d"
extensions = ["myst_parser", "sphinx_copybutton", "sphinx_last_updated_by_git"]
source_suffix = {
".rst": "restructuredtext",
".md": "markdown",
}
pygments_style = "sphinx"
# MyST configuration reference: https://myst-parser.readthedocs.io/en/latest/configuration.html
myst_heading_anchors = 3
linkcheck_ignore = [
r".*github\.com.*#", # javascript based anchors
r"http://127\.0\.0\.1:.*", # various examples
r"https://mybinder\.org/v2/gh/.*", # lots of 500 errors
r"https://packages\.ubuntu\.com/search\?keywords=openjdk", # frequent read timeouts
r"https://anaconda\.org\/conda-forge", # frequent read timeouts
]
linkcheck_allowed_redirects = {
r"https://results\.pre-commit\.ci/latest/github/jupyter/docker-stacks/main": r"https://results\.pre-commit\.ci/run/github/.*", # Latest main CI build
r"https://github\.com/jupyter/docker-stacks/issues/new.*": r"https://github\.com/login.*", # GitHub wants user to be logon to use this features
r"https://github\.com/orgs/jupyter/teams/docker-image-maintainers/members": r"https://github\.com/login.*",
}
================================================
FILE: docs/contributing/features.md
================================================
# New Features
Thank you for contributing to the Jupyter Docker Stacks!
We review pull requests for new features (e.g., new packages, new scripts, new flags)
to balance the value of the images to the Jupyter community with the cost of maintaining the images over time.
## Suggesting a New Feature
Please follow the process below to suggest a new feature for inclusion in one of the core stacks:
1. Open a [GitHub feature request issue](https://github.com/jupyter/docker-stacks/issues/new?template=feature_request.yml)
describing the feature you'd like to contribute.
2. Discuss with the maintainers whether the addition makes sense
in [one of the core stacks](../using/selecting.md#core-stacks),
as a [way to build a custom set of images](../using/custom-images.md),
as a [recipe in the documentation](recipes.md),
as a [community stack](stacks.md),
or as something else entirely.
## Selection Criteria
Roughly speaking, we evaluate new features based on the following criteria:
- **Usefulness to Jupyter users**:
Is the feature generally applicable across domains?
Does it work with JupyterLab, Jupyter Notebook, JupyterHub, etc.?
- **Fit with the image purpose**:
Does the feature match the theme of the stack to which it will be added?
Would it fit better in a new community stack?
- **The complexity of build/runtime configuration**:
How many lines of code does the feature require in one of the Dockerfiles or startup scripts?
Does it require new scripts entirely?
Do users need to adjust how they use the images?
- **Impact on image metrics**:
How many bytes does the feature and its dependencies add to the image(s)?
How many minutes do they add to the build time?
- **Ability to support the addition**:
Can existing maintainers answer user questions and address future build issues?
Are the contributors interested in helping with long-term maintenance?
Can we write tests to ensure the feature continues to work over the years?
## Submitting a Pull Request
If there's agreement that the feature belongs in one or more of the core stacks:
1. Implement the feature in a local clone of the `jupyter/docker-stacks` project.
2. Please, build the image locally before submitting a pull request.
It shortens the debugging cycle by taking some load off GitHub Actions,
which graciously provides free build services for open-source projects like this one.
If you use `make`, call:
```bash
make build/<somestack>
```
3. [Submit a pull request](https://github.com/PointCloudLibrary/pcl/wiki/A-step-by-step-guide-on-preparing-and-submitting-a-pull-request) (PR) with your changes.
4. Watch for GitHub to report a build success or failure for your PR on GitHub.
5. Discuss changes with the maintainers and address any build issues.
================================================
FILE: docs/contributing/issues.md
================================================
# Project Issues
We appreciate you taking the time to report an issue you encountered while using the Jupyter Docker Stacks.
Please review the following guidelines when reporting your problem.
- Please use GitHub's "Report a Vulnerability" button under Security > Advisories on the appropriate repo,
e.g. [report here for Jupyter Docker Stacks](https://github.com/jupyter/docker-stacks/security/advisories).
You may also send an email to <mailto:security@ipython.org>, but the GitHub reporting system is preferred.
- If you think your problem is unique to the Jupyter Docker Stacks images,
please search the [jupyter/docker-stacks issue tracker](https://github.com/jupyter/docker-stacks/issues?q=is%3Aissue%20)
to see if someone else has already reported the same problem.
If not, please open a [GitHub bug report issue](https://github.com/jupyter/docker-stacks/issues/new?template=bug_report.yml)
and provide all the information requested in the issue template.
Additionally, check the [Troubleshooting Common Problems](../using/troubleshooting.md) page in the documentation before submitting an issue.
- If the issue you're seeing is with one of the open-source libraries included in the Docker images and is reproducible outside the images,
please file a bug with the appropriate open-source project.
- If you have a general question about how to use the Jupyter Docker Stacks in your environment,
in conjunction with other tools, customizations, and so on,
please post your question on the [Jupyter Discourse site](https://discourse.jupyter.org).
================================================
FILE: docs/contributing/lint.md
================================================
# Lint
To enforce some rules, **linters** are used in this project.
Linters can be run either during the **development phase** (by the developer) or the **integration phase** (by GitHub Actions).
To integrate and enforce this process in the project lifecycle, we are using **git hooks** through [pre-commit](https://pre-commit.com/).
## Using pre-commit hooks
### Pre-commit hook installation
_pre-commit_ is a Python package that needs to be installed.
To achieve this, use the generic task to install all Python development dependencies.
```sh
# Install all development dependencies for the project
pip install --upgrade -r requirements-dev.txt
# It can also be installed directly
pip install pre-commit
```
Then the git hooks scripts configured for the project in `.pre-commit-config.yaml` need to be installed in the local git repository.
```sh
pre-commit install
```
### Run
Now, _pre-commit_ (and so configured hooks) will run automatically on `git commit` on each changed file.
However, you can also run it against all files manually.
```{note}
Hadolint pre-commit uses Docker to run, so `docker` should be running while executing this command.
```
```sh
pre-commit run --all-files --hook-stage manual
```
```{note}
We're running `pre-commit` with `--hook-stage manual`, because `pre-commit` is run on modified files only, which doesn't work well with `mypy --follow-imports error`.
More information can be found in [`.pre-commit-config.yaml` file](https://github.com/jupyter/docker-stacks/blob/main/.pre-commit-config.yaml)
```
## Image Lint
To comply with [Docker best practices](https://docs.docker.com/build/building/best-practices/),
we are using the [Hadolint](https://github.com/hadolint/hadolint) tool to analyze each `Dockerfile`.
### Ignoring Rules
Sometimes it is necessary to ignore [some rules](https://github.com/hadolint/hadolint#rules).
The following rules are ignored by default for all images in the `.hadolint.yaml` file.
- [`DL3006`][dl3006]: We use a specific policy to manage image tags.
- The `docker-stacks-foundation` `FROM` clause is fixed but based on an argument (`ARG`).
- Building downstream images from (`FROM`) the latest is done on purpose.
- [`DL3008`][dl3008]: System packages are always updated (`apt-get`) to the latest version.
- [`DL3013`][dl3013]: We always install the latest packages using `pip`
The preferred way to ignore other rules is to flag them in the `Dockerfile`.
You can use a special comment directly above the Dockerfile instruction you want to make an exception for.
Ignore rule comments look like `# hadolint ignore=DL3001,SC1081`.
For example:
```dockerfile
FROM ubuntu
# hadolint ignore=DL3003,SC1035
RUN cd /tmp && echo "hello!"
```
[dl3006]: https://github.com/hadolint/hadolint/wiki/DL3006
[dl3008]: https://github.com/hadolint/hadolint/wiki/DL3008
[dl3013]: https://github.com/hadolint/hadolint/wiki/DL3013
================================================
FILE: docs/contributing/packages.md
================================================
# Package Updates
Generally, we do not pin package versions in our `Dockerfile`s.
Dependency resolution is a difficult thing to do.
All this means that packages might have old versions.
Images are rebuilt weekly, so usually, packages receive updates quite frequently.
```{note}
We pin major.minor version of Python, so this will stay the same even after invoking the `mamba update` command.
```
## Outdated packages
To help identify packages that can be updated, you can use the following helper tool.
It will list all the outdated packages installed in the `Dockerfile`.
Dependencies are filtered to display only the requested packages.
```bash
make check-outdated/base-notebook
# INFO test_outdated:test_outdated.py:80 3/8 (38%) packages could be updated
# INFO test_outdated:test_outdated.py:82
# Package Current Newest
# ---------- --------- --------
# conda 4.7.12 4.8.2
# jupyterlab 1.2.5 2.0.0
# python 3.7.4 3.8.2
```
================================================
FILE: docs/contributing/recipes.md
================================================
# New Recipes
We welcome contributions of [recipes](../using/recipes.md), which are short examples of using, configuring, or extending the Docker Stacks for inclusion in the documentation site.
Follow the process below to add a new recipe:
1. Open the `docs/using/recipes.md` source file.
2. Add a second-level Markdown heading naming your recipe at the bottom of the file (e.g., `## Slideshows with JupyterLab and RISE`)
3. Write the body of your recipe under the heading, including whatever command line, links, etc. you need.
4. If you have a Dockerfile, please put it in a `recipe_code` subdirectory.
This file will be built automatically by [contributed-recipes workflow](https://github.com/jupyter/docker-stacks/blob/main/.github/workflows/contributed-recipes.yml).
5. [Submit a pull request](https://github.com/PointCloudLibrary/pcl/wiki/A-step-by-step-guide-on-preparing-and-submitting-a-pull-request) (PR) with your changes.
Maintainers will respond and work with you to address any formatting or content issues.
================================================
FILE: docs/contributing/stacks.md
================================================
# Community Stacks
We love to see the community create and share new Jupyter Docker images.
We've put together a [cookiecutter project](https://github.com/jupyter/cookiecutter-docker-stacks)
and the documentation below to help you get started defining, building, and sharing your Jupyter environments in Docker.
Following these steps will:
1. Set up a project on GitHub containing a Dockerfile based on any image we provide.
2. Configure GitHub Actions to build and test your image when users submit pull requests to your repository.
3. Configure Quay.io to host your images for others to use.
4. Update the [list of community stacks](../using/selecting.md#community-stacks) in this documentation to include your image.
This approach mirrors how we build and share the core stack images.
Feel free to follow it or pave your path using alternative services and build tools.
## Creating a Project
First, install [cookiecutter](https://github.com/cookiecutter/cookiecutter) using _pip_ or _mamba_:
```bash
pip install cookiecutter # or mamba install cookiecutter
```
Run the cookiecutter command pointing to the [jupyter/cookiecutter-docker-stacks](https://github.com/jupyter/cookiecutter-docker-stacks) project on GitHub.
```bash
cookiecutter https://github.com/jupyter/cookiecutter-docker-stacks.git
```
Enter a name for your new stack image.
This will serve as both the git repository name and the part of the Docker image name after the slash.
```text
stack_name [my-jupyter-stack]:
```
Enter the user or organization name under which this stack will reside on Docker Hub.
You must have access to manage this Docker Hub organization to push images here.
```text
stack_org [my-project]:
```
Select an image from the `jupyter/docker-stacks` project that will serve as the base for your new image.
```text
stack_base_image [quay.io/jupyter/base-notebook]:
```
Enter a longer description of the stack for your README.
```text
stack_description [my-jupyter-stack is a community-maintained Jupyter Docker Stack image]:
```
Create a GitHub repository to store your project.
Initialize your project as a Git repository and push it to GitHub.
```bash
cd <stack_name you chose>
git init
git add .
git commit -m 'Seed repo'
git remote add origin <url from github>
git push -u origin main
```
## Exploring GitHub Actions
1. By default, the newly `.github/workflows/docker.yaml` will trigger the CI pipeline whenever you push to your `main` branch
and when any Pull Requests are made to your repository.
For more details on this configuration, visit the [GitHub Actions documentation on triggers](https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows).
2. Go to your repository and click on the **Actions** tab.
From there, you can click on the workflows on the left-hand side of the screen.

```{note}
The first run is expected to fail because we haven't yet added Docker credentials to push the image
```
3. In the next screen, you will see information about the workflow run and duration.
If you click the button with the workflow name again, you will see the logs for the workflow steps.

## Configuring Docker Hub
```{note}
Jupyter Docker Stacks are hosted on Quay.io, but in this example, we show you how to host your image on Docker Hub.
```
Now, configure Docker Hub to build your stack image and push it to the Docker Hub repository whenever
you merge a GitHub pull request to the main branch of your project.
1. Visit [https://hub.docker.com/](https://hub.docker.com/) and log in.
2. Create a new repository - make sure to use the correct namespace (account or organization).
Enter the name of the image matching the one you entered when prompted with `stack_name` by the cookiecutter.

3. Enter a description for your image.
4. Click on your avatar in the top-right corner and select Account Settings.

5. Click on **Security** and then click on the **New Access Token** button.

6. Enter a meaningful name for your token and click on **Generate**

7. Copy the personal access token displayed on the next screen.
```{note}
**You will not be able to see it again after you close the pop-up window**.
```
8. Head back to your GitHub repository and click on the **Settings tab**.
9. Click on the **Secrets and variables->Actions** section and then on the **New repository secret** button in the top right corner.

10. Create a **DOCKERHUB_TOKEN** secret and paste the Personal Access Token from Docker Hub in the **value** field.

11. Now you're ready to go and you can restart a failed workflow.
## Defining Your Image
Make edits to the Dockerfile in your project to add third-party libraries and configure Jupyter applications.
Refer to the Dockerfiles for the core stacks (e.g., [jupyter/datascience-notebook](https://github.com/jupyter/docker-stacks/blob/main/images/datascience-notebook/Dockerfile))
to get a feel for what's possible and the best practices.
[Submit pull requests](https://github.com/PointCloudLibrary/pcl/wiki/A-step-by-step-guide-on-preparing-and-submitting-a-pull-request)
to your project repository on GitHub.
Ensure your image builds correctly on GitHub Actions before merging to the main branch.
After merging to the main branch, your image will be built and pushed to the Docker Hub automatically.
## Sharing Your Image
Finally, if you'd like to add a link to your project to this documentation site, please do the following:
1. Fork the [jupyter/docker-stacks](https://github.com/jupyter/docker-stacks) GitHub repository.
2. Open the `docs/using/selecting.md` source file and locate the **Community Stacks** section in your fork.
3. Add a table entry with a link to your project, a binder link, and a short description of what your Docker image contains.
4. [Submit a pull request](https://github.com/PointCloudLibrary/pcl/wiki/A-step-by-step-guide-on-preparing-and-submitting-a-pull-request) (PR) with your changes.
Maintainers will respond and work with you to address any formatting or content issues.
================================================
FILE: docs/contributing/tests.md
================================================
# Image Tests
We greatly appreciate Pull Requests that extend the automated tests that vet the basic functionality of the Docker images.
## How the Tests Work
A [GitHub Actions workflow](https://github.com/jupyter/docker-stacks/blob/main/.github/workflows/docker-build-test-upload.yml)
runs tests against pull requests submitted to the `jupyter/docker-stacks` repository.
We use the `pytest` module to run tests on the image.
`conftest.py` and `pytest.ini` in the `tests` folder define the environment in which tests are run.
[Read `pytest` documentation](https://docs.pytest.org/en/latest/contents.html).
The actual image-specific test files are located in folders like `tests/by_image/<somestack>/` (e.g., `tests/by_image/docker-stacks-foundation/`, etc.).
```{note}
If your test is located in `tests/by_image/<somestack>/`, it will be run against the `jupyter/<somestack>` image and against all the [images inherited from this image](../using/selecting.md#image-relationships).
```
Many tests make use of global [pytest fixtures](https://docs.pytest.org/en/latest/reference/fixtures.html)
defined in the [conftest.py](https://github.com/jupyter/docker-stacks/blob/main/tests/conftest.py) file.
## Unit tests
You can add a unit test if you want to run a Python script in one of our images.
You should create a `tests/by_image/<somestack>/units/` directory, if it doesn't already exist, and put your file there.
Files in this folder will be executed in the container when tests are run.
You can see an [TensorFlow package example here](https://github.com/jupyter/docker-stacks/blob/HEAD/tests/by_image/tensorflow-notebook/units/unit_tensorflow.py).
## Contributing New Tests
Please follow the process below to add new tests:
1. Add your test code to one of the modules in the `tests/by_image/<somestack>/` directory or create a new module.
2. Build one or more images you intend to test and run the tests locally.
If you use `make`, call:
```bash
make build/<somestack>
make test/<somestack>
```
3. [Submit a pull request](https://github.com/PointCloudLibrary/pcl/wiki/A-step-by-step-guide-on-preparing-and-submitting-a-pull-request)
(PR) with your changes.
4. Watch for GitHub to report a build success or failure for your PR on GitHub.
5. Discuss changes with the maintainers and address any issues running the tests on GitHub.
================================================
FILE: docs/index.rst
================================================
.. include:: ../README.md
:parser: myst_parser.sphinx_
Table of Contents
-----------------
.. toctree::
:maxdepth: 2
:caption: User Guide
using/selecting
using/running
using/common
using/specifics
using/recipes
using/custom-images
using/troubleshooting
using/faq
using/changelog
.. toctree::
:maxdepth: 2
:caption: Contributor Guide
contributing/issues
contributing/features
contributing/tests
contributing/lint
contributing/recipes
contributing/stacks
contributing/packages
.. toctree::
:maxdepth: 2
:caption: Maintainer Guide
maintaining/new-images-and-packages-policy
maintaining/tagging
maintaining/tasks
.. toctree::
:maxdepth: 2
:caption: Getting Help
Issue Tracker on GitHub <https://github.com/jupyter/docker-stacks/issues>
Jupyter Discourse Forum <https://discourse.jupyter.org>
Jupyter Website <https://jupyter.org>
================================================
FILE: docs/maintaining/new-images-and-packages-policy.md
================================================
# New images / packages policy
There are many things we consider while adding new images and packages.
Here is a non-exhaustive list of things we do care about:
1. **Software health**, details, and maintenance status
- reasonable versioning is adopted, and the version is considered to be stable
- has been around for several years
- the package maintains documentation
- a changelog is actively maintained
- a release procedure with helpful automation is established
- multiple people are involved in the maintenance of the project
- provides a `conda-forge` package besides a `pypi` package, where both are kept up to date
- supports both `x86_64` and `aarch64` architectures
2. **Installation consequences**
- GitHub Actions build time
- Image sizes
- All requirements should be installed as well
3. Jupyter Docker Stacks _**image fit**_
- new package or stack is changing (or inherits from) the most suitable stack
4. **Software impact** for users of docker-stacks images
- How this image can help existing users, or maybe reduce the need to build new images
5. Why it shouldn't just be a documented **recipe**
6. Impact on **security**
- Does the package open additional ports, or add new web endpoints, that could be exploited?
With all this in mind, we have a voting group, that consists of
[@mathbunnyru](https://github.com/mathbunnyru),
[@consideRatio](https://github.com/consideRatio),
[@yuvipanda](https://github.com/yuvipanda), and
[@manics](https://github.com/manics).
This voting group is responsible for accepting or declining new packages and stacks.
The change is accepted, if there are **at least 2 positive votes**.
================================================
FILE: docs/maintaining/tagging.md
================================================
# Tags and manifests
The main purpose of the source code in [the `tagging` folder](https://github.com/jupyter/docker-stacks/tree/main/tagging) is to
properly write tags file, build history line and manifest for a single-platform image,
apply these tags, and then merge single-platform images into one multi-arch image.
## What is a tag and a manifest
A tag is a label attached to a Docker image identifying specific attributes or versions.
For example, an image `jupyter/base-notebook` with Python 3.10.5 will have a full image name `quay.io/jupyter/base-notebook:python-3.10.5`.
These tags are pushed to our [Quay.io registry](https://quay.io/organization/jupyter).
A manifest is a description of important image attributes written in Markdown format.
For example, we dump all `conda` packages with their versions into the manifest.
## Main principles
- All images are organized in a hierarchical tree.
More info on [image relationships](../using/selecting.md#image-relationships).
- `TaggerInterface` and `ManifestInterface` are interfaces for functions to generate tags and manifest pieces by running commands in Docker containers.
- Tags and manifests are reevaluated for each image in the hierarchy since values may change between parent and child images.
- To tag an image and create its manifest and build history line, run `make hook/<somestack>` (e.g., `make hook/base-notebook`).
## Utils
### DockerRunner
`DockerRunner` is a helper class to easily run a docker container and execute commands inside this container:
```{literalinclude} tagging_examples/docker_runner.py
:language: py
:lines: 3-
```
### GitHelper
`GitHelper` methods are run in the current `git` repo and give the information about the last commit hash and commit message:
```{literalinclude} tagging_examples/git_helper.py
:language: py
:lines: 3-
```
The prefix of commit hash (namely, 12 letters) is used as an image tag to make it easy to inherit from a fixed version of a docker image.
## Taggers and Manifests
### Tagger
`Tagger` is a function that runs commands inside a docker container to calculate a tag for an image.
All the taggers follow `TaggerInterface`:
```{literalinclude} ../../tagging/taggers/tagger_interface.py
:language: py
:start-at: TaggerInterface
```
So, the `tagger(container)` gets a docker container as an input and returns a tag.
For example:
```{literalinclude} ../../tagging/taggers/sha.py
:language: py
:start-at: def
```
- `taggers/` subdirectory contains all taggers.
- `apps/write_tags_file.py`, `apps/apply_tags.py`, and `apps/merge_tags.py` are Python executables used to write tags for an image, apply tags from a file, and create multi-arch images.
### Manifest
All manifest functions except `build_info_manifest` follow `ManifestInterface`
and `manifest(container)` method returns a piece of the manifest.
```{literalinclude} ../../tagging/manifests/manifest_interface.py
:language: py
:start-at: ManifestInterface
```
For example:
```{literalinclude} ../../tagging/manifests/apt_packages.py
:language: py
:start-at: def
```
where:
- `quoted_output(container, cmd)` simply runs the command inside a container using `DockerRunner.exec_cmd` and wraps it to triple quotes to create a valid markdown piece.
It also adds the command which was run to the markdown piece.
- `manifests/` subdirectory contains all the manifests.
- `apps/write_manifest.py` is a Python executable to create the build manifest and history line for an image.
## Images Hierarchy
All images' dependencies on each other and what taggers and manifests are applicable to them are defined in `hierarchy/images_hierarchy.py`.
`hierarchy/get_taggers.py` and `hierarchy/get_manifests.py` define functions to get the taggers and manifests for a specific image.
================================================
FILE: docs/maintaining/tagging_examples/docker_runner.py
================================================
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
from tagging.utils.docker_runner import DockerRunner
with DockerRunner("ubuntu") as container:
DockerRunner.exec_cmd(container, cmd="env")
================================================
FILE: docs/maintaining/tagging_examples/git_helper.py
================================================
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
from tagging.utils.git_helper import GitHelper
print("Git hash:", GitHelper.commit_hash())
print("Git message:", GitHelper.commit_message())
================================================
FILE: docs/maintaining/tasks.md
================================================
# Maintainer Playbook
## Merging Pull Requests
To build new images and publish them to the Registry, do the following:
1. Make sure GitHub Actions status checks pass for the PR.
2. Merge the PR.
3. Monitor the merge commit GitHub Actions status.
```{note}
GitHub Actions are pretty reliable, so please investigate if some error occurs.
Building Docker images in PRs is the same as building them in the default branch.
The only difference is that single-platform images are pushed to Registry and then tags are merged for `x86_64` and `aarch64`.
```
4. Avoid merging another PR to the main branch until all pending builds in the main branch are complete.
This way, you will know which commit might have broken the build
and also have the correct tags for moving tags (like the `Python` version).
## Updating Python version
When a new `Python` version is released, we wait for:
- all the dependencies to be available (as wheels or in `conda-forge`).
- the first `Python` patch release for this version.
This allows us to avoid many bugs, which can happen in a major release.
## Updating the Ubuntu Base Image
`jupyter/docker-stacks-foundation` is based on the LTS Ubuntu docker image.
We wait for the first point release of the new LTS Ubuntu before updating the version.
Other images are directly or indirectly inherited from `jupyter/docker-stacks-foundation`.
We rebuild our images automatically each week, which means they frequently receive updates.
When there's a security fix in the Ubuntu base image, it's a good idea to manually trigger the rebuild of images
[from the GitHub Actions workflow UI](https://github.com/jupyter/docker-stacks/actions/workflows/docker.yml).
Pushing the `Run Workflow` button will trigger this process.
## Adding a New Core Image to the Registry
```{note}
In general, we do not add new core images and ask contributors to either
create a [recipe](../using/recipes.md) or [community stack](../contributing/stacks.md).
We have a [policy](./new-images-and-packages-policy.md), which we consider when adding new images or new packages to existing images.
```
[Take a look at an example](https://github.com/jupyter/docker-stacks/pull/1936/files) of adding a new image.
When there's a new stack definition, check before merging the PR:
1. PR includes an update to the stack overview diagram
[in the documentation](../using/selecting.md#image-relationships).
The image links to the [blockdiag source](http://interactive.blockdiag.com/) used to create it.
2. PR updates the [Makefile](https://github.com/jupyter/docker-stacks/blob/main/Makefile).
3. Necessary Tagger(s)/Manifest(s) are added for the new image
in the [tagging](https://github.com/jupyter/docker-stacks/tree/main/tagging) folder.
4. A new repository is created in the `jupyter` organization in the Registry,
and it's named after the stack folder in the git repo.
5. Robot `Write` permission is added in the `Repository Settings`.
## Adding a New Registry Owner Account
1. Visit <https://quay.io/organization/jupyter/teams/owners>
2. Add the maintainer's username.
## Restarting a failed build
If an automated build in GitHub Actions fails, you can restart the failed jobs on GitHub.
You can also download the artifacts and investigate them for any issues.
================================================
FILE: docs/requirements.txt
================================================
# ReadTheDocs environment contains old package versions preinstalled
# So, to ensure we have modern packages, we pin minimum versions of the packages we need
docutils>=0.17.1
myst-parser>=0.18.0
sphinx>=4.5.0
sphinx-book-theme>=1.0.0
sphinx-copybutton>=0.5.0
sphinx-last-updated-by-git>=0.3.4
================================================
FILE: docs/using/changelog.md
================================================
```{include} ../../CHANGELOG.md
```
<!-- markdownlint-disable-file MD041 -->
================================================
FILE: docs/using/common.md
================================================
# Common Features
Except for `jupyter/docker-stacks-foundation`, a container launched from any Jupyter Docker Stacks image runs a Jupyter Server with the JupyterLab frontend.
The container does so by executing a `start-notebook.py` script.
This script configures the internal container environment and then runs `jupyter lab`, passing any command-line arguments received.
This page describes the options supported by the startup script and how to bypass it to run alternative commands.
## Jupyter Server Options
You can pass [Jupyter Server options](https://jupyter-server.readthedocs.io/en/latest/operators/public-server.html) to the `start-notebook.py` script when launching the container.
1. For example, to secure the Jupyter Server with a [custom password](https://jupyter-server.readthedocs.io/en/latest/operators/public-server.html#preparing-a-hashed-password)
hashed using `jupyter_server.auth.passwd()` instead of the default token,
you can run the following (this hash was generated for the `my-password` password):
```bash
docker run -it --rm -p 8888:8888 quay.io/jupyter/base-notebook \
start-notebook.py --PasswordIdentityProvider.hashed_password='argon2:$argon2id$v=19$m=10240,t=10,p=8$JdAN3fe9J45NvK/EPuGCvA$O/tbxglbwRpOFuBNTYrymAEH6370Q2z+eS1eF4GM6Do'
```
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 Jupyter Server, you can run the following:
```bash
docker run -it --rm -p 8888:8888 quay.io/jupyter/base-notebook \
start-notebook.py --ServerApp.base_url=/customized/url/prefix/
```
## Docker Options
You may instruct the `start-notebook.py` script to customize the container environment before launching the Server.
You do so by passing arguments to the `docker run` command.
### User-related configurations
- `-e NB_USER=<username>` - The desired username and associated home folder.
The default value is `jovyan`.
Setting `NB_USER` redefines the `jovyan` default user and ensures that the desired user has the correct file permissions
for the new home directory created at `/home/<username>`.
For this option to take effect, you **must** run the container with `--user root`, set the working directory `-w "/home/<username>"`
and set the environment variable `-e CHOWN_HOME=yes`.
_Example usage:_
```bash
docker run -it --rm \
-p 8888:8888 \
--user root \
-e NB_USER="my-username" \
-e CHOWN_HOME=yes \
-w "/home/my-username" \
quay.io/jupyter/base-notebook
```
```{note}
If you set `NB_USER` to `root`, the `root` home dir will be set to `/home/root`.
See discussion [here](https://github.com/jupyter/docker-stacks/issues/2042).
```
- `-e NB_UID=<numeric uid>` - Instructs the startup script to switch the numeric user ID of `${NB_USER}` to the given value.
The default value is `1000`.
This feature is useful when mounting host volumes with specific owner permissions.
You **must** run the container with `--user root` for this option to take effect.
(The startup script will `su ${NB_USER}` after adjusting the user ID.)
Instead, you might consider using the modern Docker-native options [`--user`](https://docs.docker.com/engine/containers/run/#user) and
[`--group-add`](https://docs.docker.com/engine/containers/run/#additional-groups) - see the last bullet in this section for more details.
See bullet points regarding `--user` and `--group-add`.
- `-e NB_GID=<numeric gid>` - Instructs the startup script to change the primary group of `${NB_USER}` to `${NB_GID}`
(the new group is added with a name of `${NB_GROUP}` if it is defined. Otherwise, the group is named `${NB_USER}`).
This feature is useful when mounting host volumes with specific group permissions.
You **must** run the container with `--user root` for this option to take effect.
(The startup script will `su ${NB_USER}` after adjusting the group ID.)
Instead, you might consider using modern Docker options `--user` and `--group-add`.
See bullet points regarding `--user` and `--group-add`.
The user is added to the supplemental group `users` (gid 100) to grant write access to the home directory and `/opt/conda`.
If you override the user/group logic, ensure the user stays in the group `users` if you want them to be able to modify files in the image.
- `-e NB_GROUP=<name>` - The name used for `${NB_GID}`, which defaults to `${NB_USER}`.
This group name is only used if `${NB_GID}` is specified and completely optional: there is only a cosmetic effect.
- `--user 5000 --group-add users` - Launches the container with a specific user ID and adds that user to the `users` group so that it can modify files in the default home directory and `/opt/conda`.
You can use these arguments as alternatives to setting `${NB_UID}` and `${NB_GID}`.
## Permission-specific configurations
- `-e NB_UMASK=<umask>` - Configures Jupyter to use a different `umask` value from default, i.e. `022`.
For example, if setting `umask` to `002`, new files will be readable and writable by group members instead of the owner only.
[Check this Wikipedia article](https://en.wikipedia.org/wiki/Umask) for an in-depth description of `umask` and suitable values for multiple needs.
While the default `umask` value should be sufficient for most use cases, you can set the `NB_UMASK` value to fit your requirements.
```{note}
When `NB_UMASK` is set, it only applies to the Jupyter process itself -
you cannot use it to set a `umask` for additional files created during `run-hooks.sh`.
For example, via `pip` or `conda`.
If you need to set a `umask` for these, you **must** set the `umask` value for each command.
```
- `-e CHOWN_HOME=yes` - Instructs the startup script to change the `${NB_USER}` home directory owner and group to the current value of `${NB_UID}` and `${NB_GID}`.
This change will take effect even if the user home directory is mounted from the host using `-v` as described below.
The change is **not** applied recursively by default.
You can modify the `chown` behavior by setting `CHOWN_HOME_OPTS` (e.g., `-e CHOWN_HOME_OPTS='-R'`).
- `-e CHOWN_EXTRA="<some dir>,<some other dir>"` - Instructs the startup script to change the owner and group of each comma-separated container directory to the current value of `${NB_UID}` and `${NB_GID}`.
The change is **not** applied recursively by default.
You can modify the `chown` behavior by setting `CHOWN_EXTRA_OPTS` (e.g., `-e CHOWN_EXTRA_OPTS='-R'`).
- `-e GRANT_SUDO=yes` - Instructs the startup script to grant the `NB_USER` user passwordless `sudo` capability.
You do **not** need this option to allow the user to `conda` or `pip` install additional packages.
This option is helpful for cases when you wish to give `${NB_USER}` the ability to install OS packages with `apt` or modify other root-owned files in the container.
You **must** run the container with `--user root` for this option to take effect.
(The `start-notebook.py` 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 runs on an isolated host.**
### Additional runtime configurations
- `-e GEN_CERT=yes` - Instructs the startup script to generate a self-signed SSL certificate.
Configures Jupyter Server to use it to accept encrypted HTTPS connections.
- `-e DOCKER_STACKS_JUPYTER_CMD=<jupyter command>` - Instructs the startup script to run `jupyter ${DOCKER_STACKS_JUPYTER_CMD}` instead of the default `jupyter lab` command.
See [Switching back to the classic notebook or using a different startup command][switch_back] for available options.
This setting is helpful in container orchestration environments where setting environment variables is more straightforward than changing 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 installing extensions that require restarting Jupyter.
- `-v /some/host/folder/for/work:/home/jovyan/work` - Mounts a host machine directory as a folder in the container.
This configuration is useful for preserving notebooks and other work even after the container has been destroyed.
**You must grant the within-container notebook user or group (`NB_UID` or `NB_GID`) write access to the host directory (e.g., `sudo chown 1000 /some/host/folder/for/work`).**
- `-e JUPYTER_ENV_VARS_TO_UNSET=ADMIN_SECRET_1,ADMIN_SECRET_2` - Unsets specified environment variables in the default startup script.
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.
This way, the user could use any option supported by the `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
You can further customize the container environment by adding shell scripts (`*.sh`) to be sourced
or executables (`chmod +x`) to be run to the paths below:
- `/usr/local/bin/start-notebook.d/` - handled **before** any of the standard options noted above is applied
- `/usr/local/bin/before-notebook.d/` - handled **after** all the standard options noted above are applied
and ran right before the Server launches
[Open the `run-hooks.sh` script](https://github.com/jupyter/docker-stacks/blob/main/images/docker-stacks-foundation/run-hooks.sh) and how it's used in the [`start.sh`](https://github.com/jupyter/docker-stacks/blob/main/images/docker-stacks-foundation/start.sh)
script for execution details.
## SSL Certificates
You may mount an SSL key and certificate file into a container and configure the Jupyter Server to use them to accept HTTPS connections.
For example, to mount a host folder containing a `notebook.key` and `notebook.crt` and use them, you might run the following:
```bash
docker run -it --rm -p 8888:8888 \
-v /some/host/folder:/etc/ssl/notebook \
quay.io/jupyter/base-notebook \
start-notebook.py \
--ServerApp.keyfile=/etc/ssl/notebook/notebook.key \
--ServerApp.certfile=/etc/ssl/notebook/notebook.crt
```
Alternatively, you may mount a single PEM file containing both the key and certificate.
For example:
```bash
docker run -it --rm -p 8888:8888 \
-v /some/host/folder/notebook.pem:/etc/ssl/notebook.pem \
quay.io/jupyter/base-notebook \
start-notebook.py \
--ServerApp.certfile=/etc/ssl/notebook.pem
```
In either case, Jupyter Server expects the key and certificate to be a **base64 encoded text file**.
The certificate file or PEM may contain one or more certificates (e.g., server, intermediate, and root).
For additional information about using SSL, see the following:
- The [docker-stacks/examples](https://github.com/jupyter/docker-stacks/tree/main/examples)
for information about how to use
[Let's Encrypt](https://letsencrypt.org/) certificates when you run these stacks on a publicly visible domain.
- The [`jupyter_server_config.py`](https://github.com/jupyter/docker-stacks/blob/main/images/base-notebook/jupyter_server_config.py)
file for how this Docker image generates a self-signed certificate.
- The [Jupyter Server documentation](https://jupyter-server.readthedocs.io/en/latest/operators/public-server.html#securing-a-jupyter-server)
for best practices about securing a public Server in general.
## Alternative Commands
### Switching back to the classic notebook or using a different startup command
JupyterLab, built on top of Jupyter Server, is now the default for all the images of the stack.
However, switching back to the classic notebook or using a different startup command is still possible.
You can achieve this by setting the environment variable `DOCKER_STACKS_JUPYTER_CMD` at container startup.
The table below shows some options.
Since `Jupyter Notebook v7` `jupyter-server` is used as a backend.
| `DOCKER_STACKS_JUPYTER_CMD` | Frontend |
| --------------------------- | ---------------- |
| `lab` (default) | JupyterLab |
| `notebook` | Jupyter Notebook |
| `nbclassic` | NbClassic |
| `server` | None |
| `retro`\* | RetroLab |
```{note}
- Changing frontend for **JupyterHub singleuser image** is described in [JupyterHub docs](https://jupyterhub.readthedocs.io/en/latest/howto/configuration/config-user-env.html#switching-back-to-the-classic-notebook).
- \* `retro` is not installed at this time, but it could be the case in the future or in a community stack.
- Any other valid `jupyter` subcommand that starts the Jupyter Application can be used.
```
Example:
```bash
# Run Jupyter Server with the Jupyter Notebook frontend
docker run -it --rm \
-p 8888:8888 \
-e DOCKER_STACKS_JUPYTER_CMD=notebook \
quay.io/jupyter/base-notebook
# Executing the command: start-notebook.py
# Executing: jupyter notebook
# ...
# Use Jupyter NBClassic frontend
docker run -it --rm \
-p 8888:8888 \
-e DOCKER_STACKS_JUPYTER_CMD=nbclassic \
quay.io/jupyter/base-notebook
# Executing the command: start-notebook.py
# Executing: jupyter nbclassic
# ...
```
### `start.sh`
Most of the configuration options in the `start-notebook.py` script are handled by an internal `start.sh` script that automatically runs before the command provided to the container
(it's set as the container entrypoint).
This allows you to specify an arbitrary command that takes advantage of all these features.
For example, to run the text-based `ipython` console in a container, do the following:
```bash
docker run -it --rm quay.io/jupyter/base-notebook ipython
```
This script is handy when you derive a new Dockerfile from this image and install additional Jupyter applications with subcommands like `jupyter console`, `jupyter kernelgateway`, etc.
## Conda Environments
The default Python 3.x [Conda environment](https://docs.conda.io/projects/conda/en/latest/user-guide/concepts/environments.html) resides in `/opt/conda`.
The `/opt/conda/bin` directory is part of the default `jovyan` user's `${PATH}`.
That directory is also searched for binaries when run using `sudo` (`sudo my_binary` will search for `my_binary` in `/opt/conda/bin/`).
The `jovyan` user has full read/write access to the `/opt/conda` directory.
You can use either `mamba`, `pip`, or `conda` (`mamba` is recommended) to install new packages without any additional permissions.
```bash
# install a package into the default (python 3.x) environment and cleanup it after
# the installation
mamba install --yes some-package && \
mamba clean --all -f -y && \
fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}"
pip install --no-cache-dir some-package && \
fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}"
conda install --yes some-package && \
conda clean --all -f -y && \
fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}"
```
### Using Alternative Channels
Conda is configured by default to use only the [`conda-forge`](https://anaconda.org/conda-forge) channel.
However, you can use alternative channels, either one-shot by overwriting the default channel in the installation command or by configuring `mamba` to use different channels.
The examples below show how to use the [anaconda default channels](https://repo.anaconda.com/pkgs/main) instead of `conda-forge` to install packages.
```bash
# using defaults channels to install a package
mamba install --channel defaults humanize
# configure conda to add default channels at the top of the list
conda config --system --prepend channels defaults
# install a package
mamba install --yes humanize && \
mamba clean --all -f -y && \
fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}"
```
[switch_back]: #switching-back-to-the-classic-notebook-or-using-a-different-startup-command
================================================
FILE: docs/using/custom-images.md
================================================
# Building a custom set of images
This section describes how to build a custom set of images.
It may be helpful if you need to change the Ubuntu or Python version, or to make a significant change to the build process itself.
This project only builds one set of images at a time.
If you want to use older images, [take a look here](../index.rst/#using-old-images).
## Automating your build using template cookiecutter project
If you wish to build your own image on top of one of our images and automate your build process,
please, [take a look at cookiecutter template](../contributing/stacks.md).
## Custom arguments
Our repository provides several customization points:
- `ROOT_IMAGE` (docker argument) - the parent image for `docker-stacks-foundation` image
- `PYTHON_VERSION` (docker argument) - the Python version to install in `docker-stacks-foundation` image
- `REGISTRY`, `OWNER`, `BASE_IMAGE` (docker arguments) - they allow to specify parent image for all the other images
- `REGISTRY`, `OWNER` (part of `env` in some GitHub workflows) - these allow to properly tag and refer to images during following steps:
- [`build-test-upload`](https://github.com/jupyter/docker-stacks/blob/main/.github/workflows/docker-build-test-upload.yml)
- [`contributed-recipes`](https://github.com/jupyter/docker-stacks/blob/main/.github/workflows/contributed-recipes.yml)
- [`tag-push-merge`](https://github.com/jupyter/docker-stacks/blob/main/.github/workflows/docker-tag-push-merge.yml)
These customization points can't be changed during runtime.
Read more about [Docker build arguments](https://docs.docker.com/build/building/variables/#arg-usage-example) and [GitHub environment variables for a single workflow](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#defining-environment-variables-for-a-single-workflow).
## Building stack images with custom arguments
A selection of prebuilt images are available from [Quay.io](https://quay.io/organization/jupyter),
however, it's impossible to cater to everybody's needs.
For extensive customization with an automated build pipeline,
you may wish to create a [community-maintained stack](../contributing/stacks),
however, for minor customizations, this may be overkill.
For example, you may wish to use the same Jupyter stacks but built on a different base image,
or built with a different Python version.
To achieve this you can use [Docker Bake](https://docs.docker.com/build/bake/)
to build the stacks locally with custom arguments.
```{note}
Custom arguments may result in build errors due to incompatibility.
If so your use-case may require a fully customized stack.
```
As a basic example, if you want to build a custom image based on the `minimal-notebook` image using `Python 3.12`,
then with a Dockerfile like:
```{code-block} Dockerfile
:caption: Dockerfile
ARG BASE_IMAGE=minimal-notebook
FROM $BASE_IMAGE
...
```
Include the file below in your project:
```{literalinclude} recipe_code/docker-bake.custom-python.hcl
:force:
:language: hcl
:caption: docker-bake.hcl
```
To build this stack, in the same directory run:
```bash
docker buildx bake
```
Docker Bake then determines the correct build order from the `contexts` parameters
and builds the stack as requested.
This image can then be run the same way as any other image provided by this project, for example:
```bash
docker run -it --rm -p 8888:8888 custom-jupyter
```
or referenced in a Docker Compose file.
## Forking our repository
If for some reason, you need to change more things in our images, feel free to fork it and change it any way you want.
If your customization is easy to backport to the main repo and might be helpful for other users, feel free to create a PR.
It is almost always a great idea to keep your diff as small as possible and to merge/rebase the latest version of our repo in your project.
================================================
FILE: docs/using/faq.md
================================================
# Frequently Asked Questions (FAQ)
## How to persist user data
There are two types of data you might want to persist.
1. If you want to persist your environment (i.e. packages installed by `mamba`, `conda`, `pip`, `apt-get`, and so on),
then you should create an inherited image and install packages only once while building your Dockerfile.
Take a look at [an example of using `mamba` and `pip`](./recipes.md#using-mamba-install-recommended-or-pip-install-in-a-child-docker-image) in a child image.
```{note}
If you install a package inside a running container (for example you run `pip install <package>` in a terminal),
it won't be preserved when you next run your image.
To make it work, install this package in your inherited image and rerun the `docker build` command.
```
2. If you want to persist user data (files created by you, like `Python` scripts, notebooks, text files, and so on),
then you should use a
[Docker bind mount](https://docs.docker.com/engine/storage/bind-mounts/) or
[Docker Volume](https://docs.docker.com/engine/storage/volumes/).
You can find [an example of using a bind mount here](./running.md#example-2).
There is also [a mount troubleshooting section](./troubleshooting.md#permission-denied-when-mounting-volumes) if you experience any issues.
## Why we don't add your favorite package
We have lots of users with different packages they want to use.
Adding them all is impossible, so we have several images to choose from.
[Choose the image](selecting.md) that is closest to your needs, and feel free to [add your package on top of our images](recipes.md#using-mamba-install-recommended-or-pip-install-in-a-child-docker-image).
## Who is `jovyan`
As described [in this issue comment](https://github.com/jupyter/docker-stacks/issues/358#issuecomment-288844834):
```text
Jo·vy·an
/ˈjōvēən/
noun – an inhabitant of Jupyter
```
`Jovyan` is often a special term used to describe members of the Jupyter community.
It is also used as the user ID in the Jupyter Docker stacks or referenced in conversations.
You can find more information on [the Jupyter Community documentation](https://docs.jupyter.org/en/latest/community/content-community.html#what-is-a-jovyan).
## How to give root permissions to the user
We have a [recipe for enabling root permissions](recipes.md#using-sudo-within-a-container).
================================================
FILE: docs/using/recipe_code/custom_environment.dockerfile
================================================
ARG BASE_IMAGE=quay.io/jupyter/minimal-notebook
FROM $BASE_IMAGE
# Name your environment and choose the Python version
ARG env_name=python313
ARG py_ver=3.13
# You can add additional libraries here
RUN mamba create --yes -p "${CONDA_DIR}/envs/${env_name}" \
python=${py_ver} \
'ipykernel' \
'jupyterlab' && \
mamba clean --all -f -y
# Alternatively, you can comment out the lines above and uncomment those below
# if you'd prefer to use a YAML file present in the docker build context
# COPY --chown=${NB_UID}:${NB_GID} environment.yml /tmp/
# RUN mamba env create -p "${CONDA_DIR}/envs/${env_name}" -f /tmp/environment.yml && \
# mamba clean --all -f -y
# Create Python kernel and link it to jupyter
RUN "${CONDA_DIR}/envs/${env_name}/bin/python" -m ipykernel install --user --name="${env_name}" && \
fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}"
# Any additional `pip` installs can be added by using the following line
# Using `mamba` is highly recommended though
RUN "${CONDA_DIR}/envs/${env_name}/bin/pip" install --no-cache-dir \
'flake8'
# This changes the custom Python kernel so that the custom environment will
# be activated for the respective Jupyter Notebook and Jupyter Console
# hadolint ignore=DL3059
RUN /opt/setup-scripts/activate_notebook_custom_env.py "${env_name}"
# Comment the line above and uncomment the section below instead to activate the custom environment by default
# Note: uncommenting this section makes "${env_name}" default both for Jupyter Notebook and Terminals
# More information here: https://github.com/jupyter/docker-stacks/pull/2047
# USER root
# RUN \
# # This changes a startup hook, which will activate the custom environment for the process
# echo conda activate "${env_name}" >> /usr/local/bin/before-notebook.d/10activate-conda-env.sh && \
# # This makes the custom environment default in Jupyter Terminals for all users which might be created later
# echo conda activate "${env_name}" >> /etc/skel/.bashrc && \
# # This makes the custom environment default in Jupyter Terminals for already existing NB_USER
# echo conda activate "${env_name}" >> "/home/${NB_USER}/.bashrc"
USER ${NB_UID}
================================================
FILE: docs/using/recipe_code/dask_jupyterlab.dockerfile
================================================
ARG BASE_IMAGE=quay.io/jupyter/base-notebook
FROM $BASE_IMAGE
# Install the Dask dashboard
RUN mamba install --yes 'dask-labextension' && \
mamba clean --all -f -y && \
fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}"
# Dask Scheduler port
EXPOSE 8787
================================================
FILE: docs/using/recipe_code/docker-bake.custom-python.hcl
================================================
group "default" {
targets = ["custom-notebook"]
}
target "foundation" {
context = "https://github.com/jupyter/docker-stacks.git#main:images/docker-stacks-foundation"
args = {
PYTHON_VERSION = "3.13"
}
tags = ["docker-stacks-foundation"]
}
target "base-notebook" {
context = "https://github.com/jupyter/docker-stacks.git#main:images/base-notebook"
contexts = {
docker-stacks-foundation = "target:foundation"
}
args = {
BASE_IMAGE = "docker-stacks-foundation"
}
tags = ["base-notebook"]
}
target "minimal-notebook" {
context = "https://github.com/jupyter/docker-stacks.git#main:images/minimal-notebook"
contexts = {
base-notebook = "target:base-notebook"
}
args = {
BASE_IMAGE = "base-notebook"
}
tags = ["minimal-notebook"]
}
target "custom-notebook" {
context = "."
contexts = {
minimal-notebook = "target:minimal-notebook"
}
args = {
BASE_IMAGE = "minimal-notebook"
}
tags = ["custom-jupyter"]
}
================================================
FILE: docs/using/recipe_code/generate_matrix.py
================================================
#!/usr/bin/env python3
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
import json
from pathlib import Path
THIS_DIR = Path(__file__).parent.resolve()
RUNS_ON = ["ubuntu-24.04", "ubuntu-24.04-arm"]
ARM_INCOMPATIBLE_IMAGES = {"oracledb.dockerfile"}
BASE_IMAGE_PREFIX = "ARG BASE_IMAGE="
def extract_base_image(dockerfile: Path) -> str:
"""Extract base image from dockerfile"""
for line in dockerfile.read_text().splitlines():
if line.startswith(BASE_IMAGE_PREFIX):
full_image = line[len(BASE_IMAGE_PREFIX) :]
image_name = full_image[full_image.rfind("/") + 1 :]
return "" if ":" in image_name else image_name
raise RuntimeError(f"Base image not found in {dockerfile}")
def get_platform(runs_on: str) -> str:
"""Get platform architecture based on runner"""
return "x86_64" if runs_on == "ubuntu-24.04" else "aarch64"
def generate_matrix() -> dict[str, list[dict[str, str]]]:
"""Generate build matrix for GitHub Actions"""
dockerfiles = sorted(THIS_DIR.glob("*.dockerfile"))
configurations: list[dict[str, str]] = []
for dockerfile in dockerfiles:
dockerfile_name = dockerfile.name
for run in RUNS_ON:
# Skip ARM builds for incompatible images
if dockerfile_name in ARM_INCOMPATIBLE_IMAGES and run == "ubuntu-24.04-arm":
continue
configurations.append(
{
"dockerfile": dockerfile_name,
"runs-on": run,
"platform": get_platform(run),
"parent-image": extract_base_image(dockerfile),
}
)
return {"include": configurations}
if __name__ == "__main__":
print(f"matrix={json.dumps(generate_matrix())}")
================================================
FILE: docs/using/recipe_code/ijavascript.dockerfile
================================================
ARG BASE_IMAGE=quay.io/jupyter/base-notebook
FROM $BASE_IMAGE
USER root
RUN apt-get update --yes && \
apt-get install --yes --no-install-recommends \
make \
g++ && \
apt-get clean && rm -rf /var/lib/apt/lists/*
USER ${NB_UID}
# NodeJS <= 20 is required
# https://github.com/n-riesco/ijavascript/issues/184
RUN mamba install --yes nodejs=20.* && \
mamba clean --all -f -y && \
fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}"
# hadolint ignore=DL3016
RUN npm install -g ijavascript
# hadolint ignore=DL3059
RUN ijsinstall
================================================
FILE: docs/using/recipe_code/jupyterhub_version.dockerfile
================================================
ARG BASE_IMAGE=quay.io/jupyter/base-notebook
FROM $BASE_IMAGE
RUN mamba install --yes 'jupyterhub-singleuser==5.2.1' && \
mamba clean --all -f -y && \
fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}"
================================================
FILE: docs/using/recipe_code/mamba_install.dockerfile
================================================
ARG BASE_IMAGE=quay.io/jupyter/base-notebook
FROM $BASE_IMAGE
RUN mamba install --yes 'flake8' && \
mamba clean --all -f -y && \
fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}"
# Install from the requirements.txt file
COPY --chown=${NB_UID}:${NB_GID} requirements.txt /tmp/
RUN mamba install --yes --file /tmp/requirements.txt && \
mamba clean --all -f -y && \
fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}"
================================================
FILE: docs/using/recipe_code/manpage_install.dockerfile
================================================
ARG BASE_IMAGE=quay.io/jupyter/base-notebook
FROM $BASE_IMAGE
# Fix: https://github.com/hadolint/hadolint/wiki/DL4006
# Fix: https://github.com/koalaman/shellcheck/wiki/SC3014
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
USER root
# `/etc/dpkg/dpkg.cfg.d/excludes` contains several `path-exclude`s, including man pages
# Remove it, then install man, install docs
RUN rm /etc/dpkg/dpkg.cfg.d/excludes && \
apt-get update --yes && \
dpkg -l | grep ^ii | cut -d' ' -f3 | xargs apt-get install --yes --no-install-recommends --reinstall man && \
apt-get clean && rm -rf /var/lib/apt/lists/*
USER ${NB_UID}
================================================
FILE: docs/using/recipe_code/microsoft_odbc.dockerfile
================================================
ARG BASE_IMAGE=quay.io/jupyter/base-notebook
FROM $BASE_IMAGE
# Fix: https://github.com/hadolint/hadolint/wiki/DL4006
# Fix: https://github.com/koalaman/shellcheck/wiki/SC3014
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
USER root
ENV MSSQL_DRIVER="ODBC Driver 18 for SQL Server"
ENV PATH="/opt/mssql-tools18/bin:${PATH}"
RUN apt-get update --yes && \
apt-get install --yes --no-install-recommends curl gnupg2 lsb-release && \
curl -fsSL "https://packages.microsoft.com/keys/microsoft.asc" | gpg --dearmor -o /usr/share/keyrings/microsoft-prod.gpg && \
curl "https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/prod.list" > /etc/apt/sources.list.d/mssql-release.list && \
apt-get update --yes && \
ACCEPT_EULA=Y apt-get install --yes --no-install-recommends msodbcsql18 && \
# optional: for bcp and sqlcmd
ACCEPT_EULA=Y apt-get install --yes --no-install-recommends mssql-tools18 && \
# optional: for unixODBC development headers
apt-get install --yes --no-install-recommends unixodbc-dev && \
apt-get clean && rm -rf /var/lib/apt/lists/*
# Switch back to jovyan to avoid accidental container runs as root
USER ${NB_UID}
RUN mamba install --yes 'pyodbc' && \
mamba clean --all -f -y && \
fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}"
================================================
FILE: docs/using/recipe_code/oracledb.dockerfile
================================================
ARG BASE_IMAGE=quay.io/jupyter/base-notebook
FROM $BASE_IMAGE
USER root
# Install Java & Oracle SQL Instant Client
RUN apt-get update --yes && \
apt-get install --yes --no-install-recommends software-properties-common && \
add-apt-repository universe && \
apt-get update --yes && \
apt-get install --yes --no-install-recommends alien default-jre default-jdk openjdk-11-jdk libaio1t64 && \
apt-get clean && rm -rf /var/lib/apt/lists/*
# Oracle
ARG INSTANTCLIENT_MAJOR_VERSION=23
ARG INSTANTCLIENT_BIN_SUFFIX=${INSTANTCLIENT_MAJOR_VERSION}.6.0.24.10-1.el9.x86_64.rpm
ARG INSTANTCLIENT_URL=https://download.oracle.com/otn_software/linux/instantclient/2360000
# Then install Oracle SQL Instant client, SQL+Plus, tools, and JDBC.
# Note: You may need to change the URL to a newer version.
# See: https://www.oracle.com/database/technologies/instant-client/linux-x86-64-downloads.html
RUN mkdir "/opt/oracle"
WORKDIR "/opt/oracle"
# alien doesn't work well with sqlplus, so skipping it for now
RUN wget --progress=dot:giga "${INSTANTCLIENT_URL}/oracle-instantclient-basiclite-${INSTANTCLIENT_BIN_SUFFIX}" && \
alien --install --scripts "oracle-instantclient-basiclite-${INSTANTCLIENT_BIN_SUFFIX}" && \
wget --progress=dot:giga "${INSTANTCLIENT_URL}/oracle-instantclient-sqlplus-${INSTANTCLIENT_BIN_SUFFIX}" && \
# alien --install --scripts "oracle-instantclient-sqlplus-${INSTANTCLIENT_BIN_SUFFIX}" && \
wget --progress=dot:giga "${INSTANTCLIENT_URL}/oracle-instantclient-tools-${INSTANTCLIENT_BIN_SUFFIX}" && \
alien --install --scripts "oracle-instantclient-tools-${INSTANTCLIENT_BIN_SUFFIX}" && \
wget --progress=dot:giga "${INSTANTCLIENT_URL}/oracle-instantclient-jdbc-${INSTANTCLIENT_BIN_SUFFIX}" && \
alien --install --scripts "oracle-instantclient-jdbc-${INSTANTCLIENT_BIN_SUFFIX}" && \
chown -R "${NB_UID}":"${NB_GID}" "${HOME}/.rpmdb" && \
rm -f ./*.rpm
# And configure variables
RUN echo "ORACLE_HOME=/usr/lib/oracle/${INSTANTCLIENT_MAJOR_VERSION}/client64" >> "${HOME}/.bashrc" && \
echo "PATH=\"${ORACLE_HOME}/bin:${PATH}\"" >> "${HOME}/.bashrc" && \
echo "LD_LIBRARY_PATH=\"${ORACLE_HOME}/lib:${LD_LIBRARY_PATH}\"" >> "${HOME}/.bashrc" && \
echo "export ORACLE_HOME" >> "${HOME}/.bashrc" && \
echo "export PATH" >> "${HOME}/.bashrc" && \
echo "export LD_LIBRARY_PATH" >> "${HOME}/.bashrc"
# Add credentials for /redacted/ using Oracle DB.
WORKDIR /usr/lib/oracle/${INSTANTCLIENT_MAJOR_VERSION}/client64/lib/network/admin/
# Add a wildcard `[]` on the last letter of the filename to avoid throwing an error if the file does not exist.
# See: https://stackoverflow.com/questions/31528384/conditional-copy-add-in-dockerfile
COPY cwallet.ss[o] ./
COPY sqlnet.or[a] ./
COPY tnsnames.or[a] ./
# Switch back to jovyan to avoid accidental container runs as root
USER "${NB_UID}"
WORKDIR "${HOME}"
# Install `oracledb` Python library to use Oracle SQL Instant Client
RUN mamba install --yes 'oracledb' && \
mamba clean --all -f -y && \
fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}"
================================================
FILE: docs/using/recipe_code/pip_install.dockerfile
================================================
ARG BASE_IMAGE=quay.io/jupyter/base-notebook
FROM $BASE_IMAGE
# Install in the default python3 environment
RUN pip install --no-cache-dir 'flake8' && \
fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}"
# Install from the requirements.txt file
COPY --chown=${NB_UID}:${NB_GID} requirements.txt /tmp/
RUN pip install --no-cache-dir --requirement /tmp/requirements.txt && \
fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}"
================================================
FILE: docs/using/recipe_code/requirements.txt
================================================
autoflake
================================================
FILE: docs/using/recipe_code/rise_jupyterlab.dockerfile
================================================
ARG BASE_IMAGE=quay.io/jupyter/base-notebook
FROM $BASE_IMAGE
RUN mamba install --yes 'jupyterlab_rise' && \
mamba clean --all -f -y && \
fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}"
================================================
FILE: docs/using/recipe_code/spellcheck_notebook_v6.dockerfile
================================================
# Using Docker Hub here, because this image is old and not pushed to Quay.io
ARG BASE_IMAGE=docker.io/jupyter/base-notebook:notebook-6.5.4
FROM $BASE_IMAGE
RUN pip install --no-cache-dir 'jupyter_contrib_nbextensions' && \
jupyter contrib nbextension install --user && \
# can modify or enable additional extensions here
jupyter nbclassic-extension enable spellchecker/main --user && \
fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}"
================================================
FILE: docs/using/recipe_code/xgboost.dockerfile
================================================
ARG BASE_IMAGE=quay.io/jupyter/base-notebook
FROM $BASE_IMAGE
RUN mamba install --yes 'py-xgboost' && \
mamba clean --all -f -y && \
fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}"
================================================
FILE: docs/using/recipes.md
================================================
# Contributed Recipes
Users sometimes share interesting ways of using the Jupyter Docker Stacks.
We encourage users to [contribute these recipes](../contributing/recipes.md) to the documentation in case they prove helpful to other community members by submitting a pull request to `docs/using/recipes.md`.
The sections below capture this knowledge.
All the recipes here assume you would like to use an image built by this project and install some things on top of it.
If you would like to build a custom set of images, [take a look at the docs](custom-images.md).
## Using `sudo` within a container
Password authentication is disabled for the `NB_USER` (e.g., `jovyan`).
We made this choice to avoid distributing images with a weak default password that users ~might~ will forget to change before running a container on a publicly accessible host.
You can grant the within-container `NB_USER` passwordless `sudo` access by adding `--user root` and `-e GRANT_SUDO=yes` to your Docker command line or appropriate container orchestrator config.
For example:
```bash
docker run -it --rm \
--user root \
-e GRANT_SUDO=yes \
quay.io/jupyter/base-notebook
```
**You should only enable `sudo` if you trust the user and/or if the container is running on an isolated host.**
See [Docker security documentation](https://docs.docker.com/engine/security/userns-remap/) for more information about running containers as `root`.
## Using `mamba install` (recommended) or `pip install` in a Child Docker image
Create a new Dockerfile like the one shown below.
To use a requirements.txt file, first, create your `requirements.txt` file with the listing of packages desired.
```{literalinclude} recipe_code/mamba_install.dockerfile
:language: docker
```
`pip` usage is similar:
```{literalinclude} recipe_code/pip_install.dockerfile
:language: docker
```
Then build a new image.
```bash
docker build --rm --tag my-custom-image .
```
You can then run the image as follows:
```bash
docker run -it --rm \
-p 8888:8888 \
my-custom-image
```
## Add a custom conda environment and Jupyter kernel
The default version of `Python` that ships with the image may not be the version you want.
The instructions below permit adding a conda environment with a different `Python` version and making it accessible to Jupyter.
You may also use older images like `jupyter/base-notebook:python-3.10`.
We also maintain a [full build history](https://github.com/jupyter/docker-stacks/wiki).
```{literalinclude} recipe_code/custom_environment.dockerfile
:language: docker
```
## 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.
Create the Dockerfile as:
```{literalinclude} recipe_code/dask_jupyterlab.dockerfile
:language: docker
```
And build the image as:
```bash
docker build --rm --tag my-custom-image .
```
Once built, run using the command:
```bash
docker run -it --rm \
-p 8888:8888 \
-p 8787:8787 \
my-custom-image
```
## Let's Encrypt a Server
```{warning}
This recipe is not tested and might be broken.
```
See the README for basic automation here
<https://github.com/jupyter/docker-stacks/tree/main/examples/make-deploy>
which includes steps for requesting and renewing a Let's Encrypt certificate.
Ref: <https://github.com/jupyter/docker-stacks/issues/78>
## Slideshows with JupyterLab and RISE
[RISE](https://github.com/jupyterlab-contrib/rise): "Live" Reveal.js JupyterLab Slideshow Extension.
```{note}
We're providing the recipe to install the JupyterLab extension.
You can find the original Jupyter Notebook extension [here](https://github.com/damianavila/RISE)
```
```{literalinclude} recipe_code/rise_jupyterlab.dockerfile
:language: docker
```
## xgboost
```{literalinclude} recipe_code/xgboost.dockerfile
:language: docker
```
## Running behind an nginx proxy
```{warning}
This recipe is not tested and might be broken.
```
Sometimes it is helpful to run the Jupyter instance behind an nginx proxy, for example:
- you would prefer to access the notebook at a server URL with a path
(`https://example.com/jupyter`) rather than a port (`https://example.com:8888`)
- you may have many services in addition to Jupyter running on the same server
and want nginx to help improve server performance in managing the connections
Here is a [quick example of NGINX configuration](https://gist.github.com/cboettig/8643341bd3c93b62b5c2) to get started.
You'll need a server, a `.crt`, and a `.key` file for your server, and `docker` & `docker-compose` installed.
Then download the files at that gist and run `docker-compose up` to test it out.
Customize the `nginx.conf` file to set the desired paths and add other services.
## Host volume mounts and notebook errors
If you are mounting a host directory as `/home/jovyan/work` in your container,
and you receive permission errors or connection errors when you create a notebook,
be sure that the `jovyan` user (`UID=1000` by default) has read/write access to the directory on the host.
Alternatively, specify the UID of the `jovyan` user on container startup using the `-e NB_UID` option
described in the [Common Features, Docker Options section](common.md#docker-options)
Ref: <https://github.com/jupyter/docker-stacks/issues/199>
## Manpage installation
Most images, including our Ubuntu base image, ship without manpages installed to save space.
You can use the following Dockerfile to inherit from one of our images to enable manpages:
```{literalinclude} recipe_code/manpage_install.dockerfile
:language: docker
```
Adding the documentation on top of the existing image wastes a lot of space
and requires reinstalling every system package,
which can take additional time and bandwidth.
Enabling manpages in the base Ubuntu layer prevents this image bloat.
To achieve this, use the previous `Dockerfile`'s commands with the original `ubuntu` image as your base image:
```dockerfile
FROM ubuntu:24.04
```
Be sure to check the current base image in `jupyter/docker-stacks-foundation` before building.
## JupyterHub
We also have contributed recipes for using JupyterHub.
### Use JupyterHub's DockerSpawner
You can find [an example of using DockerSpawner](https://github.com/jupyterhub/jupyterhub-deploy-docker/tree/main/basic-example).
### Containers with a specific version of JupyterHub
The version of `jupyterhub` in your image should match the
version in JupyterHub itself.
To use a specific version of JupyterHub, do the following:
```{literalinclude} recipe_code/jupyterhub_version.dockerfile
:language: docker
```
## Spark
A few suggestions have been made regarding using Docker Stacks with Spark.
### Using PySpark with AWS S3
```{warning}
This recipe is not tested and might be broken.
```
Using Spark session for Hadoop 2.7.3
```python
import os
# To figure out what version of Hadoop, run:
# ls /usr/local/spark/jars/hadoop*
os.environ["PYSPARK_SUBMIT_ARGS"] = (
'--packages "org.apache.hadoop:hadoop-aws:2.7.3" pyspark-shell'
)
import pyspark
myAccessKey = input()
mySecretKey = input()
spark = (
pyspark.sql.SparkSession.builder.master("local[*]")
.config("spark.hadoop.fs.s3a.access.key", myAccessKey)
.config("spark.hadoop.fs.s3a.secret.key", mySecretKey)
.getOrCreate()
)
df = spark.read.parquet("s3://myBucket/myKey")
```
Using Spark context for Hadoop 2.6.0
```python
import os
os.environ["PYSPARK_SUBMIT_ARGS"] = (
"--packages com.amazonaws:aws-java-sdk:1.10.34,org.apache.hadoop:hadoop-aws:2.6.0 pyspark-shell"
)
import pyspark
sc = pyspark.SparkContext("local[*]")
from pyspark.sql import SQLContext
sqlContext = SQLContext(sc)
hadoopConf = sc._jsc.hadoopConfiguration()
myAccessKey = input()
mySecretKey = input()
hadoopConf.set("fs.s3.impl", "org.apache.hadoop.fs.s3native.NativeS3FileSystem")
hadoopConf.set("fs.s3.awsAccessKeyId", myAccessKey)
hadoopConf.set("fs.s3.awsSecretAccessKey", mySecretKey)
df = sqlContext.read.parquet("s3://myBucket/myKey")
```
Ref: <https://github.com/jupyter/docker-stacks/issues/127>
### Using Local Spark JARs
```{warning}
This recipe is not tested and might be broken.
```
```python
import os
os.environ["PYSPARK_SUBMIT_ARGS"] = (
"--jars /home/jovyan/spark-streaming-kafka-assembly_2.10-1.6.1.jar pyspark-shell"
)
import pyspark
from pyspark.streaming.kafka import KafkaUtils
from pyspark.streaming import StreamingContext
sc = pyspark.SparkContext()
ssc = StreamingContext(sc, 1)
broker = "<my_broker_ip>"
directKafkaStream = KafkaUtils.createDirectStream(
ssc, ["test1"], {"metadata.broker.list": broker}
)
directKafkaStream.pprint()
ssc.start()
```
Ref: <https://github.com/jupyter/docker-stacks/issues/154>
### Using spark-packages.org
```{warning}
This recipe is not tested and might be broken.
```
If you'd like to use packages from [spark-packages.org](https://spark-packages.org/), see
[https://gist.github.com/parente/c95fdaba5a9a066efaab](https://gist.github.com/parente/c95fdaba5a9a066efaab)
for an example of how to specify the package identifier in the environment before creating a
SparkContext.
Ref: <https://github.com/jupyter/docker-stacks/issues/43>
### Use jupyter/all-spark-notebooks with an existing Spark/YARN cluster
```{warning}
This recipe is not tested and might be broken.
```
```dockerfile
FROM quay.io/jupyter/all-spark-notebook
# Set env vars for pydoop
ENV HADOOP_HOME=/usr/local/hadoop-2.7.3
ENV JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
ENV HADOOP_CONF_HOME=/usr/local/hadoop-2.7.3/etc/hadoop
ENV HADOOP_CONF_DIR=/usr/local/hadoop-2.7.3/etc/hadoop
USER root
# Add proper open-jdk-8 not the jre only, needed for pydoop
RUN echo 'deb https://cdn-fastly.deb.debian.org/debian jessie-backports main' > /etc/apt/sources.list.d/jessie-backports.list && \
apt-get update --yes && \
apt-get install --yes --no-install-recommends -t jessie-backports openjdk-8-jdk && \
rm /etc/apt/sources.list.d/jessie-backports.list && \
apt-get clean && rm -rf /var/lib/apt/lists/* && \
# Add Hadoop binaries
wget --progress=dot:giga https://mirrors.ukfast.co.uk/sites/ftp.apache.org/hadoop/common/hadoop-2.7.3/hadoop-2.7.3.tar.gz && \
tar -xvf hadoop-2.7.3.tar.gz -C /usr/local && \
chown -R "${NB_USER}:users" /usr/local/hadoop-2.7.3 && \
rm -f hadoop-2.7.3.tar.gz && \
# Install os dependencies required for pydoop, pyhive
apt-get update --yes && \
apt-get install --yes --no-install-recommends build-essential python-dev libsasl2-dev && \
apt-get clean && rm -rf /var/lib/apt/lists/* && \
# Remove the example hadoop configs and replace
# with those for our cluster.
# Alternatively, this could be mounted as a volume
rm -f /usr/local/hadoop-2.7.3/etc/hadoop/*
# Download this from ambari/cloudera manager and copy it here
COPY example-hadoop-conf/ /usr/local/hadoop-2.7.3/etc/hadoop/
# Spark-Submit doesn't work unless I set the following
RUN echo "spark.driver.extraJavaOptions -Dhdp.version=2.5.3.0-37" >> /usr/local/spark/conf/spark-defaults.conf && \
echo "spark.yarn.am.extraJavaOptions -Dhdp.version=2.5.3.0-37" >> /usr/local/spark/conf/spark-defaults.conf && \
echo "spark.master=yarn" >> /usr/local/spark/conf/spark-defaults.conf && \
echo "spark.hadoop.yarn.timeline-service.enabled=false" >> /usr/local/spark/conf/spark-defaults.conf && \
chown -R "${NB_USER}:users" /usr/local/spark/conf/spark-defaults.conf && \
# Create an alternative HADOOP_CONF_HOME so we can mount as a volume and repoint
# using ENV var if needed
mkdir -p /etc/hadoop/conf/ && \
chown "${NB_USER}":users /etc/hadoop/conf/
USER ${NB_UID}
# Install useful jupyter extensions and python libraries like :
# - Dashboards
# - PyDoop
# - PyHive
RUN pip install --no-cache-dir 'jupyter_dashboards' 'faker' && \
jupyter dashboards quick-setup --sys-prefix && \
pip2 install --no-cache-dir 'pyhive' 'pydoop' 'thrift' 'sasl' 'thrift_sasl' 'faker' && \
fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}"
USER root
# Ensure we overwrite the kernel config so that toree connects to cluster
RUN jupyter toree install --sys-prefix --spark_opts="\
--master yarn \
--deploy-mode client \
--driver-memory 512m \
--executor-memory 512m \
--executor-cores 1 \
--driver-java-options \
-Dhdp.version=2.5.3.0-37 \
--conf spark.hadoop.yarn.timeline-service.enabled=false \
"
USER ${NB_UID}
```
Credit: [britishbadger](https://github.com/britishbadger) from [docker-stacks/issues/369](https://github.com/jupyter/docker-stacks/issues/369)
## Run Server inside an already secured environment (i.e., with no token)
The default security is very good.
There are use cases, encouraged by containers, where the jupyter container and the system it runs within lie inside the security boundary.
It is convenient to launch the server without a password or token in these use cases.
In this case, you should use the `start-notebook.py` script to launch the server with no token:
For JupyterLab:
```bash
docker run -it --rm \
quay.io/jupyter/base-notebook \
start-notebook.py --IdentityProvider.token=''
```
For Jupyter Notebook:
```bash
docker run -it --rm \
-e DOCKER_STACKS_JUPYTER_CMD=notebook \
quay.io/jupyter/base-notebook \
start-notebook.py --IdentityProvider.token=''
```
## Enable nbclassic-extension spellchecker for markdown (or any other nbclassic-extension)
```{note}
This recipe only works for NBClassic with Jupyter Notebook < 7.
It is recommended to use [jupyterlab-spellchecker](https://github.com/jupyterlab-contrib/spellchecker) in modern environments.
```
```{literalinclude} recipe_code/spellcheck_notebook_v6.dockerfile
:language: docker
```
## Enable Delta Lake in Spark notebooks
```{warning}
This recipe is not tested and might be broken.
```
Please note that the [Delta Lake](https://delta.io/) packages are only available for Spark version > `3.0`.
By adding the properties to `spark-defaults.conf`, the user no longer needs to enable Delta support in each notebook.
```dockerfile
FROM quay.io/jupyter/pyspark-notebook
RUN mamba install --yes 'delta-spark' && \
mamba clean --all -f -y && \
fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}"
USER root
RUN echo 'spark.sql.extensions io.delta.sql.DeltaSparkSessionExtension' >> "${SPARK_HOME}/conf/spark-defaults.conf" && \
echo 'spark.sql.catalog.spark_catalog org.apache.spark.sql.delta.catalog.DeltaCatalog' >> "${SPARK_HOME}/conf/spark-defaults.conf"
USER ${NB_UID}
# Trigger download of delta lake files
RUN echo "from pyspark.sql import SparkSession" > /tmp/init-delta.py && \
echo "from delta import *" >> /tmp/init-delta.py && \
echo "spark = configure_spark_with_delta_pip(SparkSession.builder).getOrCreate()" >> /tmp/init-delta.py && \
python /tmp/init-delta.py && \
rm /tmp/init-delta.py
```
## Add Custom Fonts in Scipy notebook
```{warning}
This recipe is not tested and might be broken.
```
The example below is a Dockerfile to load Source Han Sans with normal weight, usually used for the web.
```dockerfile
FROM quay.io/jupyter/scipy-notebook
RUN PYV=$(ls "${CONDA_DIR}/lib" | grep ^python) && \
MPL_DATA="${CONDA_DIR}/lib/${PYV}/site-packages/matplotlib/mpl-data" && \
wget --progress=dot:giga -P "${MPL_DATA}/fonts/ttf/" https://mirrors.cloud.tencent.com/adobe-fonts/source-han-sans/SubsetOTF/CN/SourceHanSansCN-Normal.otf && \
sed -i 's/#font.family/font.family/g' "${MPL_DATA}/matplotlibrc" && \
sed -i 's/#font.sans-serif:/font.sans-serif: Source Han Sans CN,/g' "${MPL_DATA}/matplotlibrc" && \
sed -i 's/#axes.unicode_minus: True/axes.unicode_minus: False/g' "${MPL_DATA}/matplotlibrc" && \
rm -rf "/home/${NB_USER}/.cache/matplotlib" && \
python -c 'import matplotlib.font_manager;print("font loaded: ",("Source Han Sans CN" in [f.name for f in matplotlib.font_manager.fontManager.ttflist]))'
```
## Enable clipboard in pandas on Linux systems
```{warning}
This recipe is not tested and might be broken.
```
```{admonition} Additional notes
This solution works on Linux host systems.
It is not required on Windows and won't work on macOS.
```
To enable the `pandas.read_clipboard()` functionality, you need to have `xclip` installed
(installed in `minimal-notebook` and all the inherited images)
and add these options when running `docker`: `-e DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix`, i.e.:
```bash
docker run -it --rm \
-e DISPLAY \
-v /tmp/.X11-unix:/tmp/.X11-unix \
quay.io/jupyter/minimal-notebook
```
## Install ijavascript kernel in your image
The example below is a Dockerfile to install the [IJavascript kernel](https://github.com/n-riesco/ijavascript).
```{literalinclude} recipe_code/ijavascript.dockerfile
:language: docker
```
## Add Microsoft SQL Server ODBC driver
The following recipe demonstrates how to add functionality to read from and write to an instance of Microsoft SQL server in your notebook.
```{literalinclude} recipe_code/microsoft_odbc.dockerfile
:language: docker
```
You can now use `pyodbc` and `sqlalchemy` to interact with the database.
Pre-built images are hosted in the [Realiserad/jupyter-docker-mssql](https://github.com/Realiserad/jupyter-docker-mssql) repository.
## Add Oracle SQL Instant client, SQL\*Plus, and other tools (Version 21.x)
```{note}
This recipe only works for x86_64 architecture.
```
The following recipe demonstrates how to add functionality to connect to an Oracle Database using [Oracle Instant Client](https://www.oracle.com/database/technologies/instant-client.html)
in your notebook.
This recipe installs version `21.11.0.0.0`.
Nonetheless, go to the [Oracle Instant Client Download page](https://www.oracle.com/es/database/technologies/instant-client/linux-x86-64-downloads.html) for the complete list of versions available.
You may need to perform different steps for older versions;
they may be explained in the "Installation instructions" section of the Downloads page.
```{literalinclude} recipe_code/oracledb.dockerfile
:language: docker
```
## Running Jupyter Docker Stacks with Singularity
You can also start Jupyter Docker Stacks containers using **Singularity** instead of Docker. For example:
```bash
singularity run --bind "${PWD}:/home/${USER}/work" --containall docker://quay.io/jupyter/datascience-notebook:2025-12-31
```
- `--bind "${PWD}:/home/${USER}/work"` mounts your current working directory into the container at `/home/$USER/work`.
When running the image with Singularity, the container uses your host username inside the container.
Therefore, the bind target is `/home/${USER}/work` instead of the usual `/home/jovyan/work`.
- `--containall` starts the container in a fully isolated environment, ignoring most of the host’s filesystem and environment except for explicitly bound paths.
By default, Singularity would bind your home directory automatically.
If you have Python packages installed there, this may cause conflicts with packages inside the container.
Using `--containall` avoids such interference.
================================================
FILE: docs/using/running.md
================================================
# Running a Container
Using one of the Jupyter Docker Stacks requires two choices:
1. Which Docker image you wish to use
2. How you wish to start Docker containers from that image
This section provides details about the second.
## Using the Docker CLI
You can launch a local Docker container from the Jupyter Docker Stacks using the [Docker command-line interface](https://docs.docker.com/reference/cli/docker/).
There are numerous ways to configure containers using CLI.
The following are some common patterns.
### Example 1
This command pulls the `jupyter/scipy-notebook` image tagged `2025-12-31` from Quay.io if it is not already present on the local host.
It then starts a container running a Jupyter Server with the JupyterLab frontend and exposes the server on host port 8888.
The server logs appear in the terminal and include a URL to the server.
```bash
docker run -it -p 8888:8888 quay.io/jupyter/scipy-notebook:2025-12-31
# Entered start.sh with args: jupyter lab
# ...
# To access the server, open this file in a browser:
# file:///home/jovyan/.local/share/jupyter/runtime/jpserver-7-open.html
# Or copy and paste one of these URLs:
# http://eca4aa01751c:8888/lab?token=d4ac9278f5f5388e88097a3a8ebbe9401be206cfa0b83099
# http://127.0.0.1:8888/lab?token=d4ac9278f5f5388e88097a3a8ebbe9401be206cfa0b83099
```
Pressing `Ctrl-C` twice shuts down the Server but leaves the container intact on disk for later restart or permanent deletion using commands like the following:
```bash
# list containers
docker ps --all
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# eca4aa01751c quay.io/jupyter/scipy-notebook:2025-12-31 "tini -g -- start-no…" About a minute ago Exited (0) 5 seconds ago silly_panini
# start the stopped container
docker start --attach -i eca4aa01751c
# Entered start.sh with args: jupyter lab
# ...
# remove the stopped container
docker rm eca4aa01751c
# eca4aa01751c
```
### Example 2
This command pulls the `jupyter/r-notebook` image tagged `2025-12-31` from Quay.io if it is not already present on the local host.
It then starts a container running a Jupyter Server and exposes the server on host port 10000.
The server logs appear in the terminal and include a URL to the Server but with the internal container port (8888) instead of the correct host port (10000).
```bash
docker run -it --rm -p 10000:8888 -v "${PWD}":/home/jovyan/work quay.io/jupyter/r-notebook:2025-12-31
```
Pressing `Ctrl-C` twice shuts down the Server and immediately destroys the Docker container.
New files and changes in `~/work` in the container will be preserved.
Any other changes made in the container will be lost.
```{note}
By default, [jupyter's root_dir](https://jupyter-server.readthedocs.io/en/latest/other/full-config.html) is `/home/jovyan`.
So, new notebooks will be saved there, unless you change the directory in the file browser.
To change the default directory, you will need to specify `ServerApp.root_dir` by adding this line to the previous command: `start-notebook.py --ServerApp.root_dir=/home/jovyan/work`.
```
### Example 3
This command pulls the `jupyter/all-spark-notebook` image currently tagged `latest` from Quay.io if an image tagged `latest` is not already present on the local host.
It then starts a container named `notebook` running a JupyterLab server and exposes the server on a randomly selected port.
```bash
docker run --detach -P --name notebook quay.io/jupyter/all-spark-notebook
```
where:
- `--detach`: will run the container in detached mode
You can also use the following docker commands to see the port and Jupyter Server token:
```bash
# get the random host port assigned to the container port 8888
docker port notebook 8888
# 0.0.0.0:49153
# :::49153
# get the notebook token from the logs
docker logs --tail 3 notebook
# Or copy and paste one of these URLs:
# http://878f1a9b4dfa:8888/lab?token=d336fa63c03f064ff15ce7b269cab95b2095786cf9ab2ba3
# or http://127.0.0.1:8888/lab?token=d336fa63c03f064ff15ce7b269cab95b2095786cf9ab2ba3
```
Together, the URL to visit on the host machine to access the server, in this case, is <http://127.0.0.1:49153/lab?token=d336fa63c03f064ff15ce7b269cab95b2095786cf9ab2ba3>.
The container runs in the background until stopped and/or removed by additional Docker commands:
```bash
# stop the container
docker stop notebook
# notebook
# remove the container permanently
docker rm notebook
# notebook
```
## Using the Podman CLI
An alternative to using the Docker CLI is to use the Podman CLI.
Podman is mostly compatible with Docker.
### Podman example
If we use Podman instead of Docker in the situation given in _Example 2_, it will look like this:
The example makes use of rootless Podman; in other words, the Podman command is run from a regular user account.
In a Bash shell, set the shell variables _uid_ and _gid_ to the UID and GID of the user _jovyan_ in the container.
```bash
uid=1000
gid=100
```
Set the shell variables _subuidSize_ and _subgidSize_ to the number of subordinate UIDs and GIDs, respectively.
```bash
subuidSize=$(( $(podman info --format "{{ range .Host.IDMappings.UIDMap }}+{{.Size }}{{end }}" ) - 1 ))
subgidSize=$(( $(podman info --format "{{ range .Host.IDMappings.GIDMap }}+{{.Size }}{{end }}" ) - 1 ))
```
This command pulls the `quay.io/jupyter/r-notebook` image tagged `2025-12-31` from Quay.io if it is not already present on the local host.
It then starts a container running a Jupyter Server with the JupyterLab frontend and exposes the server on host port 10000.
The server logs appear in the terminal and include a URL to the server but with the internal container port (8888) instead of the correct host port (10000).
```bash
podman run -it --rm -p 10000:8888 \
-v "${PWD}":/home/jovyan/work --user $uid:$gid \
--uidmap $uid:0:1 --uidmap 0:1:$uid --uidmap $(($uid+1)):$(($uid+1)):$(($subuidSize-$uid)) \
--gidmap $gid:0:1 --gidmap 0:1:$gid --gidmap $(($gid+1)):$(($gid+1)):$(($subgidSize-$gid)) \
quay.io/jupyter/r-notebook:2025-12-31
```
```{warning}
The `podman run` options `--uidmap` and `--gidmap` can be used to map the container user _jovyan_ to the regular user on the host when running rootless Podman.
The same Podman command should not be run with sudo (i.e. running rootful Podman)
because then the mapping would map the container user _jovyan_ to the root user on the host.
It's a good security practice to run programs with as few privileges as possible.
```
```{note}
The `podman run` command in the example above maps all subuids and subgids of the user into the container.
That works fine but is actually more than needed.
The `podman run` option `--userns=auto` will, for instance, not be possible to use as long as there are no unused subuids and subgids available.
The example could be improved by investigating more in detail which UIDs and GIDs need to be available in the container and then only map them.
```
Pressing `Ctrl-C` twice shuts down the Server and immediately destroys the Docker container.
New files and changes in `~/work` in the container will be preserved.
Any other changes made in the container will be lost.
## Using Binder
A [Binder](https://mybinder.org/) is a service that allows you to create a
gitextract_w6y_9n58/
├── .devcontainer/
│ ├── Dockerfile
│ └── devcontainer.json
├── .flake8
├── .gitattributes
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── blank.yml
│ │ ├── bug_report.yml
│ │ ├── config.yml
│ │ └── feature_request.yml
│ ├── actions/
│ │ ├── apply-single-tags/
│ │ │ └── action.yml
│ │ ├── create-dev-env/
│ │ │ └── action.yml
│ │ ├── free-disk-space/
│ │ │ └── action.yml
│ │ └── load-image/
│ │ └── action.yml
│ ├── dependabot.yml
│ ├── pull_request_template.md
│ └── workflows/
│ ├── contributed-recipes.yml
│ ├── docker-build-test-upload.yml
│ ├── docker-tag-merge.yml
│ ├── docker-tag-push-merge.yml
│ ├── docker-tag-push.yml
│ ├── docker-wiki-update.yml
│ ├── docker.yml
│ ├── pre-commit.yml
│ ├── registry-move.yml
│ ├── registry-overviews.yml
│ └── sphinx.yml
├── .gitignore
├── .hadolint.yaml
├── .markdownlint.yaml
├── .pre-commit-config.yaml
├── .readthedocs.yaml
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE.md
├── Makefile
├── README.md
├── SECURITY.md
├── binder/
│ ├── Dockerfile
│ └── README.ipynb
├── docs/
│ ├── conf.py
│ ├── contributing/
│ │ ├── features.md
│ │ ├── issues.md
│ │ ├── lint.md
│ │ ├── packages.md
│ │ ├── recipes.md
│ │ ├── stacks.md
│ │ └── tests.md
│ ├── index.rst
│ ├── maintaining/
│ │ ├── new-images-and-packages-policy.md
│ │ ├── tagging.md
│ │ ├── tagging_examples/
│ │ │ ├── docker_runner.py
│ │ │ └── git_helper.py
│ │ └── tasks.md
│ ├── requirements.txt
│ └── using/
│ ├── changelog.md
│ ├── common.md
│ ├── custom-images.md
│ ├── faq.md
│ ├── recipe_code/
│ │ ├── custom_environment.dockerfile
│ │ ├── dask_jupyterlab.dockerfile
│ │ ├── docker-bake.custom-python.hcl
│ │ ├── generate_matrix.py
│ │ ├── ijavascript.dockerfile
│ │ ├── jupyterhub_version.dockerfile
│ │ ├── mamba_install.dockerfile
│ │ ├── manpage_install.dockerfile
│ │ ├── microsoft_odbc.dockerfile
│ │ ├── oracledb.dockerfile
│ │ ├── pip_install.dockerfile
│ │ ├── requirements.txt
│ │ ├── rise_jupyterlab.dockerfile
│ │ ├── spellcheck_notebook_v6.dockerfile
│ │ └── xgboost.dockerfile
│ ├── recipes.md
│ ├── running.md
│ ├── selecting.md
│ ├── specifics.md
│ └── troubleshooting.md
├── examples/
│ ├── README.md
│ ├── docker-compose/
│ │ ├── README.md
│ │ ├── bin/
│ │ │ ├── letsencrypt.sh
│ │ │ ├── sl-dns.sh
│ │ │ ├── softlayer.sh
│ │ │ └── vbox.sh
│ │ └── notebook/
│ │ ├── Dockerfile
│ │ ├── build.sh
│ │ ├── down.sh
│ │ ├── env.sh
│ │ ├── letsencrypt-notebook.yml
│ │ ├── notebook.yml
│ │ ├── secure-notebook.yml
│ │ └── up.sh
│ ├── make-deploy/
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── letsencrypt.makefile
│ │ ├── self-signed.makefile
│ │ ├── softlayer.makefile
│ │ └── virtualbox.makefile
│ ├── openshift/
│ │ ├── README.md
│ │ └── templates.json
│ └── source-to-image/
│ ├── README.md
│ ├── assemble
│ ├── run
│ ├── save-artifacts
│ └── templates.json
├── images/
│ ├── all-spark-notebook/
│ │ ├── .dockerignore
│ │ ├── Dockerfile
│ │ └── README.md
│ ├── base-notebook/
│ │ ├── .dockerignore
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── docker_healthcheck.py
│ │ ├── jupyter_server_config.py
│ │ ├── start-notebook.py
│ │ ├── start-notebook.sh
│ │ ├── start-singleuser.py
│ │ └── start-singleuser.sh
│ ├── datascience-notebook/
│ │ ├── .dockerignore
│ │ ├── Dockerfile
│ │ └── README.md
│ ├── docker-stacks-foundation/
│ │ ├── .dockerignore
│ │ ├── 10activate-conda-env.sh
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── fix-permissions
│ │ ├── initial-condarc
│ │ ├── run-hooks.sh
│ │ └── start.sh
│ ├── julia-notebook/
│ │ ├── .dockerignore
│ │ ├── Dockerfile
│ │ └── README.md
│ ├── minimal-notebook/
│ │ ├── .dockerignore
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── Rprofile.site
│ │ └── setup-scripts/
│ │ ├── activate_notebook_custom_env.py
│ │ ├── setup-julia-packages.bash
│ │ └── setup_julia.py
│ ├── pyspark-notebook/
│ │ ├── .dockerignore
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── ipython_kernel_config.py
│ │ └── setup_spark.py
│ ├── pytorch-notebook/
│ │ ├── .dockerignore
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── cuda12/
│ │ │ └── Dockerfile
│ │ └── cuda13/
│ │ └── Dockerfile
│ ├── r-notebook/
│ │ ├── .dockerignore
│ │ ├── Dockerfile
│ │ └── README.md
│ ├── scipy-notebook/
│ │ ├── .dockerignore
│ │ ├── Dockerfile
│ │ └── README.md
│ └── tensorflow-notebook/
│ ├── .dockerignore
│ ├── Dockerfile
│ ├── README.md
│ └── cuda/
│ ├── 20tensorboard-proxy-env.sh
│ ├── Dockerfile
│ └── nvidia-lib-dirs.sh
├── mypy.ini
├── requirements-dev.txt
├── tagging/
│ ├── README.md
│ ├── __init__.py
│ ├── apps/
│ │ ├── __init__.py
│ │ ├── apply_tags.py
│ │ ├── common_cli_arguments.py
│ │ ├── config.py
│ │ ├── merge_tags.py
│ │ ├── write_manifest.py
│ │ └── write_tags_file.py
│ ├── hierarchy/
│ │ ├── __init__.py
│ │ ├── get_manifests.py
│ │ ├── get_taggers.py
│ │ └── images_hierarchy.py
│ ├── manifests/
│ │ ├── __init__.py
│ │ ├── apt_packages.py
│ │ ├── build_info.py
│ │ ├── conda_environment.py
│ │ ├── julia_packages.py
│ │ ├── manifest_interface.py
│ │ ├── r_packages.py
│ │ └── spark_info.py
│ ├── taggers/
│ │ ├── __init__.py
│ │ ├── date.py
│ │ ├── sha.py
│ │ ├── tagger_interface.py
│ │ ├── ubuntu_version.py
│ │ └── versions.py
│ └── utils/
│ ├── __init__.py
│ ├── docker_runner.py
│ ├── get_platform.py
│ ├── get_prefix.py
│ ├── git_helper.py
│ └── quoted_output.py
├── tests/
│ ├── README.md
│ ├── __init__.py
│ ├── by_image/
│ │ ├── all-spark-notebook/
│ │ │ ├── data/
│ │ │ │ ├── local_sparkR.ipynb
│ │ │ │ └── local_sparklyr.ipynb
│ │ │ └── test_spark_r_nbconvert.py
│ │ ├── base-notebook/
│ │ │ ├── data/
│ │ │ │ └── check_listening.py
│ │ │ ├── test_container_options.py
│ │ │ ├── test_healthcheck.py
│ │ │ ├── test_ips.py
│ │ │ ├── test_notebook.py
│ │ │ ├── test_pandoc.py
│ │ │ └── test_start_container.py
│ │ ├── datascience-notebook/
│ │ │ ├── test_julia_datascience.py
│ │ │ ├── test_mimetypes.py
│ │ │ └── test_pluto_datascience.py
│ │ ├── docker-stacks-foundation/
│ │ │ ├── data/
│ │ │ │ └── run-hooks/
│ │ │ │ ├── change/
│ │ │ │ │ ├── a.sh
│ │ │ │ │ ├── b.sh
│ │ │ │ │ └── c.sh
│ │ │ │ ├── executables/
│ │ │ │ │ ├── executable.py
│ │ │ │ │ ├── non_executable.py
│ │ │ │ │ └── run-me.sh
│ │ │ │ ├── failures/
│ │ │ │ │ ├── a.sh
│ │ │ │ │ ├── b.py
│ │ │ │ │ ├── c.sh
│ │ │ │ │ └── d.sh
│ │ │ │ ├── sh-files/
│ │ │ │ │ ├── executable.sh
│ │ │ │ │ └── non-executable.sh
│ │ │ │ └── unset/
│ │ │ │ ├── a.sh
│ │ │ │ ├── b.sh
│ │ │ │ └── c.sh
│ │ │ ├── test_outdated.py
│ │ │ ├── test_package_managers.py
│ │ │ ├── test_packages.py
│ │ │ ├── test_python_version.py
│ │ │ ├── test_run_hooks.py
│ │ │ ├── test_units.py
│ │ │ └── test_user_options.py
│ │ ├── julia-notebook/
│ │ │ ├── test_julia.py
│ │ │ └── test_pluto.py
│ │ ├── minimal-notebook/
│ │ │ ├── data/
│ │ │ │ ├── notebook_math.ipynb
│ │ │ │ └── notebook_svg.ipynb
│ │ │ └── test_nbconvert.py
│ │ ├── pyspark-notebook/
│ │ │ ├── data/
│ │ │ │ ├── issue_1168.ipynb
│ │ │ │ └── local_pyspark.ipynb
│ │ │ ├── test_spark.py
│ │ │ ├── test_spark_nbconvert.py
│ │ │ └── units/
│ │ │ ├── unit_pandas_version.py
│ │ │ └── unit_spark.py
│ │ ├── pytorch-notebook/
│ │ │ └── units/
│ │ │ └── unit_pytorch.py
│ │ ├── r-notebook/
│ │ │ └── test_R_mimetypes.py
│ │ ├── scipy-notebook/
│ │ │ ├── data/
│ │ │ │ ├── cython/
│ │ │ │ │ ├── helloworld.pyx
│ │ │ │ │ └── setup.py
│ │ │ │ └── matplotlib/
│ │ │ │ ├── matplotlib_1.py
│ │ │ │ └── matplotlib_fonts_1.py
│ │ │ ├── test_cython.py
│ │ │ ├── test_extensions.py
│ │ │ ├── test_matplotlib.py
│ │ │ └── units/
│ │ │ └── unit_pandas.py
│ │ └── tensorflow-notebook/
│ │ └── units/
│ │ └── unit_tensorflow.py
│ ├── conftest.py
│ ├── hierarchy/
│ │ ├── __init__.py
│ │ ├── get_test_dirs.py
│ │ └── images_hierarchy.py
│ ├── pytest.ini
│ ├── run_tests.py
│ ├── shared_checks/
│ │ ├── R_mimetype_check.py
│ │ ├── __init__.py
│ │ ├── nbconvert_check.py
│ │ └── pluto_check.py
│ └── utils/
│ ├── __init__.py
│ ├── conda_package_helper.py
│ └── tracked_container.py
└── wiki/
├── Home.md
├── __init__.py
├── config.py
├── manifest_time.py
└── update_wiki.py
SYMBOL INDEX (196 symbols across 66 files)
FILE: docs/using/recipe_code/generate_matrix.py
function extract_base_image (line 14) | def extract_base_image(dockerfile: Path) -> str:
function get_platform (line 24) | def get_platform(runs_on: str) -> str:
function generate_matrix (line 29) | def generate_matrix() -> dict[str, list[dict[str, str]]]:
FILE: images/minimal-notebook/setup-scripts/setup_julia.py
function unify_aarch64 (line 21) | def unify_aarch64(platform: str) -> str:
function get_latest_julia_url (line 28) | def get_latest_julia_url() -> tuple[str, str]:
function download_julia (line 49) | def download_julia(julia_url: str) -> None:
function configure_julia (line 63) | def configure_julia(julia_version: str) -> None:
FILE: images/pyspark-notebook/setup_spark.py
function get_all_refs (line 22) | def get_all_refs(url: str) -> list[str]:
function get_latest_spark_version (line 31) | def get_latest_spark_version() -> str:
function download_spark (line 57) | def download_spark(
function configure_spark (line 98) | def configure_spark(spark_dir_name: str, spark_home: Path) -> None:
FILE: tagging/apps/apply_tags.py
function apply_tags (line 17) | def apply_tags(config: Config) -> None:
FILE: tagging/apps/common_cli_arguments.py
function common_arguments_parser (line 10) | def common_arguments_parser(
FILE: tagging/apps/config.py
class Config (line 8) | class Config:
method full_image (line 21) | def full_image(self) -> str:
FILE: tagging/apps/merge_tags.py
function read_local_tags_from_files (line 25) | def read_local_tags_from_files(config: Config) -> set[str]:
function inspect_manifest (line 50) | def inspect_manifest(tag: str) -> None:
function find_platform_tags (line 56) | def find_platform_tags(merged_tag: str) -> list[str]:
function merge_tags (line 72) | def merge_tags(merged_tag: str, push_to_registry: bool) -> None:
FILE: tagging/apps/write_manifest.py
function get_build_history_line (line 25) | def get_build_history_line(config: Config, container: Container, filenam...
function write_build_history_line (line 50) | def write_build_history_line(
function get_manifest (line 63) | def get_manifest(config: Config, container: Container, commit_hash_tag: ...
function write_manifest (line 89) | def write_manifest(
function write_all (line 102) | def write_all(config: Config) -> None:
FILE: tagging/apps/write_tags_file.py
function get_tags (line 15) | def get_tags(config: Config) -> list[str]:
function write_tags_file (line 34) | def write_tags_file(config: Config) -> None:
FILE: tagging/hierarchy/get_manifests.py
function get_manifests (line 7) | def get_manifests(image: str | None) -> list[ManifestInterface]:
FILE: tagging/hierarchy/get_taggers.py
function get_taggers (line 7) | def get_taggers(image: str | None) -> list[TaggerInterface]:
FILE: tagging/hierarchy/images_hierarchy.py
class ImageDescription (line 19) | class ImageDescription:
FILE: tagging/manifests/apt_packages.py
function apt_packages_manifest (line 9) | def apt_packages_manifest(container: Container) -> MarkdownPiece:
FILE: tagging/manifests/build_info.py
class BuildInfoConfig (line 15) | class BuildInfoConfig:
method full_image (line 24) | def full_image(self) -> str:
function build_info_manifest (line 28) | def build_info_manifest(config: BuildInfoConfig) -> MarkdownPiece:
FILE: tagging/manifests/conda_environment.py
function conda_environment_manifest (line 10) | def conda_environment_manifest(container: Container) -> MarkdownPiece:
FILE: tagging/manifests/julia_packages.py
function julia_packages_manifest (line 9) | def julia_packages_manifest(container: Container) -> MarkdownPiece:
FILE: tagging/manifests/manifest_interface.py
class MarkdownPiece (line 10) | class MarkdownPiece:
method __post_init__ (line 14) | def __post_init__(self) -> None:
method get_str (line 18) | def get_str(self) -> str:
FILE: tagging/manifests/r_packages.py
function r_packages_manifest (line 9) | def r_packages_manifest(container: Container) -> MarkdownPiece:
FILE: tagging/manifests/spark_info.py
function spark_info_manifest (line 9) | def spark_info_manifest(container: Container) -> MarkdownPiece:
FILE: tagging/taggers/date.py
function date_tagger (line 8) | def date_tagger(container: Container) -> str:
FILE: tagging/taggers/sha.py
function commit_sha_tagger (line 8) | def commit_sha_tagger(container: Container) -> str:
FILE: tagging/taggers/ubuntu_version.py
function ubuntu_version_tagger (line 8) | def ubuntu_version_tagger(container: Container) -> str:
FILE: tagging/taggers/versions.py
function _get_program_version (line 8) | def _get_program_version(container: Container, program: str) -> str:
function _get_pip_package_version (line 12) | def _get_pip_package_version(container: Container, package: str) -> str:
function python_tagger (line 24) | def python_tagger(container: Container) -> str:
function python_major_minor_tagger (line 28) | def python_major_minor_tagger(container: Container) -> str:
function mamba_tagger (line 33) | def mamba_tagger(container: Container) -> str:
function conda_tagger (line 37) | def conda_tagger(container: Container) -> str:
function jupyter_notebook_tagger (line 41) | def jupyter_notebook_tagger(container: Container) -> str:
function jupyter_lab_tagger (line 45) | def jupyter_lab_tagger(container: Container) -> str:
function jupyter_hub_tagger (line 49) | def jupyter_hub_tagger(container: Container) -> str:
function r_tagger (line 53) | def r_tagger(container: Container) -> str:
function julia_tagger (line 57) | def julia_tagger(container: Container) -> str:
function tensorflow_tagger (line 61) | def tensorflow_tagger(container: Container) -> str:
function pytorch_tagger (line 68) | def pytorch_tagger(container: Container) -> str:
function spark_tagger (line 72) | def spark_tagger(container: Container) -> str:
function java_tagger (line 85) | def java_tagger(container: Container) -> str:
FILE: tagging/utils/docker_runner.py
class DockerRunner (line 12) | class DockerRunner:
method __init__ (line 13) | def __init__(
method __enter__ (line 24) | def __enter__(self) -> Container:
method __exit__ (line 33) | def __exit__(
method exec_cmd (line 45) | def exec_cmd(container: Container, cmd: str) -> str:
FILE: tagging/utils/get_platform.py
function unify_aarch64 (line 8) | def unify_aarch64(platform: str) -> str:
function get_platform (line 15) | def get_platform() -> str:
FILE: tagging/utils/get_prefix.py
function get_file_prefix_for_platform (line 8) | def get_file_prefix_for_platform(*, platform: str, variant: str) -> str:
function _get_tag_prefix_for_platform (line 12) | def _get_tag_prefix_for_platform(*, platform: str, variant: str) -> str:
function get_file_prefix (line 18) | def get_file_prefix(variant: str) -> str:
function get_tag_prefix (line 23) | def get_tag_prefix(variant: str) -> str:
FILE: tagging/utils/git_helper.py
class GitHelper (line 9) | class GitHelper:
method commit_hash (line 11) | def commit_hash() -> str:
method commit_hash_tag (line 15) | def commit_hash_tag() -> str:
method commit_message (line 19) | def commit_message() -> str:
FILE: tagging/utils/quoted_output.py
function quoted_output (line 10) | def quoted_output(container: Container, cmd: str) -> str:
FILE: tests/by_image/all-spark-notebook/test_spark_r_nbconvert.py
function test_spark_r_nbconvert (line 24) | def test_spark_r_nbconvert(
FILE: tests/by_image/base-notebook/data/check_listening.py
function make_get_request (line 10) | def make_get_request() -> None:
function check_addrs (line 24) | def check_addrs(family: socket.AddressFamily) -> None:
function test_connect (line 49) | def test_connect() -> None:
FILE: tests/by_image/base-notebook/test_container_options.py
function test_cli_args (line 14) | def test_cli_args(
function test_nb_user_change (line 32) | def test_nb_user_change(container: TrackedContainer) -> None:
function test_unsigned_ssl (line 56) | def test_unsigned_ssl(
function test_custom_internal_port (line 93) | def test_custom_internal_port(
FILE: tests/by_image/base-notebook/test_healthcheck.py
function get_healthy_status (line 13) | def get_healthy_status(
function test_healthy (line 82) | def test_healthy(
function test_healthy_with_proxy (line 115) | def test_healthy_with_proxy(
function test_not_healthy (line 138) | def test_not_healthy(
FILE: tests/by_image/base-notebook/test_ips.py
function ipv6_network (line 18) | def ipv6_network(docker_client: docker.DockerClient) -> Generator[str, N...
function test_ipv46 (line 36) | def test_ipv46(container: TrackedContainer, ipv6_network: str) -> None:
FILE: tests/by_image/base-notebook/test_notebook.py
function test_secured_server (line 8) | def test_secured_server(
FILE: tests/by_image/base-notebook/test_pandoc.py
function test_pandoc (line 10) | def test_pandoc(container: TrackedContainer) -> None:
FILE: tests/by_image/base-notebook/test_start_container.py
function test_start_notebook (line 31) | def test_start_notebook(
function test_tini_entrypoint (line 65) | def test_tini_entrypoint(
FILE: tests/by_image/datascience-notebook/test_julia_datascience.py
function test_julia (line 6) | def test_julia(container: TrackedContainer) -> None:
FILE: tests/by_image/datascience-notebook/test_mimetypes.py
function test_mimetypes (line 7) | def test_mimetypes(container: TrackedContainer) -> None:
FILE: tests/by_image/datascience-notebook/test_pluto_datascience.py
function test_pluto_proxy (line 9) | def test_pluto_proxy(
FILE: tests/by_image/docker-stacks-foundation/test_outdated.py
function test_outdated_packages (line 15) | def test_outdated_packages(container: TrackedContainer, requested_only: ...
FILE: tests/by_image/docker-stacks-foundation/test_package_managers.py
function test_package_manager (line 12) | def test_package_manager(
FILE: tests/by_image/docker-stacks-foundation/test_packages.py
function is_r_package (line 67) | def is_r_package(package: str) -> bool:
function get_package_import_name (line 72) | def get_package_import_name(package: str) -> str:
function check_import_python_package (line 79) | def check_import_python_package(container: TrackedContainer, package: st...
function check_import_r_package (line 84) | def check_import_r_package(container: TrackedContainer, package: str) ->...
function _check_import_packages (line 89) | def _check_import_packages(
function get_r_packages (line 108) | def get_r_packages(package_helper: CondaPackageHelper) -> list[str]:
function test_r_packages (line 117) | def test_r_packages(container: TrackedContainer) -> None:
function get_python_packages (line 123) | def get_python_packages(package_helper: CondaPackageHelper) -> list[str]:
function test_python_packages (line 132) | def test_python_packages(container: TrackedContainer) -> None:
FILE: tests/by_image/docker-stacks-foundation/test_python_version.py
function test_python_version (line 11) | def test_python_version(container: TrackedContainer) -> None:
function test_python_pinned_version (line 26) | def test_python_pinned_version(container: TrackedContainer) -> None:
FILE: tests/by_image/docker-stacks-foundation/test_run_hooks.py
function test_run_hooks_zero_args (line 14) | def test_run_hooks_zero_args(container: TrackedContainer) -> None:
function test_run_hooks_two_args (line 26) | def test_run_hooks_two_args(container: TrackedContainer) -> None:
function test_run_hooks_missing_dir (line 42) | def test_run_hooks_missing_dir(container: TrackedContainer) -> None:
function test_run_hooks_dir_is_file (line 58) | def test_run_hooks_dir_is_file(container: TrackedContainer) -> None:
function test_run_hooks_empty_dir (line 74) | def test_run_hooks_empty_dir(container: TrackedContainer) -> None:
function run_source_in_dir (line 88) | def run_source_in_dir(
function test_run_hooks_change (line 115) | def test_run_hooks_change(container: TrackedContainer) -> None:
function test_run_hooks_executables (line 125) | def test_run_hooks_executables(container: TrackedContainer) -> None:
function test_run_hooks_failures (line 137) | def test_run_hooks_failures(container: TrackedContainer) -> None:
function test_run_hooks_sh_files (line 161) | def test_run_hooks_sh_files(container: TrackedContainer) -> None:
function test_run_hooks_unset (line 168) | def test_run_hooks_unset(container: TrackedContainer) -> None:
FILE: tests/by_image/docker-stacks-foundation/test_units.py
function test_units (line 11) | def test_units(container: TrackedContainer) -> None:
FILE: tests/by_image/docker-stacks-foundation/test_user_options.py
function test_uid_change (line 14) | def test_uid_change(container: TrackedContainer) -> None:
function test_gid_change (line 25) | def test_gid_change(container: TrackedContainer) -> None:
function test_nb_user_change (line 37) | def test_nb_user_change(container: TrackedContainer) -> None:
function test_chown_extra (line 82) | def test_chown_extra(container: TrackedContainer) -> None:
function test_chown_home (line 106) | def test_chown_home(container: TrackedContainer) -> None:
function test_sudo (line 124) | def test_sudo(container: TrackedContainer) -> None:
function test_sudo_path (line 135) | def test_sudo_path(container: TrackedContainer) -> None:
function test_sudo_path_without_grant (line 146) | def test_sudo_path_without_grant(container: TrackedContainer) -> None:
function test_group_add (line 156) | def test_group_add(container: TrackedContainer) -> None:
function test_set_uid (line 174) | def test_set_uid(container: TrackedContainer) -> None:
function test_set_uid_and_nb_user (line 191) | def test_set_uid_and_nb_user(container: TrackedContainer) -> None:
function test_container_not_delete_bind_mount (line 207) | def test_container_not_delete_bind_mount(
function test_jupyter_env_vars_to_unset (line 234) | def test_jupyter_env_vars_to_unset(
function test_secure_path (line 258) | def test_secure_path(container: TrackedContainer, tmp_path: pathlib.Path...
function test_startsh_multiple_exec (line 278) | def test_startsh_multiple_exec(container: TrackedContainer) -> None:
function test_rootless_triplet_change (line 296) | def test_rootless_triplet_change(container: TrackedContainer) -> None:
function test_rootless_triplet_home (line 309) | def test_rootless_triplet_home(container: TrackedContainer) -> None:
function test_rootless_triplet_sudo (line 321) | def test_rootless_triplet_sudo(container: TrackedContainer) -> None:
function test_log_stderr (line 332) | def test_log_stderr(container: TrackedContainer) -> None:
FILE: tests/by_image/julia-notebook/test_julia.py
function test_julia (line 6) | def test_julia(container: TrackedContainer) -> None:
FILE: tests/by_image/julia-notebook/test_pluto.py
function test_pluto_proxy (line 9) | def test_pluto_proxy(
FILE: tests/by_image/minimal-notebook/test_nbconvert.py
function test_nbconvert (line 17) | def test_nbconvert(
FILE: tests/by_image/pyspark-notebook/test_spark.py
function test_spark_shell (line 10) | def test_spark_shell(container: TrackedContainer) -> None:
FILE: tests/by_image/pyspark-notebook/test_spark_nbconvert.py
function test_spark_nbconvert (line 17) | def test_spark_nbconvert(
FILE: tests/by_image/r-notebook/test_R_mimetypes.py
function test_mimetypes (line 7) | def test_mimetypes(container: TrackedContainer) -> None:
FILE: tests/by_image/scipy-notebook/test_cython.py
function test_cython (line 10) | def test_cython(container: TrackedContainer) -> None:
FILE: tests/by_image/scipy-notebook/test_extensions.py
function test_check_extension (line 21) | def test_check_extension(container: TrackedContainer, extension: str) ->...
FILE: tests/by_image/scipy-notebook/test_matplotlib.py
function test_matplotlib (line 29) | def test_matplotlib(
FILE: tests/conftest.py
function http_client (line 20) | def http_client() -> requests.Session:
function docker_client (line 30) | def docker_client() -> docker.DockerClient:
function pytest_addoption (line 37) | def pytest_addoption(parser: pytest.Parser) -> None:
function image_name (line 58) | def image_name(request: pytest.FixtureRequest) -> str:
function container (line 70) | def container(
function free_host_port (line 87) | def free_host_port() -> Generator[int]:
FILE: tests/hierarchy/get_test_dirs.py
function get_test_dirs (line 13) | def get_test_dirs(image: str | None) -> list[Path]:
FILE: tests/run_tests.py
function test_image (line 16) | def test_image(*, registry: str, owner: str, image: str) -> None:
FILE: tests/shared_checks/R_mimetype_check.py
function check_r_mimetypes (line 10) | def check_r_mimetypes(container: TrackedContainer) -> None:
FILE: tests/shared_checks/nbconvert_check.py
function check_nbconvert (line 11) | def check_nbconvert(
FILE: tests/shared_checks/pluto_check.py
function check_pluto_proxy (line 14) | def check_pluto_proxy(
FILE: tests/utils/conda_package_helper.py
class CondaPackageHelper (line 39) | class CondaPackageHelper:
method __init__ (line 42) | def __init__(self, container: TrackedContainer):
method installed_packages (line 47) | def installed_packages(self) -> dict[str, set[str]]:
method requested_packages (line 54) | def requested_packages(self) -> dict[str, set[str]]:
method _parse_package_versions (line 63) | def _parse_package_versions(env_export: str) -> dict[str, set[str]]:
method available_packages (line 101) | def available_packages(self) -> dict[str, set[str]]:
method _extract_available (line 109) | def _extract_available(lines: str) -> defaultdict[str, set[str]]:
method find_updatable_packages (line 119) | def find_updatable_packages(self, requested_only: bool) -> list[dict[s...
method semantic_cmp (line 135) | def semantic_cmp(version_string: str) -> tuple[int, ...]:
method get_outdated_summary (line 160) | def get_outdated_summary(
method get_outdated_table (line 172) | def get_outdated_table(self, updatable: list[dict[str, str]]) -> str:
FILE: tests/utils/tracked_container.py
class TrackedContainer (line 12) | class TrackedContainer:
method __init__ (line 24) | def __init__(
method run_detached (line 33) | def run_detached(self, **kwargs: Any) -> None:
method get_logs (line 57) | def get_logs(self, *, stdout: bool = True, stderr: bool = True) -> str:
method get_health (line 63) | def get_health(self) -> str:
method exec_cmd (line 68) | def exec_cmd(self, cmd: str, **kwargs: Any) -> str:
method run_and_wait (line 86) | def run_and_wait(
method run_and_wait (line 98) | def run_and_wait(
method run_and_wait (line 109) | def run_and_wait(
method get_errors (line 160) | def get_errors(logs: str) -> list[str]:
method get_warnings (line 164) | def get_warnings(logs: str) -> list[str]:
method _lines_starting_with (line 175) | def _lines_starting_with(logs: str, pattern: LiteralString) -> list[str]:
method remove (line 178) | def remove(self) -> None:
FILE: wiki/config.py
class Config (line 8) | class Config:
FILE: wiki/manifest_time.py
function get_manifest_timestamp (line 6) | def get_manifest_timestamp(manifest_file: Path) -> str:
function get_manifest_year_month (line 19) | def get_manifest_year_month(manifest_file: Path) -> str:
FILE: wiki/update_wiki.py
class YearMonthFile (line 26) | class YearMonthFile:
class Statistics (line 32) | class Statistics:
function calculate_monthly_stat (line 38) | def calculate_monthly_stat(
class YearFiles (line 63) | class YearFiles:
function generate_home_wiki_tables (line 68) | def generate_home_wiki_tables(repository: str, all_years: list[YearFiles...
function write_home_wiki_page (line 122) | def write_home_wiki_page(wiki_dir: Path, repository: str) -> None:
function update_monthly_wiki_page (line 151) | def update_monthly_wiki_page(wiki_dir: Path, build_history_line: str) ->...
function remove_old_manifests (line 177) | def remove_old_manifests(wiki_dir: Path) -> None:
function copy_manifest_files (line 190) | def copy_manifest_files(config: Config) -> None:
function update_wiki (line 203) | def update_wiki(config: Config) -> None:
Condensed preview — 273 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (539K chars).
[
{
"path": ".devcontainer/Dockerfile",
"chars": 283,
"preview": "FROM mcr.microsoft.com/devcontainers/python:3.13\n\nCOPY requirements-dev.txt /tmp/requirements-dev.txt\nCOPY docs/requirem"
},
{
"path": ".devcontainer/devcontainer.json",
"chars": 646,
"preview": "{\n \"name\": \"Jupyter Docker Stacks\",\n \"build\": {\n \"context\": \"..\",\n \"dockerfile\": \"Dockerfile\"\n },\n\n \"features\""
},
{
"path": ".flake8",
"chars": 98,
"preview": "[flake8]\nmax-line-length = 88\nselect = C, E, F, W, B, B950\nextend-ignore = E203, E501, E704, W503\n"
},
{
"path": ".gitattributes",
"chars": 19,
"preview": "* text=auto eol=lf\n"
},
{
"path": ".github/ISSUE_TEMPLATE/blank.yml",
"chars": 441,
"preview": "name: \"(maintainers only) Blank issue\"\ndescription: For maintainers only\nlabels: []\n\nbody:\n - type: markdown\n attrib"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.yml",
"chars": 4029,
"preview": "name: Bug report\ndescription: Create a report to help us improve\nlabels: [\"type:Bug\"]\n\nbody:\n - type: markdown\n attr"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 571,
"preview": "blank_issues_enabled: false\ncontact_links:\n - name: 📖 - Jupyter Docker Stacks documentation\n url: https://jupyter-do"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.yml",
"chars": 2478,
"preview": "name: Feature request\ndescription: Suggest a new feature for this project\nlabels: [\"type:Enhancement\"]\n\nbody:\n - type: "
},
{
"path": ".github/actions/apply-single-tags/action.yml",
"chars": 1835,
"preview": "name: Apply single platform tags\ndescription: Download the image tar, load it to Docker and apply tags to it\n\ninputs:\n "
},
{
"path": ".github/actions/create-dev-env/action.yml",
"chars": 789,
"preview": "name: Build environment\ndescription: Create a build environment\n\nruns:\n using: composite\n steps:\n - name: Set Up Py"
},
{
"path": ".github/actions/free-disk-space/action.yml",
"chars": 832,
"preview": "name: \"Free Disk Space (Ubuntu)\"\ndescription: \"A GitHub Action to free up disk space on an Ubuntu GitHub Actions runner."
},
{
"path": ".github/actions/load-image/action.yml",
"chars": 938,
"preview": "name: Load Docker image\ndescription: Download the image tar and load it to Docker\n\ninputs:\n image:\n description: Ima"
},
{
"path": ".github/dependabot.yml",
"chars": 1361,
"preview": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where "
},
{
"path": ".github/pull_request_template.md",
"chars": 486,
"preview": "## Describe your changes\n\n## Issue ticket if applicable\n\n<!-- Example - Fix: https://github.com/jupyter/docker-stacks/is"
},
{
"path": ".github/workflows/contributed-recipes.yml",
"chars": 3286,
"preview": "name: Test the contributed recipes\n\nenv:\n REGISTRY: quay.io\n OWNER: ${{ github.repository_owner }}\n\non:\n schedule:\n "
},
{
"path": ".github/workflows/docker-build-test-upload.yml",
"chars": 5262,
"preview": "name: Download a parent image, build a new one, and test it; upload the image, tags, build history line and manifest to "
},
{
"path": ".github/workflows/docker-tag-merge.yml",
"chars": 2426,
"preview": "name: Merge single platform tags\n\nenv:\n REGISTRY: quay.io\n PUSH_TO_REGISTRY: ${{ (github.repository_owner == 'jupyter'"
},
{
"path": ".github/workflows/docker-tag-push-merge.yml",
"chars": 1049,
"preview": "name: Download a Docker image and its tags from GitHub artifacts, apply them, and push the image to the Registry; then m"
},
{
"path": ".github/workflows/docker-tag-push.yml",
"chars": 2613,
"preview": "name: Download a Docker image and its tags from GitHub artifacts, apply them, and push the image to the Registry\n\nenv:\n "
},
{
"path": ".github/workflows/docker-wiki-update.yml",
"chars": 2210,
"preview": "name: Download build history lines and manifests from GitHub artifacts and push them to the GitHub wiki\n# We're doing ev"
},
{
"path": ".github/workflows/docker.yml",
"chars": 15049,
"preview": "name: Docker Stacks\n\n# [FAST_BUILD] in the PR title makes this workflow only build\n# the `jupyter/docker-stacks-foundati"
},
{
"path": ".github/workflows/pre-commit.yml",
"chars": 717,
"preview": "name: Run pre-commit hooks\n\non:\n pull_request:\n push:\n branches:\n - main\n workflow_dispatch:\n\npermissions:\n "
},
{
"path": ".github/workflows/registry-move.yml",
"chars": 1973,
"preview": "name: Move some images from Docker Hub to Quay.io\n\nenv:\n OWNER: ${{ github.repository_owner }}\n PUSH_TO_REGISTRY: ${{ "
},
{
"path": ".github/workflows/registry-overviews.yml",
"chars": 1358,
"preview": "name: Update Registry overviews\n\nenv:\n OWNER: ${{ github.repository_owner }}\n\non:\n push:\n branches:\n - main\n "
},
{
"path": ".github/workflows/sphinx.yml",
"chars": 1793,
"preview": "name: Build Sphinx Documentation and check links\n\non:\n schedule:\n # Weekly, at 03:00 on Monday UTC\n - cron: \"0 3 "
},
{
"path": ".gitignore",
"chars": 3883,
"preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packagi"
},
{
"path": ".hadolint.yaml",
"chars": 46,
"preview": "---\nignored:\n - DL3006\n - DL3008\n - DL3013\n"
},
{
"path": ".markdownlint.yaml",
"chars": 146,
"preview": "# Default state for all rules\ndefault: true\n\n# MD013/line-length - Line length\nMD013:\n # Number of characters\n line_le"
},
{
"path": ".pre-commit-config.yaml",
"chars": 5783,
"preview": "---\n# pre-commit is a tool to perform a predefined set of tasks manually and/or\n# automatically before git commits are m"
},
{
"path": ".readthedocs.yaml",
"chars": 1093,
"preview": "# Read the Docs configuration file for Sphinx projects\n# See https://docs.readthedocs.io/en/stable/config-file/v2.html f"
},
{
"path": "CHANGELOG.md",
"chars": 7744,
"preview": "# Changelog\n\nThis changelog only contains breaking and/or significant changes manually introduced to this repository (us"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 177,
"preview": "# Project `jupyter/docker-stacks` Code of Conduct\n\nPlease see the [Project Jupyter Code of Conduct](https://github.com/j"
},
{
"path": "CONTRIBUTING.md",
"chars": 1635,
"preview": "Thanks for contributing!\nPlease see the **Contributor Guide** section in [the documentation](https://jupyter-docker-stac"
},
{
"path": "LICENSE.md",
"chars": 1563,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2001-2015, IPython Development Team\n\nCopyright (c) 2015-, Jupyter Development Team\n\n"
},
{
"path": "Makefile",
"chars": 4921,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n.PHONY: docs help t"
},
{
"path": "README.md",
"chars": 11143,
"preview": "# Jupyter Docker Stacks\n\n[ Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\n# https://quay.io/"
},
{
"path": "binder/README.ipynb",
"chars": 3183,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# jupyter/base-notebook on Binder\\n"
},
{
"path": "docs/conf.py",
"chars": 2886,
"preview": "# Configuration file for the Sphinx documentation builder.\n#\n# For the full list of built-in configuration values, see t"
},
{
"path": "docs/contributing/features.md",
"chars": 2800,
"preview": "# New Features\n\nThank you for contributing to the Jupyter Docker Stacks!\nWe review pull requests for new features (e.g.,"
},
{
"path": "docs/contributing/issues.md",
"chars": 1573,
"preview": "# Project Issues\n\nWe appreciate you taking the time to report an issue you encountered while using the Jupyter Docker St"
},
{
"path": "docs/contributing/lint.md",
"chars": 2901,
"preview": "# Lint\n\nTo enforce some rules, **linters** are used in this project.\nLinters can be run either during the **development "
},
{
"path": "docs/contributing/packages.md",
"chars": 975,
"preview": "# Package Updates\n\nGenerally, we do not pin package versions in our `Dockerfile`s.\nDependency resolution is a difficult "
},
{
"path": "docs/contributing/recipes.md",
"chars": 1030,
"preview": "# New Recipes\n\nWe welcome contributions of [recipes](../using/recipes.md), which are short examples of using, configurin"
},
{
"path": "docs/contributing/stacks.md",
"chars": 7321,
"preview": "# Community Stacks\n\nWe love to see the community create and share new Jupyter Docker images.\nWe've put together a [cooki"
},
{
"path": "docs/contributing/tests.md",
"chars": 2363,
"preview": "# Image Tests\n\nWe greatly appreciate Pull Requests that extend the automated tests that vet the basic functionality of t"
},
{
"path": "docs/index.rst",
"chars": 928,
"preview": ".. include:: ../README.md\n :parser: myst_parser.sphinx_\n\nTable of Contents\n-----------------\n\n.. toctree::\n :maxdept"
},
{
"path": "docs/maintaining/new-images-and-packages-policy.md",
"chars": 1682,
"preview": "# New images / packages policy\n\nThere are many things we consider while adding new images and packages.\n\nHere is a non-e"
},
{
"path": "docs/maintaining/tagging.md",
"chars": 3778,
"preview": "# Tags and manifests\n\nThe main purpose of the source code in [the `tagging` folder](https://github.com/jupyter/docker-st"
},
{
"path": "docs/maintaining/tagging_examples/docker_runner.py",
"chars": 245,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nfrom tagging.utils."
},
{
"path": "docs/maintaining/tagging_examples/git_helper.py",
"chars": 243,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nfrom tagging.utils."
},
{
"path": "docs/maintaining/tasks.md",
"chars": 3302,
"preview": "# Maintainer Playbook\n\n## Merging Pull Requests\n\nTo build new images and publish them to the Registry, do the following:"
},
{
"path": "docs/requirements.txt",
"chars": 293,
"preview": "# ReadTheDocs environment contains old package versions preinstalled\n# So, to ensure we have modern packages, we pin min"
},
{
"path": "docs/using/changelog.md",
"chars": 79,
"preview": "```{include} ../../CHANGELOG.md\n\n```\n\n<!-- markdownlint-disable-file MD041 -->\n"
},
{
"path": "docs/using/common.md",
"chars": 16323,
"preview": "# Common Features\n\nExcept for `jupyter/docker-stacks-foundation`, a container launched from any Jupyter Docker Stacks im"
},
{
"path": "docs/using/custom-images.md",
"chars": 3923,
"preview": "# Building a custom set of images\n\nThis section describes how to build a custom set of images.\nIt may be helpful if you "
},
{
"path": "docs/using/faq.md",
"chars": 2377,
"preview": "# Frequently Asked Questions (FAQ)\n\n## How to persist user data\n\nThere are two types of data you might want to persist.\n"
},
{
"path": "docs/using/recipe_code/custom_environment.dockerfile",
"chars": 2226,
"preview": "ARG BASE_IMAGE=quay.io/jupyter/minimal-notebook\nFROM $BASE_IMAGE\n\n# Name your environment and choose the Python version\n"
},
{
"path": "docs/using/recipe_code/dask_jupyterlab.dockerfile",
"chars": 288,
"preview": "ARG BASE_IMAGE=quay.io/jupyter/base-notebook\nFROM $BASE_IMAGE\n\n# Install the Dask dashboard\nRUN mamba install --yes 'das"
},
{
"path": "docs/using/recipe_code/docker-bake.custom-python.hcl",
"chars": 1049,
"preview": "group \"default\" {\n targets = [\"custom-notebook\"]\n}\n\ntarget \"foundation\" {\n context = \"https://github.com/jupyter/d"
},
{
"path": "docs/using/recipe_code/generate_matrix.py",
"chars": 1840,
"preview": "#!/usr/bin/env python3\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD Licen"
},
{
"path": "docs/using/recipe_code/ijavascript.dockerfile",
"chars": 576,
"preview": "ARG BASE_IMAGE=quay.io/jupyter/base-notebook\nFROM $BASE_IMAGE\n\nUSER root\n\nRUN apt-get update --yes && \\\n apt-get inst"
},
{
"path": "docs/using/recipe_code/jupyterhub_version.dockerfile",
"chars": 235,
"preview": "ARG BASE_IMAGE=quay.io/jupyter/base-notebook\nFROM $BASE_IMAGE\n\nRUN mamba install --yes 'jupyterhub-singleuser==5.2.1' &&"
},
{
"path": "docs/using/recipe_code/mamba_install.dockerfile",
"chars": 481,
"preview": "ARG BASE_IMAGE=quay.io/jupyter/base-notebook\nFROM $BASE_IMAGE\n\nRUN mamba install --yes 'flake8' && \\\n mamba clean --a"
},
{
"path": "docs/using/recipe_code/manpage_install.dockerfile",
"chars": 616,
"preview": "ARG BASE_IMAGE=quay.io/jupyter/base-notebook\nFROM $BASE_IMAGE\n\n# Fix: https://github.com/hadolint/hadolint/wiki/DL4006\n#"
},
{
"path": "docs/using/recipe_code/microsoft_odbc.dockerfile",
"chars": 1328,
"preview": "ARG BASE_IMAGE=quay.io/jupyter/base-notebook\nFROM $BASE_IMAGE\n\n# Fix: https://github.com/hadolint/hadolint/wiki/DL4006\n#"
},
{
"path": "docs/using/recipe_code/oracledb.dockerfile",
"chars": 3102,
"preview": "ARG BASE_IMAGE=quay.io/jupyter/base-notebook\nFROM $BASE_IMAGE\n\nUSER root\n\n# Install Java & Oracle SQL Instant Client\nRUN"
},
{
"path": "docs/using/recipe_code/pip_install.dockerfile",
"chars": 481,
"preview": "ARG BASE_IMAGE=quay.io/jupyter/base-notebook\nFROM $BASE_IMAGE\n\n# Install in the default python3 environment\nRUN pip inst"
},
{
"path": "docs/using/recipe_code/requirements.txt",
"chars": 10,
"preview": "autoflake\n"
},
{
"path": "docs/using/recipe_code/rise_jupyterlab.dockerfile",
"chars": 222,
"preview": "ARG BASE_IMAGE=quay.io/jupyter/base-notebook\nFROM $BASE_IMAGE\n\nRUN mamba install --yes 'jupyterlab_rise' && \\\n mamba "
},
{
"path": "docs/using/recipe_code/spellcheck_notebook_v6.dockerfile",
"chars": 478,
"preview": "# Using Docker Hub here, because this image is old and not pushed to Quay.io\nARG BASE_IMAGE=docker.io/jupyter/base-noteb"
},
{
"path": "docs/using/recipe_code/xgboost.dockerfile",
"chars": 217,
"preview": "ARG BASE_IMAGE=quay.io/jupyter/base-notebook\nFROM $BASE_IMAGE\n\nRUN mamba install --yes 'py-xgboost' && \\\n mamba clean"
},
{
"path": "docs/using/recipes.md",
"chars": 19211,
"preview": "# Contributed Recipes\n\nUsers sometimes share interesting ways of using the Jupyter Docker Stacks.\nWe encourage users to "
},
{
"path": "docs/using/running.md",
"chars": 9011,
"preview": "# Running a Container\n\nUsing one of the Jupyter Docker Stacks requires two choices:\n\n1. Which Docker image you wish to u"
},
{
"path": "docs/using/selecting.md",
"chars": 24031,
"preview": "# Selecting an Image\n\n- [Core Stacks](#core-stacks)\n- [Image Relationships](#image-relationships)\n- [Community Stacks](#"
},
{
"path": "docs/using/specifics.md",
"chars": 10909,
"preview": "# Image Specifics\n\nThis page provides details about features specific to one or more images.\n\n## Apache Spark™\n\n### Spec"
},
{
"path": "docs/using/troubleshooting.md",
"chars": 13655,
"preview": "# Troubleshooting Common Problems\n\nWhen troubleshooting, you may see unexpected behaviors or receive an error message.\nT"
},
{
"path": "examples/README.md",
"chars": 134,
"preview": "# Examples\n\nThese examples are not tested and might not work.\nPlease, send PRs if you start using these examples and see"
},
{
"path": "examples/docker-compose/README.md",
"chars": 5766,
"preview": "# Docker Compose example\n\nThis example demonstrate how to deploy docker-stack notebook containers to any Docker Machine-"
},
{
"path": "examples/docker-compose/bin/letsencrypt.sh",
"chars": 1532,
"preview": "#!/bin/bash\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\n# Use "
},
{
"path": "examples/docker-compose/bin/sl-dns.sh",
"chars": 803,
"preview": "#!/bin/bash\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\nset -e"
},
{
"path": "examples/docker-compose/bin/softlayer.sh",
"chars": 410,
"preview": "#!/bin/bash\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\n# Set "
},
{
"path": "examples/docker-compose/bin/vbox.sh",
"chars": 314,
"preview": "#!/bin/bash\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\n# Set "
},
{
"path": "examples/docker-compose/notebook/Dockerfile",
"chars": 529,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\n# Pick your favori"
},
{
"path": "examples/docker-compose/notebook/build.sh",
"chars": 348,
"preview": "#!/bin/bash\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\nDIR=\"$"
},
{
"path": "examples/docker-compose/notebook/down.sh",
"chars": 407,
"preview": "#!/bin/bash\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\nDIR=\"$"
},
{
"path": "examples/docker-compose/notebook/env.sh",
"chars": 497,
"preview": "#!/bin/bash\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\n# Set "
},
{
"path": "examples/docker-compose/notebook/letsencrypt-notebook.yml",
"chars": 655,
"preview": "---\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\nversion: \"2\"\n\n"
},
{
"path": "examples/docker-compose/notebook/notebook.yml",
"chars": 345,
"preview": "---\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\nversion: \"2\"\n\n"
},
{
"path": "examples/docker-compose/notebook/secure-notebook.yml",
"chars": 413,
"preview": "---\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\nversion: \"2\"\n\n"
},
{
"path": "examples/docker-compose/notebook/up.sh",
"chars": 1836,
"preview": "#!/bin/bash\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\nset -e"
},
{
"path": "examples/make-deploy/Dockerfile",
"chars": 529,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\n# Pick your favori"
},
{
"path": "examples/make-deploy/Makefile",
"chars": 1333,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\n.PHONY: help check"
},
{
"path": "examples/make-deploy/README.md",
"chars": 4459,
"preview": "# Make deploy example\n\nThis folder contains a Makefile and a set of supporting files demonstrating how to run a docker-s"
},
{
"path": "examples/make-deploy/letsencrypt.makefile",
"chars": 2349,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\n# BE CAREFUL when "
},
{
"path": "examples/make-deploy/self-signed.makefile",
"chars": 428,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\nself-signed-notebo"
},
{
"path": "examples/make-deploy/softlayer.makefile",
"chars": 1193,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\nsoftlayer-vm: expo"
},
{
"path": "examples/make-deploy/virtualbox.makefile",
"chars": 397,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\nvirtualbox-vm: exp"
},
{
"path": "examples/openshift/README.md",
"chars": 8889,
"preview": "# OpenShift example\n\nThis example provides templates for deploying the Jupyter Project docker-stacks images to OpenShift"
},
{
"path": "examples/openshift/templates.json",
"chars": 4705,
"preview": "{\n \"kind\": \"Template\",\n \"apiVersion\": \"v1\",\n \"metadata\": {\n \"name\": \"jupyter-notebook\",\n \"annotations\": {\n "
},
{
"path": "examples/source-to-image/README.md",
"chars": 8405,
"preview": "# Custom Jupyter Notebook images\n\nThis example provides scripts for building custom Jupyter Notebook images containing n"
},
{
"path": "examples/source-to-image/assemble",
"chars": 1249,
"preview": "#!/bin/bash\n\nset -x\n\nset -eo pipefail\n\n# Remove any 'environment.yml' or 'requirements.txt' files which may\n# have been "
},
{
"path": "examples/source-to-image/run",
"chars": 76,
"preview": "#!/bin/bash\n\n# Start up the notebook instance.\n\nexec start-notebook.py \"$@\"\n"
},
{
"path": "examples/source-to-image/save-artifacts",
"chars": 45,
"preview": "#!/bin/bash\n\ntar cf - --files-from /dev/null\n"
},
{
"path": "examples/source-to-image/templates.json",
"chars": 10577,
"preview": "{\n \"kind\": \"List\",\n \"apiVersion\": \"v1\",\n \"items\": [\n {\n \"kind\": \"Template\",\n \"apiVersion\": \"v1\",\n \""
},
{
"path": "images/all-spark-notebook/.dockerignore",
"chars": 26,
"preview": "# Documentation\nREADME.md\n"
},
{
"path": "images/all-spark-notebook/Dockerfile",
"chars": 1352,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nARG REGISTRY=quay.i"
},
{
"path": "images/all-spark-notebook/README.md",
"chars": 671,
"preview": "# Jupyter Notebook Python, R, Spark Stack\n\nGitHub Actions in the <https://github.com/jupyter/docker-stacks> project buil"
},
{
"path": "images/base-notebook/.dockerignore",
"chars": 26,
"preview": "# Documentation\nREADME.md\n"
},
{
"path": "images/base-notebook/Dockerfile",
"chars": 3808,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nARG REGISTRY=quay.i"
},
{
"path": "images/base-notebook/README.md",
"chars": 523,
"preview": "# Base Jupyter Notebook Stack\n\nGitHub Actions in the <https://github.com/jupyter/docker-stacks> project builds and pushe"
},
{
"path": "images/base-notebook/docker_healthcheck.py",
"chars": 1255,
"preview": "#!/usr/bin/env python3\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD Licen"
},
{
"path": "images/base-notebook/jupyter_server_config.py",
"chars": 1812,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n# mypy: ignore-erro"
},
{
"path": "images/base-notebook/start-notebook.py",
"chars": 1532,
"preview": "#!/usr/bin/env python\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD Licens"
},
{
"path": "images/base-notebook/start-notebook.sh",
"chars": 152,
"preview": "#!/bin/bash\n# Shim to emit warning and call start-notebook.py\necho \"WARNING: Use start-notebook.py instead\"\n\nexec /usr/l"
},
{
"path": "images/base-notebook/start-singleuser.py",
"chars": 731,
"preview": "#!/usr/bin/env python\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD Licens"
},
{
"path": "images/base-notebook/start-singleuser.sh",
"chars": 158,
"preview": "#!/bin/bash\n# Shim to emit warning and call start-singleuser.py\necho \"WARNING: Use start-singleuser.py instead\"\n\nexec /u"
},
{
"path": "images/datascience-notebook/.dockerignore",
"chars": 26,
"preview": "# Documentation\nREADME.md\n"
},
{
"path": "images/datascience-notebook/Dockerfile",
"chars": 1908,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nARG REGISTRY=quay.i"
},
{
"path": "images/datascience-notebook/README.md",
"chars": 545,
"preview": "# Jupyter Notebook Data Science Stack\n\nGitHub Actions in the <https://github.com/jupyter/docker-stacks> project builds a"
},
{
"path": "images/docker-stacks-foundation/.dockerignore",
"chars": 26,
"preview": "# Documentation\nREADME.md\n"
},
{
"path": "images/docker-stacks-foundation/10activate-conda-env.sh",
"chars": 406,
"preview": "#!/bin/bash\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\n# This"
},
{
"path": "images/docker-stacks-foundation/Dockerfile",
"chars": 6684,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\n# Ubuntu 24.04 (no"
},
{
"path": "images/docker-stacks-foundation/README.md",
"chars": 542,
"preview": "# Foundation Jupyter Stack\n\nGitHub Actions in the <https://github.com/jupyter/docker-stacks> project builds and pushes t"
},
{
"path": "images/docker-stacks-foundation/fix-permissions",
"chars": 1041,
"preview": "#!/bin/bash\n# Set permissions on a directory\n# After any installation, if a directory needs to be (human) user-writable,"
},
{
"path": "images/docker-stacks-foundation/initial-condarc",
"chars": 163,
"preview": "# Conda configuration see https://conda.io/projects/conda/en/latest/configuration.html\n\nauto_update_conda: false\nshow_ch"
},
{
"path": "images/docker-stacks-foundation/run-hooks.sh",
"chars": 1665,
"preview": "#!/bin/bash\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\n# iden"
},
{
"path": "images/docker-stacks-foundation/start.sh",
"chars": 12672,
"preview": "#!/bin/bash\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\nset -e"
},
{
"path": "images/julia-notebook/.dockerignore",
"chars": 26,
"preview": "# Documentation\nREADME.md\n"
},
{
"path": "images/julia-notebook/Dockerfile",
"chars": 1079,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nARG REGISTRY=quay.i"
},
{
"path": "images/julia-notebook/README.md",
"chars": 526,
"preview": "# Jupyter Notebook Julia Stack\n\nGitHub Actions in the <https://github.com/jupyter/docker-stacks> project builds and push"
},
{
"path": "images/minimal-notebook/.dockerignore",
"chars": 26,
"preview": "# Documentation\nREADME.md\n"
},
{
"path": "images/minimal-notebook/Dockerfile",
"chars": 1946,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nARG REGISTRY=quay.i"
},
{
"path": "images/minimal-notebook/README.md",
"chars": 532,
"preview": "# Minimal Jupyter Notebook Stack\n\nGitHub Actions in the <https://github.com/jupyter/docker-stacks> project builds and pu"
},
{
"path": "images/minimal-notebook/Rprofile.site",
"chars": 292,
"preview": "# Add R mimetype to specify how the plot returns from R to the browser.\n# https://notebook.community/andrie/jupyter-note"
},
{
"path": "images/minimal-notebook/setup-scripts/activate_notebook_custom_env.py",
"chars": 701,
"preview": "#!/usr/bin/env python3\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD Licen"
},
{
"path": "images/minimal-notebook/setup-scripts/setup-julia-packages.bash",
"chars": 2445,
"preview": "#!/bin/bash\nset -exuo pipefail\n# Requirements:\n# - Run as a non-root user\n# - The JULIA_PKGDIR environment variable is s"
},
{
"path": "images/minimal-notebook/setup-scripts/setup_julia.py",
"chars": 3050,
"preview": "#!/usr/bin/env python3\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD Licen"
},
{
"path": "images/pyspark-notebook/.dockerignore",
"chars": 26,
"preview": "# Documentation\nREADME.md\n"
},
{
"path": "images/pyspark-notebook/Dockerfile",
"chars": 2804,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nARG REGISTRY=quay.i"
},
{
"path": "images/pyspark-notebook/README.md",
"chars": 664,
"preview": "# Jupyter Notebook Python, Spark Stack\n\nGitHub Actions in the <https://github.com/jupyter/docker-stacks> project builds "
},
{
"path": "images/pyspark-notebook/ipython_kernel_config.py",
"chars": 659,
"preview": "# Configuration file for ipython-kernel.\n# See <https://ipython.readthedocs.io/en/stable/config/options/kernel.html>\n\n# "
},
{
"path": "images/pyspark-notebook/setup_spark.py",
"chars": 4209,
"preview": "#!/usr/bin/env python3\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD Licen"
},
{
"path": "images/pytorch-notebook/.dockerignore",
"chars": 26,
"preview": "# Documentation\nREADME.md\n"
},
{
"path": "images/pytorch-notebook/Dockerfile",
"chars": 741,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nARG REGISTRY=quay.i"
},
{
"path": "images/pytorch-notebook/README.md",
"chars": 546,
"preview": "# Jupyter Notebook PyTorch Deep Learning Stack\n\nGitHub Actions in the <https://github.com/jupyter/docker-stacks> project"
},
{
"path": "images/pytorch-notebook/cuda12/Dockerfile",
"chars": 1203,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nARG REGISTRY=quay.i"
},
{
"path": "images/pytorch-notebook/cuda13/Dockerfile",
"chars": 1203,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nARG REGISTRY=quay.i"
},
{
"path": "images/r-notebook/.dockerignore",
"chars": 26,
"preview": "# Documentation\nREADME.md\n"
},
{
"path": "images/r-notebook/Dockerfile",
"chars": 1641,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nARG REGISTRY=quay.i"
},
{
"path": "images/r-notebook/README.md",
"chars": 514,
"preview": "# Jupyter Notebook R Stack\n\nGitHub Actions in the <https://github.com/jupyter/docker-stacks> project builds and pushes t"
},
{
"path": "images/scipy-notebook/.dockerignore",
"chars": 26,
"preview": "# Documentation\nREADME.md\n"
},
{
"path": "images/scipy-notebook/Dockerfile",
"chars": 2321,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nARG REGISTRY=quay.i"
},
{
"path": "images/scipy-notebook/README.md",
"chars": 538,
"preview": "# Jupyter Notebook Scientific Python Stack\n\nGitHub Actions in the <https://github.com/jupyter/docker-stacks> project bui"
},
{
"path": "images/tensorflow-notebook/.dockerignore",
"chars": 26,
"preview": "# Documentation\nREADME.md\n"
},
{
"path": "images/tensorflow-notebook/Dockerfile",
"chars": 1209,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nARG REGISTRY=quay.i"
},
{
"path": "images/tensorflow-notebook/README.md",
"chars": 677,
"preview": "# Jupyter Notebook TensorFlow Deep Learning Stack\n\nGitHub Actions in the <https://github.com/jupyter/docker-stacks> proj"
},
{
"path": "images/tensorflow-notebook/cuda/20tensorboard-proxy-env.sh",
"chars": 295,
"preview": "#!/bin/bash\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\nset -e"
},
{
"path": "images/tensorflow-notebook/cuda/Dockerfile",
"chars": 1789,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nARG REGISTRY=quay.i"
},
{
"path": "images/tensorflow-notebook/cuda/nvidia-lib-dirs.sh",
"chars": 459,
"preview": "#!/bin/bash\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\n# This"
},
{
"path": "mypy.ini",
"chars": 1084,
"preview": "# Mypy is an optional static type checker for Python that aims to combine\n# the benefits of dynamic (or \"duck\") typing a"
},
{
"path": "requirements-dev.txt",
"chars": 228,
"preview": "docker\nplumbum\npre-commit\npytest\npytest-rerunfailures\n# `pytest-xdist` is a plugin that provides the `--numprocesses` fl"
},
{
"path": "tagging/README.md",
"chars": 227,
"preview": "# Docker stacks tagging and manifest creation\n\nPlease, refer to the [tagging section of documentation](https://jupyter-d"
},
{
"path": "tagging/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "tagging/apps/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "tagging/apps/apply_tags.py",
"chars": 1185,
"preview": "#!/usr/bin/env python3\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD Licen"
},
{
"path": "tagging/apps/common_cli_arguments.py",
"chars": 2319,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nimport argparse\nfro"
},
{
"path": "tagging/apps/config.py",
"chars": 524,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nfrom dataclasses im"
},
{
"path": "tagging/apps/merge_tags.py",
"chars": 3749,
"preview": "#!/usr/bin/env python3\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD Licen"
},
{
"path": "tagging/apps/write_manifest.py",
"chars": 4696,
"preview": "#!/usr/bin/env python3\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD Licen"
},
{
"path": "tagging/apps/write_tags_file.py",
"chars": 1800,
"preview": "#!/usr/bin/env python3\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD Licen"
},
{
"path": "tagging/hierarchy/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "tagging/hierarchy/get_manifests.py",
"chars": 502,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nfrom tagging.hierar"
},
{
"path": "tagging/hierarchy/get_taggers.py",
"chars": 484,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nfrom tagging.hierar"
},
{
"path": "tagging/hierarchy/images_hierarchy.py",
"chars": 3009,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nfrom dataclasses im"
},
{
"path": "tagging/manifests/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "tagging/manifests/apt_packages.py",
"chars": 468,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nfrom docker.models."
},
{
"path": "tagging/manifests/build_info.py",
"chars": 1673,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nimport textwrap\nfro"
},
{
"path": "tagging/manifests/conda_environment.py",
"chars": 712,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nfrom docker.models."
},
{
"path": "tagging/manifests/julia_packages.py",
"chars": 630,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nfrom docker.models."
},
{
"path": "tagging/manifests/manifest_interface.py",
"chars": 563,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nfrom collections.ab"
},
{
"path": "tagging/manifests/r_packages.py",
"chars": 604,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nfrom docker.models."
},
{
"path": "tagging/manifests/spark_info.py",
"chars": 511,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nfrom docker.models."
},
{
"path": "tagging/taggers/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "tagging/taggers/date.py",
"chars": 281,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nimport datetime\n\nfr"
},
{
"path": "tagging/taggers/sha.py",
"chars": 289,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nfrom docker.models."
},
{
"path": "tagging/taggers/tagger_interface.py",
"chars": 232,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nfrom collections.ab"
},
{
"path": "tagging/taggers/ubuntu_version.py",
"chars": 571,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nfrom docker.models."
},
{
"path": "tagging/taggers/versions.py",
"chars": 2761,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nfrom docker.models."
},
{
"path": "tagging/utils/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "tagging/utils/docker_runner.py",
"chars": 1968,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nimport logging\nfrom"
},
{
"path": "tagging/utils/get_platform.py",
"chars": 434,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nimport platform\n\nAL"
},
{
"path": "tagging/utils/get_prefix.py",
"chars": 760,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nfrom tagging.utils."
},
{
"path": "tagging/utils/git_helper.py",
"chars": 651,
"preview": "#!/usr/bin/env python3\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD Licen"
},
{
"path": "tagging/utils/quoted_output.py",
"chars": 768,
"preview": "# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\nimport textwrap\n\nfr"
},
{
"path": "tests/README.md",
"chars": 191,
"preview": "# Docker stacks testing\n\nPlease, refer to the [testing section of documentation](https://jupyter-docker-stacks.readthedo"
},
{
"path": "tests/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "tests/by_image/all-spark-notebook/data/local_sparkR.ipynb",
"chars": 804,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": "
},
{
"path": "tests/by_image/all-spark-notebook/data/local_sparklyr.ipynb",
"chars": 942,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": "
}
]
// ... and 73 more files (download for full content)
About this extraction
This page contains the full source code of the jupyter/docker-stacks GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 273 files (487.0 KB), approximately 134.0k tokens, and a symbol index with 196 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.