mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-18 07:23:00 +00:00
Merge branch 'main' into alexanderchosen
This commit is contained in:
12
.github/workflows/release.yml
vendored
12
.github/workflows/release.yml
vendored
@@ -108,10 +108,10 @@ jobs:
|
|||||||
# https://github.com/docker/build-push-action/tree/v2.4.0#usage
|
# https://github.com/docker/build-push-action/tree/v2.4.0#usage
|
||||||
# https://github.com/docker/build-push-action/blob/v2.4.0/docs/advanced/multi-platform.md
|
# https://github.com/docker/build-push-action/blob/v2.4.0/docs/advanced/multi-platform.md
|
||||||
- name: Set up QEMU (for docker buildx)
|
- name: Set up QEMU (for docker buildx)
|
||||||
uses: docker/setup-qemu-action@8b122486cedac8393e77aa9734c3528886e4a1a8 # associated tag: v1.0.2
|
uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # associated tag: v1.0.2
|
||||||
|
|
||||||
- name: Set up Docker Buildx (for multi-arch builds)
|
- name: Set up Docker Buildx (for multi-arch builds)
|
||||||
uses: docker/setup-buildx-action@dc7b9719a96d48369863986a06765841d7ea23f6 # associated tag: v1.1.2
|
uses: docker/setup-buildx-action@95cb08cb2672c73d4ffd2f422e6d11953d2a9c70
|
||||||
with:
|
with:
|
||||||
# Allows pushing to registry on localhost:5000
|
# Allows pushing to registry on localhost:5000
|
||||||
driver-opts: network=host
|
driver-opts: network=host
|
||||||
@@ -149,7 +149,7 @@ jobs:
|
|||||||
branchRegex: ^\w[\w-.]*$
|
branchRegex: ^\w[\w-.]*$
|
||||||
|
|
||||||
- name: Build and push jupyterhub
|
- name: Build and push jupyterhub
|
||||||
uses: docker/build-push-action@c84f38281176d4c9cdb1626ffafcd6b3911b5d94
|
uses: docker/build-push-action@c56af957549030174b10d6867f20e78cfd7debc5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
@@ -170,7 +170,7 @@ jobs:
|
|||||||
branchRegex: ^\w[\w-.]*$
|
branchRegex: ^\w[\w-.]*$
|
||||||
|
|
||||||
- name: Build and push jupyterhub-onbuild
|
- name: Build and push jupyterhub-onbuild
|
||||||
uses: docker/build-push-action@c84f38281176d4c9cdb1626ffafcd6b3911b5d94
|
uses: docker/build-push-action@c56af957549030174b10d6867f20e78cfd7debc5
|
||||||
with:
|
with:
|
||||||
build-args: |
|
build-args: |
|
||||||
BASE_IMAGE=${{ fromJson(steps.jupyterhubtags.outputs.tags)[0] }}
|
BASE_IMAGE=${{ fromJson(steps.jupyterhubtags.outputs.tags)[0] }}
|
||||||
@@ -191,7 +191,7 @@ jobs:
|
|||||||
branchRegex: ^\w[\w-.]*$
|
branchRegex: ^\w[\w-.]*$
|
||||||
|
|
||||||
- name: Build and push jupyterhub-demo
|
- name: Build and push jupyterhub-demo
|
||||||
uses: docker/build-push-action@c84f38281176d4c9cdb1626ffafcd6b3911b5d94
|
uses: docker/build-push-action@c56af957549030174b10d6867f20e78cfd7debc5
|
||||||
with:
|
with:
|
||||||
build-args: |
|
build-args: |
|
||||||
BASE_IMAGE=${{ fromJson(steps.onbuildtags.outputs.tags)[0] }}
|
BASE_IMAGE=${{ fromJson(steps.onbuildtags.outputs.tags)[0] }}
|
||||||
@@ -215,7 +215,7 @@ jobs:
|
|||||||
branchRegex: ^\w[\w-.]*$
|
branchRegex: ^\w[\w-.]*$
|
||||||
|
|
||||||
- name: Build and push jupyterhub/singleuser
|
- name: Build and push jupyterhub/singleuser
|
||||||
uses: docker/build-push-action@c84f38281176d4c9cdb1626ffafcd6b3911b5d94
|
uses: docker/build-push-action@c56af957549030174b10d6867f20e78cfd7debc5
|
||||||
with:
|
with:
|
||||||
build-args: |
|
build-args: |
|
||||||
JUPYTERHUB_VERSION=${{ github.ref_type == 'tag' && github.ref_name || format('git:{0}', github.sha) }}
|
JUPYTERHUB_VERSION=${{ github.ref_type == 'tag' && github.ref_name || format('git:{0}', github.sha) }}
|
||||||
|
@@ -8,19 +8,20 @@ log messages, what they mean and what are the most common causes that generated
|
|||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
Your log might display lines that seem cryptic
|
Your logs might be littered with lines that look scary
|
||||||
|
|
||||||
```
|
```
|
||||||
[W 2022-03-10 17:25:19.774 JupyterHub base:1349] Failing suspected API request to not-running server: /hub/user/<user-name>/api/metrics/v1
|
[W 2022-03-10 17:25:19.774 JupyterHub base:1349] Failing suspected API request to not-running server: /hub/user/<user-name>/api/metrics/v1
|
||||||
```
|
```
|
||||||
|
|
||||||
### Most likely cause
|
### Cause
|
||||||
|
|
||||||
The possible reason may be that the user's server has stopped running
|
This likely means that the user's server has stopped running but they
|
||||||
but they still have a browser tab open. For example, you might have 3 tabs open and you shut
|
still have a browser tab open. For example, you might have 3 tabs open and you shut
|
||||||
the server down via one.
|
the server down via one.
|
||||||
The other possible reason could be that you closed your laptop and the server was culled for inactivity, then reopened the laptop!
|
Another possible reason could be that you closed your laptop and the server was culled for inactivity, then reopened the laptop!
|
||||||
However, the client-side code (JupyterLab, Classic Notebook, etc) doesn't interpret the shut-down server and continues to make some API requests.
|
However, the client-side code (JupyterLab, Classic Notebook, etc) doesn't interpret the shut-down server and continues to make some API requests.
|
||||||
|
|
||||||
JupyterHub's architecture means that the proxy routes all requests that
|
JupyterHub's architecture means that the proxy routes all requests that
|
||||||
don't go to a running user server to the hub process itself. The hub
|
don't go to a running user server to the hub process itself. The hub
|
||||||
process then explicitly returns a failure response, so the client knows
|
process then explicitly returns a failure response, so the client knows
|
||||||
|
23
docs/source/contributing/community.md
Normal file
23
docs/source/contributing/community.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Community communication channels
|
||||||
|
|
||||||
|
We use different channels of communication for different purposes. Whichever one you use will depend on what kind of communication you want to engage in.
|
||||||
|
|
||||||
|
## Discourse (recommended)
|
||||||
|
|
||||||
|
We use [Discourse](https://discourse.jupyter.org) for online discussions and support questions. Everyone in the Jupyter community is welcome to bring ideas and questions there.
|
||||||
|
|
||||||
|
All our past and current discussions on Discourse are archived and searchable. This is why we recommend you first go to Discourse, so that discussions remain useful and accessible to the whole community.
|
||||||
|
|
||||||
|
## Gitter
|
||||||
|
|
||||||
|
We use [our Gitter channel](https://gitter.im/jupyterhub/jupyterhub) for online, real-time text chat; a place for more ephemeral discussions. When you're not on Discourse, you can stop here to have other discussions on the fly.
|
||||||
|
|
||||||
|
## Github Issues
|
||||||
|
|
||||||
|
Github issues are used for most long-form project discussions, bug reports and feature requests.
|
||||||
|
|
||||||
|
Issues related to a specific authenticator or spawner should be opened in the appropriate repository for the authenticator or spawner. If you are using a specific JupyterHub distribution (such as [Zero to JupyterHub on Kubernetes](http://github.com/jupyterhub/zero-to-jupyterhub-k8s) or [The Littlest JupyterHub](http://github.com/jupyterhub/the-littlest-jupyterhub/)), you should open issues directly in their repository.
|
||||||
|
|
||||||
|
If you cannot find a repository to open your issue in, do not worry! Open the issue in the [main JupyterHub repository](https://github.com/jupyterhub/jupyterhub/) and our community will help you figure it out.
|
||||||
|
|
||||||
|
**NOTE**: Our community is distributed across the world in various timezones, so please be patient if you do not get a response immediately!
|
@@ -1,30 +0,0 @@
|
|||||||
.. _contributing/community:
|
|
||||||
|
|
||||||
================================
|
|
||||||
Community communication channels
|
|
||||||
================================
|
|
||||||
|
|
||||||
We use `Discourse <https://discourse.jupyter.org>` for online discussion.
|
|
||||||
Everyone in the Jupyter community is welcome to bring ideas and questions there.
|
|
||||||
In addition, we use `Gitter <https://gitter.im>`_ for online, real-time text chat,
|
|
||||||
a place for more ephemeral discussions.
|
|
||||||
The primary Gitter channel for JupyterHub is `jupyterhub/jupyterhub <https://gitter.im/jupyterhub/jupyterhub>`_.
|
|
||||||
Gitter isn't archived or searchable, so we recommend going to discourse first
|
|
||||||
to make sure that discussions are most useful and accessible to the community.
|
|
||||||
Remember that our community is distributed across the world in various
|
|
||||||
timezones, so be patient if you do not get an answer immediately!
|
|
||||||
|
|
||||||
GitHub issues are used for most long-form project discussions, bug reports
|
|
||||||
and feature requests. Issues related to a specific authenticator or
|
|
||||||
spawner should be directed to the appropriate repository for the
|
|
||||||
authenticator or spawner. If you are using a specific JupyterHub
|
|
||||||
distribution (such as `Zero to JupyterHub on Kubernetes <http://github.com/jupyterhub/zero-to-jupyterhub-k8s>`_
|
|
||||||
or `The Littlest JupyterHub <http://github.com/jupyterhub/the-littlest-jupyterhub/>`_),
|
|
||||||
you should open issues directly in their repository. If you can not
|
|
||||||
find a repository to open your issue in, do not worry! Create it in the `main
|
|
||||||
JupyterHub repository <https://github.com/jupyterhub/jupyterhub/>`_ and our
|
|
||||||
community will help you figure it out.
|
|
||||||
|
|
||||||
A `mailing list <https://groups.google.com/forum/#!forum/jupyter>`_ for all
|
|
||||||
of Project Jupyter exists, along with one for `teaching with Jupyter
|
|
||||||
<https://groups.google.com/forum/#!forum/jupyter-education>`_.
|
|
@@ -4,19 +4,16 @@
|
|||||||
Testing JupyterHub and linting code
|
Testing JupyterHub and linting code
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
Unit test help validate that JupyterHub works the way we think it does,
|
Unit tests help confirm that JupyterHub works as intended, including after modifications are made. Additionally, they help in clarifying our expectations for our code.
|
||||||
and continues to do so when changes occur. They also help communicate
|
|
||||||
precisely what we expect our code to do.
|
|
||||||
|
|
||||||
JupyterHub uses `pytest <https://pytest.org>`_ for all our tests. You
|
JupyterHub uses `pytest <https://pytest.org>`_ for all the tests. You
|
||||||
can find them under ``jupyterhub/tests`` directory in the git repository.
|
can find them under the `jupyterhub/tests <https://github.com/jupyterhub/jupyterhub/tree/main/jupyterhub/tests>`_ directory in the git repository.
|
||||||
|
|
||||||
Running the tests
|
Running the tests
|
||||||
==================
|
==================
|
||||||
|
|
||||||
#. Make sure you have completed :ref:`contributing/setup`. You should be able
|
#. Make sure you have completed :ref:`contributing/setup`. Once completed, you should be able
|
||||||
to start ``jupyterhub`` from the commandline & access it from your
|
to run ``jupyterhub`` on your command line and access JupyterHub from your browser at http://localhost:8000. Being able to run and access `jupyterhub` should mean that the dev environment is properly set
|
||||||
web browser. This ensures that the dev environment is properly set
|
|
||||||
up for tests to run.
|
up for tests to run.
|
||||||
|
|
||||||
#. You can run all tests in JupyterHub
|
#. You can run all tests in JupyterHub
|
||||||
@@ -57,7 +54,7 @@ Running the tests
|
|||||||
|
|
||||||
pytest -v jupyterhub/tests/test_api.py::test_shutdown
|
pytest -v jupyterhub/tests/test_api.py::test_shutdown
|
||||||
|
|
||||||
See the `pytest usage documentation <https://pytest.readthedocs.io/en/latest/usage.html>`_ for more details.
|
For more information, refer to the `pytest usage documentation <https://pytest.readthedocs.io/en/latest/usage.html>`_.
|
||||||
|
|
||||||
Test organisation
|
Test organisation
|
||||||
=================
|
=================
|
||||||
@@ -98,8 +95,7 @@ And fixtures to add functionality or spawning behavior:
|
|||||||
- ``bad_spawn``: enables the BadSpawner (a spawner that fails immediately)
|
- ``bad_spawn``: enables the BadSpawner (a spawner that fails immediately)
|
||||||
- ``slow_bad_spawn``: enables the SlowBadSpawner (a spawner that fails after a short delay)
|
- ``slow_bad_spawn``: enables the SlowBadSpawner (a spawner that fails after a short delay)
|
||||||
|
|
||||||
See the `pytest fixtures documentation <https://pytest.readthedocs.io/en/latest/fixture.html>`_
|
For information on using the existing fixtures and creating new ones, refer to the `pytest fixtures documentation <https://pytest.readthedocs.io/en/latest/fixture.html>`_
|
||||||
for how to use the existing fixtures, and how to create new ones.
|
|
||||||
|
|
||||||
|
|
||||||
Troubleshooting Test Failures
|
Troubleshooting Test Failures
|
||||||
@@ -108,8 +104,7 @@ Troubleshooting Test Failures
|
|||||||
All the tests are failing
|
All the tests are failing
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
Make sure you have completed all the steps in :ref:`contributing/setup` successfully, and
|
Make sure you have completed all the steps in :ref:`contributing/setup` successfully, and are able to access JupyterHub from your browser at http://localhost:8000 after starting ``jupyterhub`` in your command line.
|
||||||
can launch ``jupyterhub`` from the terminal.
|
|
||||||
|
|
||||||
|
|
||||||
Code formatting and linting
|
Code formatting and linting
|
||||||
@@ -117,13 +112,13 @@ Code formatting and linting
|
|||||||
|
|
||||||
JupyterHub has adopted automatic code formatting and linting.
|
JupyterHub has adopted automatic code formatting and linting.
|
||||||
As long as your code is valid, the pre-commit hook should take care of how it should look.
|
As long as your code is valid, the pre-commit hook should take care of how it should look.
|
||||||
You can invoke the pre-commit hook by hand at any time with:
|
You can invoke the pre-commit hook manually at any time with:
|
||||||
|
|
||||||
.. code:: bash
|
.. code:: bash
|
||||||
|
|
||||||
pre-commit run
|
pre-commit run
|
||||||
|
|
||||||
which should run any autoformatting on your code and tell you about any errors it couldn't fix automatically.
|
This should run any auto formatting on your code and tell you about any errors it couldn't fix automatically.
|
||||||
You may also install `black integration <https://github.com/psf/black#editor-integration>`_
|
You may also install `black integration <https://github.com/psf/black#editor-integration>`_
|
||||||
into your text editor to format code automatically.
|
into your text editor to format code automatically.
|
||||||
|
|
||||||
|
@@ -2,31 +2,29 @@
|
|||||||
JupyterHub
|
JupyterHub
|
||||||
==========
|
==========
|
||||||
|
|
||||||
`JupyterHub`_ is the best way to serve `Jupyter notebook`_ for multiple users.
|
`JupyterHub`_ is the best way to serve `Jupyter notebook`_ for multiple users.
|
||||||
It can be used in a class of students, a corporate data science group or scientific
|
Because JupyterHub manages a separate Jupyter environment for each user,
|
||||||
|
it can be used in a class of students, a corporate data science group, or a scientific
|
||||||
research group. It is a multi-user **Hub** that spawns, manages, and proxies multiple
|
research group. It is a multi-user **Hub** that spawns, manages, and proxies multiple
|
||||||
instances of the single-user `Jupyter notebook`_ server.
|
instances of the single-user `Jupyter notebook`_ server.
|
||||||
|
|
||||||
To make life easier, JupyterHub has distributions. Be sure to
|
JupyterHub offers distributions for different use cases. Be sure to
|
||||||
take a look at them before continuing with the configuration of the broad
|
take a look at them before continuing with the configuration of the broad
|
||||||
original system of `JupyterHub`_. Today, you can find two main cases:
|
original system of `JupyterHub`_. As of now, you can find two main cases:
|
||||||
|
|
||||||
1. If you need a simple case for a small amount of users (0-100) and single server
|
1. `The Littlest JupyterHub <https://github.com/jupyterhub/the-littlest-jupyterhub>`__ distribution is suitable if you need a small number of users (1-100) and a single server with a simple environment.
|
||||||
take a look at
|
2. `Zero to JupyterHub with Kubernetes <https://github.com/jupyterhub/zero-to-jupyterhub-k8s>`__ allows you to deploy dynamic servers on the cloud if you need even more users.
|
||||||
`The Littlest JupyterHub <https://github.com/jupyterhub/the-littlest-jupyterhub>`__ distribution.
|
|
||||||
2. If you need to allow for even more users, a dynamic amount of servers can be used on a cloud,
|
|
||||||
take a look at the `Zero to JupyterHub with Kubernetes <https://github.com/jupyterhub/zero-to-jupyterhub-k8s>`__ .
|
|
||||||
|
|
||||||
|
|
||||||
Four subsystems make up JupyterHub:
|
Four subsystems make up JupyterHub:
|
||||||
|
|
||||||
* a **Hub** (tornado process) that is the heart of JupyterHub
|
* a **Hub** (tornado process) that is the heart of JupyterHub
|
||||||
* a **configurable http proxy** (node-http-proxy) that receives the requests from the client's browser
|
* a **Configurable HTTP Proxy** (node-http-proxy) that receives the requests from the client's browser
|
||||||
* multiple **single-user Jupyter notebook servers** (Python/IPython/tornado) that are monitored by Spawners
|
* multiple **Single-User Jupyter Notebook Servers** (Python/IPython/tornado) that are monitored by Spawners
|
||||||
* an **authentication class** that manages how users can access the system
|
* an **Authentication Class** that manages how users can access the system
|
||||||
|
|
||||||
|
|
||||||
Besides these central pieces, you can add optional configurations through a `config.py` file and manage users kernels on an admin panel. A simplification of the whole system can be seen in the figure below:
|
Besides these central pieces, you can add optional configurations through a `config.py` file and manage users' environments through an admin panel. A simplification of the whole system can be seen in the figure below:
|
||||||
|
|
||||||
.. image:: images/jhub-fluxogram.jpeg
|
.. image:: images/jhub-fluxogram.jpeg
|
||||||
:alt: JupyterHub subsystems
|
:alt: JupyterHub subsystems
|
||||||
@@ -56,17 +54,17 @@ Contents
|
|||||||
Distributions
|
Distributions
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
A JupyterHub **distribution** is tailored towards a particular set of
|
Each JupyterHub **distribution** is tailored toward a particular set of
|
||||||
use cases. These are generally easier to set up than setting up
|
use cases. These are generally easier to set up than setting up
|
||||||
JupyterHub from scratch, assuming they fit your use case.
|
JupyterHub from scratch, assuming they fit your use case.
|
||||||
|
|
||||||
The two popular ones are:
|
The two popular ones are:
|
||||||
|
|
||||||
* `Zero to JupyterHub on Kubernetes <http://z2jh.jupyter.org>`_, for
|
|
||||||
running JupyterHub on top of `Kubernetes <https://k8s.io>`_. This
|
|
||||||
can scale to large number of machines & users.
|
|
||||||
* `The Littlest JupyterHub <http://tljh.jupyter.org>`_, for an easy
|
* `The Littlest JupyterHub <http://tljh.jupyter.org>`_, for an easy
|
||||||
to set up & run JupyterHub supporting 1-100 users on a single machine.
|
to set up & run JupyterHub supporting 1-100 users on a single machine.
|
||||||
|
* `Zero to JupyterHub on Kubernetes <http://z2jh.jupyter.org>`_, for
|
||||||
|
running JupyterHub on top of `Kubernetes <https://k8s.io>`_. This
|
||||||
|
can scale to a large number of machines & users.
|
||||||
|
|
||||||
Installation Guide
|
Installation Guide
|
||||||
------------------
|
------------------
|
||||||
@@ -119,8 +117,8 @@ RBAC Reference
|
|||||||
Contributing
|
Contributing
|
||||||
------------
|
------------
|
||||||
|
|
||||||
We want you to contribute to JupyterHub in ways that are most exciting
|
We welcome you to contribute to JupyterHub in ways that are most exciting
|
||||||
& useful to you. We value documentation, testing, bug reporting & code equally,
|
& useful to you. We value documentation, testing, bug reporting & code equally
|
||||||
and are glad to have your contributions in whatever form you wish :)
|
and are glad to have your contributions in whatever form you wish :)
|
||||||
|
|
||||||
Our `Code of Conduct <https://github.com/jupyter/governance/blob/HEAD/conduct/code_of_conduct.md>`_
|
Our `Code of Conduct <https://github.com/jupyter/governance/blob/HEAD/conduct/code_of_conduct.md>`_
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
# Technical Implementation
|
# Technical Implementation
|
||||||
|
|
||||||
Roles are stored in the database, where they are associated with users, services, etc., and can be added or modified as explained in {ref}`define-role-target` section. Users, services, groups, and tokens can gain, change, and lose roles. This is currently achieved via `jupyterhub_config.py` (see {ref}`define-role-target`) and will be made available via API in future. The latter will allow for changing a token's role, and thereby its permissions, without the need to issue a new token.
|
[Roles](roles) are stored in the database, where they are associated with users, services, and groups. Roles can be added or modified as explained in the {ref}`define-role-target` section. Users, services, groups, and tokens can gain, change, and lose roles. This is currently achieved via `jupyterhub_config.py` (see {ref}`define-role-target`) and will be made available via API in the future. The latter will allow for changing a user's role, and thereby its permissions, without the need to restart JupyterHub.
|
||||||
|
|
||||||
Roles and scopes utilities can be found in `roles.py` and `scopes.py` modules. Scope variables take on five different formats which is reflected throughout the utilities via specific nomenclature:
|
Roles and scopes utilities can be found in `roles.py` and `scopes.py` modules. Scope variables take on five different formats that are reflected throughout the utilities via specific nomenclature:
|
||||||
|
|
||||||
```{admonition} **Scope variable nomenclature**
|
```{admonition} **Scope variable nomenclature**
|
||||||
:class: tip
|
:class: tip
|
||||||
@@ -11,22 +11,22 @@ Roles and scopes utilities can be found in `roles.py` and `scopes.py` modules. S
|
|||||||
- _expanded scopes_ \
|
- _expanded scopes_ \
|
||||||
Set of fully expanded scopes without abbreviations (i.e., resolved metascopes, filters, and subscopes). E.g., `{"users:activity!user=charlie", "read:users:activity!user=charlie"}`.
|
Set of fully expanded scopes without abbreviations (i.e., resolved metascopes, filters, and subscopes). E.g., `{"users:activity!user=charlie", "read:users:activity!user=charlie"}`.
|
||||||
- _parsed scopes_ \
|
- _parsed scopes_ \
|
||||||
Dictionary represenation of expanded scopes. E.g., `{"users:activity": {"user": ["charlie"]}, "read:users:activity": {"users": ["charlie"]}}`.
|
Dictionary representation of expanded scopes. E.g., `{"users:activity": {"user": ["charlie"]}, "read:users:activity": {"users": ["charlie"]}}`.
|
||||||
- _intersection_ \
|
- _intersection_ \
|
||||||
Set of expanded scopes as intersection of 2 expanded scope sets.
|
Set of expanded scopes as intersection of 2 expanded scope sets.
|
||||||
- _identify scopes_ \
|
- _identify scopes_ \
|
||||||
Set of expanded scopes needed for identify (whoami) endpoints.
|
Set of expanded scopes needed for identity (whoami) endpoints.
|
||||||
```
|
```
|
||||||
|
|
||||||
(resolving-roles-scopes-target)=
|
(resolving-roles-scopes-target)=
|
||||||
|
|
||||||
## Resolving roles and scopes
|
## Resolving roles and scopes
|
||||||
|
|
||||||
**Resolving roles** refers to determining which roles a user, service, or group has, extracting the list of scopes from each role and combining them into a single set of scopes.
|
**Resolving roles** involves determining which roles a user, service, or group has, extracting the list of scopes from each role and combining them into a single set of scopes.
|
||||||
|
|
||||||
**Resolving scopes** involves expanding scopes into all their possible subscopes (_expanded scopes_), parsing them into format used for access evaluation (_parsed scopes_) and, if applicable, comparing two sets of scopes (_intersection_). All procedures take into account the scope hierarchy, {ref}`vertical <vertical-filtering-target>` and {ref}`horizontal filtering <horizontal-filtering-target>`, limiting or elevated permissions (`read:<resource>` or `admin:<resource>`, respectively), and metascopes.
|
**Resolving scopes** involves expanding scopes into all their possible subscopes (_expanded scopes_), parsing them into the format used for access evaluation (_parsed scopes_) and, if applicable, comparing two sets of scopes (_intersection_). All procedures take into account the scope hierarchy, {ref}`vertical <vertical-filtering-target>` and {ref}`horizontal filtering <horizontal-filtering-target>`, limiting or elevated permissions (`read:<resource>` or `admin:<resource>`, respectively), and metascopes.
|
||||||
|
|
||||||
Roles and scopes are resolved on several occasions, for example when requesting an API token with specific scopes or making an API request. The following sections provide more details.
|
Roles and scopes are resolved on several occasions, for example when requesting an API token with specific scopes or when making an API request. The following sections provide more details.
|
||||||
|
|
||||||
(requesting-api-token-target)=
|
(requesting-api-token-target)=
|
||||||
|
|
||||||
@@ -43,25 +43,24 @@ Prior to 3.0, tokens stored _roles_,
|
|||||||
which meant their scopes were resolved on each request.
|
which meant their scopes were resolved on each request.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
API tokens grant access to JupyterHub's APIs. The RBAC framework allows for requesting tokens with specific permissions.
|
API tokens grant access to JupyterHub's APIs. The Role Based Access Control (RBAC) framework allows for the requesting of tokens with specific permissions.
|
||||||
|
|
||||||
RBAC is involved in several stages of the OAuth token flow.
|
RBAC is involved in several stages of the OAuth token flow.
|
||||||
|
|
||||||
When requesting a token via the tokens API (`/users/:name/tokens`), or the token page (`/hub/token`),
|
When requesting a token via the tokens API (`/users/:name/tokens`), or the token page (`/hub/token`),
|
||||||
if no scopes are requested, the token is issued with the permissions stored on the default `token` role
|
if no scopes are requested, the token is issued with the permissions stored on the default `token` role
|
||||||
(providing the requester is allowed to create the token).
|
(provided the requester is allowed to create the token).
|
||||||
|
|
||||||
OAuth tokens are also requested via OAuth flow
|
OAuth tokens are also requested via OAuth flow
|
||||||
|
|
||||||
If the token is requested with any scopes, the permissions of requesting entity are checked against the requested permissions to ensure the token would not grant its owner additional privileges.
|
If the token is requested with any scopes, the permissions of requesting entity are checked against the requested permissions to ensure the token would not grant its owner additional privileges.
|
||||||
|
|
||||||
If, due to modifications of permissions of the token or token owner,
|
If a token has any scopes that its owner does not possess
|
||||||
at API request time a token has any scopes that its owner does not,
|
at the time of making the API request, those scopes are removed.
|
||||||
those scopes are removed.
|
|
||||||
The API request is resolved without additional errors using the scope _intersection_;
|
The API request is resolved without additional errors using the scope _intersection_;
|
||||||
the Hub logs a warning in this case (see {ref}`Figure 2 <api-request-chart>`).
|
the Hub logs a warning in this case (see {ref}`Figure 2 <api-request-chart>`).
|
||||||
|
|
||||||
Resolving a token's scope (yellow box in {ref}`Figure 1 <token-request-chart>`) corresponds to resolving all the token's owner roles (including the roles associated with their groups) and the token's own scopes into a set of scopes. The two sets are compared (Resolve the scopes box in orange in {ref}`Figure 1 <token-request-chart>`), taking into account the scope hierarchy.
|
Resolving a token's scope (yellow box in {ref}`Figure 1 <token-request-chart>`) corresponds to resolving all the roles of the token's owner (including the roles associated with their groups) and the token's own scopes into a set of scopes. The two sets are compared (Resolve the scopes box in orange in {ref}`Figure 1 <token-request-chart>`), taking into account the scope hierarchy.
|
||||||
If the token's scopes are a subset of the token owner's scopes, the token is issued with the requested scopes; if not, JupyterHub will raise an error.
|
If the token's scopes are a subset of the token owner's scopes, the token is issued with the requested scopes; if not, JupyterHub will raise an error.
|
||||||
|
|
||||||
{ref}`Figure 1 <token-request-chart>` below illustrates the steps involved. The orange rectangles highlight where in the process the roles and scopes are resolved.
|
{ref}`Figure 1 <token-request-chart>` below illustrates the steps involved. The orange rectangles highlight where in the process the roles and scopes are resolved.
|
||||||
@@ -75,10 +74,10 @@ Figure 1. Resolving roles and scopes during API token request
|
|||||||
|
|
||||||
### Making an API request
|
### Making an API request
|
||||||
|
|
||||||
With the RBAC framework, each authenticated JupyterHub API request is guarded by a scope decorator that specifies which scopes are required to gain the access to the API.
|
With the RBAC framework, each authenticated JupyterHub API request is guarded by a scope decorator that specifies which scopes are required in order to gain the access to the API.
|
||||||
|
|
||||||
When an API request is performed, the requesting API token's scopes are again intersected with its owner's (yellow box in {ref}`Figure 2 <api-request-chart>`) to ensure the token does not grant more permissions than its owner has at the request time (e.g., due to changing/losing roles).
|
When an API request is made, the requesting API token's scopes are again intersected with its owner's (yellow box in {ref}`Figure 2 <api-request-chart>`) to ensure that the token does not grant more permissions than its owner has at the request time (e.g., due to changing/losing roles).
|
||||||
If the owner's roles do not include some scopes of the token's scopes, only the _intersection_ of the token's and owner's scopes will be used. For example, using a token with scope `users` whose owner's role scope is `read:users:name` will result in only the `read:users:name` scope being passed on. In the case of no _intersection_, an empty set of scopes will be used.
|
If the owner's roles do not include some scopes of the token, only the _intersection_ of the token's and owner's scopes will be used. For example, using a token with scope `users` whose owner's role scope is `read:users:name` will result in only the `read:users:name` scope being passed on. In the case of no _intersection_, an empty set of scopes will be used.
|
||||||
|
|
||||||
The passed scopes are compared to the scopes required to access the API as follows:
|
The passed scopes are compared to the scopes required to access the API as follows:
|
||||||
|
|
||||||
@@ -86,7 +85,7 @@ The passed scopes are compared to the scopes required to access the API as follo
|
|||||||
|
|
||||||
- if that is not the case, another check is utilized to determine if subscopes of the required API scopes can be found in the passed scope set:
|
- if that is not the case, another check is utilized to determine if subscopes of the required API scopes can be found in the passed scope set:
|
||||||
|
|
||||||
- if found, the RBAC framework employs the {ref}`filtering <vertical-filtering-target>` procedures to refine the API response to access only resource attributes corresponding to the passed scopes. For example, providing a scope `read:users:activity!group=class-C` for the _GET /users_ API will return a list of user models from group `class-C` containing only the `last_activity` attribute for each user model
|
- if found, the RBAC framework employs the {ref}`filtering <vertical-filtering-target>` procedures to refine the API response to access only resource attributes corresponding to the passed scopes. For example, providing a scope `read:users:activity!group=class-C` for the `GET /users` API will return a list of user models from group `class-C` containing only the `last_activity` attribute for each user model
|
||||||
|
|
||||||
- if not found, the access to API is denied
|
- if not found, the access to API is denied
|
||||||
|
|
||||||
|
@@ -5,15 +5,15 @@ deployment with the following assumptions:
|
|||||||
|
|
||||||
- Running JupyterHub on a single cloud server
|
- Running JupyterHub on a single cloud server
|
||||||
- Using SSL on the standard HTTPS port 443
|
- Using SSL on the standard HTTPS port 443
|
||||||
- Using GitHub OAuth (using oauthenticator) for login
|
- Using GitHub OAuth (using [OAuthenticator](https://oauthenticator.readthedocs.io/en/latest)) for login
|
||||||
- Using the default spawner (to configure other spawners, uncomment and edit
|
- Using the default spawner (to configure other spawners, uncomment and edit
|
||||||
`spawner_class` as well as follow the instructions for your desired spawner)
|
`spawner_class` as well as follow the instructions for your desired spawner)
|
||||||
- Users exist locally on the server
|
- Users exist locally on the server
|
||||||
- Users' notebooks to be served from `~/assignments` to allow users to browse
|
- Users' notebooks to be served from `~/assignments` to allow users to browse
|
||||||
for notebooks within other users' home directories
|
for notebooks within other users' home directories
|
||||||
- You want the landing page for each user to be a `Welcome.ipynb` notebook in
|
- You want the landing page for each user to be a `Welcome.ipynb` notebook in
|
||||||
their assignments directory.
|
their assignments directory
|
||||||
- All runtime files are put into `/srv/jupyterhub` and log files in `/var/log`.
|
- All runtime files are put into `/srv/jupyterhub` and log files in `/var/log`
|
||||||
|
|
||||||
The `jupyterhub_config.py` file would have these settings:
|
The `jupyterhub_config.py` file would have these settings:
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ c.Spawner.args = ['--NotebookApp.default_url=/notebooks/Welcome.ipynb']
|
|||||||
```
|
```
|
||||||
|
|
||||||
Using the GitHub Authenticator requires a few additional
|
Using the GitHub Authenticator requires a few additional
|
||||||
environment variable to be set prior to launching JupyterHub:
|
environment variables to be set prior to launching JupyterHub:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export GITHUB_CLIENT_ID=github_id
|
export GITHUB_CLIENT_ID=github_id
|
||||||
@@ -79,3 +79,5 @@ export CONFIGPROXY_AUTH_TOKEN=super-secret
|
|||||||
# append log output to log file /var/log/jupyterhub.log
|
# append log output to log file /var/log/jupyterhub.log
|
||||||
jupyterhub -f /etc/jupyterhub/jupyterhub_config.py &>> /var/log/jupyterhub.log
|
jupyterhub -f /etc/jupyterhub/jupyterhub_config.py &>> /var/log/jupyterhub.log
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Visit the [Github OAuthenticator reference](https://oauthenticator.readthedocs.io/en/latest/api/gen/oauthenticator.github.html) to see the full list of options for configuring Github OAuth with JupyterHub.
|
||||||
|
@@ -4,23 +4,31 @@ To deploy JupyterHub means you are providing Jupyter notebook environments for
|
|||||||
multiple users. Often, this includes a desire to configure the user
|
multiple users. Often, this includes a desire to configure the user
|
||||||
environment in a custom way.
|
environment in a custom way.
|
||||||
|
|
||||||
Since the `jupyterhub-singleuser` server extends the standard Jupyter notebook server, most configuration and documentation that applies to Jupyter Notebook applies to the single-user environments.
|
Since the `jupyterhub-singleuser` server extends the standard Jupyter notebook
|
||||||
Configuration of user environments typically does not occur through JupyterHub itself, but rather through system-wide Jupyter's configuration, which is inherited by `jupyterhub-singleuser`.
|
server, most configuration and documentation that applies to Jupyter Notebook
|
||||||
|
applies to the single-user environments. Configuration of user environments
|
||||||
|
typically does not occur through JupyterHub itself, but rather through the system-wide
|
||||||
|
configuration of Jupyter, which is inherited by `jupyterhub-singleuser`.
|
||||||
|
|
||||||
**Tip:** When searching for configuration tips for JupyterHub user environments, you might want to remove JupyterHub from your search because there are a lot more people out there configuring Jupyter than JupyterHub and the configuration is the same.
|
**Tip:** When searching for configuration tips for JupyterHub user environments, you might want to remove JupyterHub from your search because there are a lot more people out there configuring Jupyter than JupyterHub and the configuration is the same.
|
||||||
|
|
||||||
This section will focus on user environments, which includes the following:
|
This section will focus on user environments, which includes the following:
|
||||||
|
|
||||||
- Installing packages
|
- [Installing packages](#installing-packages)
|
||||||
- Configuring Jupyter and IPython
|
- [Configuring Jupyter and IPython](#configuring-jupyter-and-ipython)
|
||||||
- Installing kernelspecs
|
- [Installing kernelspecs](#installing-kernelspecs)
|
||||||
- Using containers vs. multi-user hosts
|
- [Using containers vs. multi-user hosts](#multi-user-hosts-vs-containers)
|
||||||
|
|
||||||
## Installing packages
|
## Installing packages
|
||||||
|
|
||||||
To make packages available to users, you will typically install packages system-wide or in a shared environment.
|
To make packages available to users, you will typically install packages system-wide or in a shared environment.
|
||||||
|
|
||||||
This installation location should always be in the same environment where `jupyterhub-singleuser` itself is installed, and must be _readable and executable_ by your users. If you want users to be able to install additional packages, it must also be _writable_ by your users.
|
|
||||||
|
This installation location should always be in the same environment where
|
||||||
|
`jupyterhub-singleuser` itself is installed in, and must be _readable and
|
||||||
|
executable_ by your users. If you want your users to be able to install additional
|
||||||
|
packages, the installation location must also be _writable_ by your users.
|
||||||
|
|
||||||
|
|
||||||
If you are using a standard Python installation on your system, use the following command:
|
If you are using a standard Python installation on your system, use the following command:
|
||||||
|
|
||||||
@@ -84,7 +92,11 @@ c.MappingKernelManager.cull_interval = 2 * 60
|
|||||||
You may have multiple Jupyter kernels installed and want to make sure that they are available to all of your users. This means installing kernelspecs either system-wide (e.g. in /usr/local/) or in the `sys.prefix` of JupyterHub
|
You may have multiple Jupyter kernels installed and want to make sure that they are available to all of your users. This means installing kernelspecs either system-wide (e.g. in /usr/local/) or in the `sys.prefix` of JupyterHub
|
||||||
itself.
|
itself.
|
||||||
|
|
||||||
Jupyter kernelspec installation is system wide by default, but some kernels may default to installing kernelspecs in your home directory. These will need to be moved system-wide to ensure that they are accessible.
|
|
||||||
|
Jupyter kernelspec installation is system-wide by default, but some kernels
|
||||||
|
may default to installing kernelspecs in your home directory. These will need
|
||||||
|
to be moved system-wide to ensure that they are accessible.
|
||||||
|
|
||||||
|
|
||||||
To see where your kernelspecs are, you can use the following command:
|
To see where your kernelspecs are, you can use the following command:
|
||||||
|
|
||||||
@@ -115,19 +127,22 @@ depending on what Spawner you are using.
|
|||||||
The first category is a **shared system (multi-user host)** where
|
The first category is a **shared system (multi-user host)** where
|
||||||
each user has a JupyterHub account, a home directory as well as being
|
each user has a JupyterHub account, a home directory as well as being
|
||||||
a real system user. In this example, shared configuration and installation
|
a real system user. In this example, shared configuration and installation
|
||||||
must be in a 'system-wide' location, such as `/etc/` or `/usr/local`
|
must be in a 'system-wide' location, such as `/etc/`, or `/usr/local`
|
||||||
or a custom prefix such as `/opt/conda`.
|
or a custom prefix such as `/opt/conda`.
|
||||||
|
|
||||||
When JupyterHub uses **container-based** Spawners (e.g. KubeSpawner or
|
When JupyterHub uses **container-based** Spawners (e.g. KubeSpawner or
|
||||||
DockerSpawner), the 'system-wide' environment is really the container image used for users.
|
DockerSpawner), the 'system-wide' environment is really the container image used for users.
|
||||||
|
|
||||||
|
|
||||||
In both cases, you want to _avoid putting configuration in user home
|
In both cases, you want to _avoid putting configuration in user home
|
||||||
directories_ because users can change those configuration settings. Also, home directories typically persist once they are created, thereby making it difficult for admins to update later.
|
directories_ because users can change those configuration settings. Also, home directories typically persist once they are created, thereby making it difficult for admins to update later.
|
||||||
|
|
||||||
## Named servers
|
## Named servers
|
||||||
|
|
||||||
|
|
||||||
By default, in a JupyterHub deployment, each user has one server only.
|
By default, in a JupyterHub deployment, each user has one server only.
|
||||||
|
|
||||||
|
|
||||||
JupyterHub can, however, have multiple servers per user.
|
JupyterHub can, however, have multiple servers per user.
|
||||||
This is mostly useful in deployments where users can configure the environment in which their server will start (e.g. resource requests on an HPC cluster), so that a given user can have multiple configurations running at the same time, without having to stop and restart their own server.
|
This is mostly useful in deployments where users can configure the environment in which their server will start (e.g. resource requests on an HPC cluster), so that a given user can have multiple configurations running at the same time, without having to stop and restart their own server.
|
||||||
|
|
||||||
@@ -146,7 +161,10 @@ as well as the admin page:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
Named servers can be accessed, created, started, stopped, and deleted from these pages. Activity tracking is now per-server as well.
|
|
||||||
|
Named servers can be accessed, created, started, stopped, and deleted
|
||||||
|
from these pages. Activity tracking is now per server as well.
|
||||||
|
|
||||||
|
|
||||||
To limit the number of **named server** per user by setting a constant value, use this:
|
To limit the number of **named server** per user by setting a constant value, use this:
|
||||||
|
|
||||||
@@ -172,9 +190,12 @@ If `named_server_limit_per_user` is set to `0`, no limit is enforced.
|
|||||||
|
|
||||||
(classic-notebook-ui)=
|
(classic-notebook-ui)=
|
||||||
|
|
||||||
## Switching back to classic notebook
|
## Switching back to the classic notebook
|
||||||
|
|
||||||
|
|
||||||
|
By default, the single-user server launches JupyterLab,
|
||||||
|
which is based on [Jupyter Server][].
|
||||||
|
|
||||||
By default, the single-user server launches JupyterLab, which is based on [Jupyter Server][].
|
|
||||||
This is the default server when running JupyterHub ≥ 2.0.
|
This is the default server when running JupyterHub ≥ 2.0.
|
||||||
To switch to using the legacy Jupyter Notebook server, you can set the `JUPYTERHUB_SINGLEUSER_APP` environment variable
|
To switch to using the legacy Jupyter Notebook server, you can set the `JUPYTERHUB_SINGLEUSER_APP` environment variable
|
||||||
(in the single-user environment) to:
|
(in the single-user environment) to:
|
||||||
@@ -187,8 +208,13 @@ export JUPYTERHUB_SINGLEUSER_APP='notebook.notebookapp.NotebookApp'
|
|||||||
[jupyter notebook]: https://jupyter-notebook.readthedocs.io
|
[jupyter notebook]: https://jupyter-notebook.readthedocs.io
|
||||||
|
|
||||||
:::{versionchanged} 2.0
|
:::{versionchanged} 2.0
|
||||||
JupyterLab is now the default singleuser UI, if available,
|
|
||||||
which is based on the [Jupyter Server][], no longer the legacy [Jupyter Notebook][] server.JupyterHub prior to 2.0 launched the legacy notebook server (`jupyter notebook`),and Jupyter server could be selected by specifying the following:
|
JupyterLab is now the default single-user UI, if available,
|
||||||
|
which is based on the [Jupyter Server][],
|
||||||
|
no longer the legacy [Jupyter Notebook][] server.
|
||||||
|
JupyterHub prior to 2.0 launched the legacy notebook server (`jupyter notebook`),
|
||||||
|
and the Jupyter server could be selected by specifying the following:
|
||||||
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# jupyterhub_config.py
|
# jupyterhub_config.py
|
||||||
|
@@ -267,8 +267,8 @@ Spawners mainly do one thing: launch a command in an environment.
|
|||||||
|
|
||||||
The command-line is constructed from user configuration:
|
The command-line is constructed from user configuration:
|
||||||
|
|
||||||
- Spawner.cmd (default: `['jupterhub-singleuser']`)
|
- Spawner.cmd (default: `['jupyterhub-singleuser']`)
|
||||||
- Spawner.args (cli args to pass to the cmd, default: empty)
|
- Spawner.args (CLI args to pass to the cmd, default: empty)
|
||||||
|
|
||||||
where the configuration:
|
where the configuration:
|
||||||
|
|
||||||
@@ -319,12 +319,12 @@ Optional environment variables, depending on configuration:
|
|||||||
- JUPYTERHUB_ROOT_DIR - the root directory of the server (notebook directory), when Spawner.notebook_dir is defined (new in 2.0)
|
- JUPYTERHUB_ROOT_DIR - the root directory of the server (notebook directory), when Spawner.notebook_dir is defined (new in 2.0)
|
||||||
- JUPYTERHUB_DEFAULT_URL - the default URL for the server (for redirects from /user/:name/),
|
- JUPYTERHUB_DEFAULT_URL - the default URL for the server (for redirects from /user/:name/),
|
||||||
if Spawner.default_url is defined
|
if Spawner.default_url is defined
|
||||||
(new in 2.0, previously passed via cli)
|
(new in 2.0, previously passed via CLI)
|
||||||
- JUPYTERHUB_DEBUG=1 - generic debug flag, sets maximum log level when Spawner.debug is True
|
- JUPYTERHUB_DEBUG=1 - generic debug flag, sets maximum log level when Spawner.debug is True
|
||||||
(new in 2.0, previously passed via cli)
|
(new in 2.0, previously passed via CLI)
|
||||||
- JUPYTERHUB_DISABLE_USER_CONFIG=1 - disable loading user config,
|
- JUPYTERHUB_DISABLE_USER_CONFIG=1 - disable loading user config,
|
||||||
sets maximum log level when Spawner.debug is True (new in 2.0,
|
sets maximum log level when Spawner.debug is True (new in 2.0,
|
||||||
previously passed via cli)
|
previously passed via CLI)
|
||||||
|
|
||||||
- JUPYTERHUB*[MEM|CPU]*[LIMIT_GUARANTEE] - the values of cpu and memory limits and guarantees.
|
- JUPYTERHUB*[MEM|CPU]*[LIMIT_GUARANTEE] - the values of cpu and memory limits and guarantees.
|
||||||
These are not expected to be enforced by the process,
|
These are not expected to be enforced by the process,
|
||||||
|
@@ -5,7 +5,7 @@ The **Security Overview** section helps you learn about:
|
|||||||
- the design of JupyterHub with respect to web security
|
- the design of JupyterHub with respect to web security
|
||||||
- the semi-trusted user
|
- the semi-trusted user
|
||||||
- the available mitigations to protect untrusted users from each other
|
- the available mitigations to protect untrusted users from each other
|
||||||
- the value of periodic security audits.
|
- the value of periodic security audits
|
||||||
|
|
||||||
This overview also helps you obtain a deeper understanding of how JupyterHub
|
This overview also helps you obtain a deeper understanding of how JupyterHub
|
||||||
works.
|
works.
|
||||||
@@ -32,7 +32,7 @@ servers) as a single website (i.e. single domain).
|
|||||||
|
|
||||||
To protect users from each other, a user must **never** be able to write arbitrary
|
To protect users from each other, a user must **never** be able to write arbitrary
|
||||||
HTML and serve it to another user on the Hub's domain. JupyterHub's
|
HTML and serve it to another user on the Hub's domain. JupyterHub's
|
||||||
authentication setup prevents a user writing arbitrary HTML and serving it to
|
authentication setup prevents a user from writing arbitrary HTML and serving it to
|
||||||
another user because only the owner of a given single-user notebook server is
|
another user because only the owner of a given single-user notebook server is
|
||||||
allowed to view user-authored pages served by the given single-user notebook
|
allowed to view user-authored pages served by the given single-user notebook
|
||||||
server.
|
server.
|
||||||
@@ -101,8 +101,8 @@ pose additional risk to the web application's security.
|
|||||||
|
|
||||||
### Encrypt internal connections with SSL/TLS
|
### Encrypt internal connections with SSL/TLS
|
||||||
|
|
||||||
By default, all communication on the server, between the proxy, hub, and single
|
By default, all communications on the server, between the proxy, hub, and single
|
||||||
-user notebooks is performed unencrypted. Setting the `internal_ssl` flag in
|
-user notebooks are performed unencrypted. Setting the `internal_ssl` flag in
|
||||||
`jupyterhub_config.py` secures the aforementioned routes. Turning this
|
`jupyterhub_config.py` secures the aforementioned routes. Turning this
|
||||||
feature on does require that the enabled `Spawner` can use the certificates
|
feature on does require that the enabled `Spawner` can use the certificates
|
||||||
generated by the `Hub` (the default `LocalProcessSpawner` can, for instance).
|
generated by the `Hub` (the default `LocalProcessSpawner` can, for instance).
|
||||||
@@ -118,7 +118,7 @@ extend to securing the `tcp` sockets as well.
|
|||||||
|
|
||||||
## Security audits
|
## Security audits
|
||||||
|
|
||||||
We recommend that you do periodic reviews of your deployment's security. It's
|
We recommend that you do periodic reviews of your deployment's security. It is
|
||||||
good practice to keep JupyterHub, configurable-http-proxy, and nodejs
|
good practice to keep JupyterHub, configurable-http-proxy, and nodejs
|
||||||
versions up to date.
|
versions up to date.
|
||||||
|
|
||||||
@@ -129,7 +129,7 @@ A handy website for testing your deployment is
|
|||||||
|
|
||||||
## Vulnerability reporting
|
## Vulnerability reporting
|
||||||
|
|
||||||
If you believe you’ve found a security vulnerability in JupyterHub, or any
|
If you believe you have found a security vulnerability in JupyterHub, or any
|
||||||
Jupyter project, please report it to
|
Jupyter project, please report it to
|
||||||
[security@ipython.org](mailto:security@ipython.org). If you prefer to encrypt
|
[security@ipython.org](mailto:security@ipython.org). If you prefer to encrypt
|
||||||
your security reports, you can use [this PGP public
|
your security reports, you can use [this PGP public
|
||||||
|
@@ -1,35 +1,9 @@
|
|||||||
# Troubleshooting
|
# Troubleshooting
|
||||||
|
|
||||||
When troubleshooting, you may see unexpected behaviors or receive an error
|
When troubleshooting, you may see unexpected behaviors or receive an error
|
||||||
message. This section provide links for identifying the cause of the
|
message. This section provides links for identifying the cause of the
|
||||||
problem and how to resolve it.
|
problem and how to resolve it.
|
||||||
|
|
||||||
[_Behavior_](#behavior)
|
|
||||||
|
|
||||||
- JupyterHub proxy fails to start
|
|
||||||
- sudospawner fails to run
|
|
||||||
- What is the default behavior when none of the lists (admin, allowed,
|
|
||||||
allowed groups) are set?
|
|
||||||
- JupyterHub Docker container not accessible at localhost
|
|
||||||
|
|
||||||
[_Errors_](#errors)
|
|
||||||
|
|
||||||
- 500 error after spawning my single-user server
|
|
||||||
|
|
||||||
[_How do I...?_](#how-do-i)
|
|
||||||
|
|
||||||
- Use a chained SSL certificate
|
|
||||||
- Install JupyterHub without a network connection
|
|
||||||
- I want access to the whole filesystem, but still default users to their home directory
|
|
||||||
- How do I increase the number of pySpark executors on YARN?
|
|
||||||
- How do I use JupyterLab's prerelease version with JupyterHub?
|
|
||||||
- How do I set up JupyterHub for a workshop (when users are not known ahead of time)?
|
|
||||||
- How do I set up rotating daily logs?
|
|
||||||
- Toree integration with HDFS rack awareness script
|
|
||||||
- Where do I find Docker images and Dockerfiles related to JupyterHub?
|
|
||||||
|
|
||||||
[_Troubleshooting commands_](#troubleshooting-commands)
|
|
||||||
|
|
||||||
## Behavior
|
## Behavior
|
||||||
|
|
||||||
### JupyterHub proxy fails to start
|
### JupyterHub proxy fails to start
|
||||||
@@ -40,9 +14,9 @@ If you have tried to start the JupyterHub proxy and it fails to start:
|
|||||||
`c.JupyterHub.ip = '*'`; if it is, try `c.JupyterHub.ip = ''`
|
`c.JupyterHub.ip = '*'`; if it is, try `c.JupyterHub.ip = ''`
|
||||||
- Try starting with `jupyterhub --ip=0.0.0.0`
|
- Try starting with `jupyterhub --ip=0.0.0.0`
|
||||||
|
|
||||||
**Note**: If this occurs on Ubuntu/Debian, check that the you are using a
|
**Note**: If this occurs on Ubuntu/Debian, check that you are using a
|
||||||
recent version of node. Some versions of Ubuntu/Debian come with a version
|
recent version of [Node](https://nodejs.org). Some versions of Ubuntu/Debian come with a version
|
||||||
of node that is very old, and it is necessary to update node.
|
of Node that is very old, and it is necessary to update Node.
|
||||||
|
|
||||||
### sudospawner fails to run
|
### sudospawner fails to run
|
||||||
|
|
||||||
@@ -61,24 +35,24 @@ to the config file, `jupyterhub_config.py`.
|
|||||||
### What is the default behavior when none of the lists (admin, allowed, allowed groups) are set?
|
### What is the default behavior when none of the lists (admin, allowed, allowed groups) are set?
|
||||||
|
|
||||||
When nothing is given for these lists, there will be no admins, and all users
|
When nothing is given for these lists, there will be no admins, and all users
|
||||||
who can authenticate on the system (i.e. all the unix users on the server with
|
who can authenticate on the system (i.e. all the Unix users on the server with
|
||||||
a password) will be allowed to start a server. The allowed username set lets you limit
|
a password) will be allowed to start a server. The allowed username set lets you limit
|
||||||
this to a particular set of users, and admin_users lets you specify who
|
this to a particular set of users, and admin_users lets you specify who
|
||||||
among them may use the admin interface (not necessary, unless you need to do
|
among them may use the admin interface (not necessary, unless you need to do
|
||||||
things like inspect other users' servers, or modify the user list at runtime).
|
things like inspect other users' servers or modify the user list at runtime).
|
||||||
|
|
||||||
### JupyterHub Docker container not accessible at localhost
|
### JupyterHub Docker container not accessible at localhost
|
||||||
|
|
||||||
Even though the command to start your Docker container exposes port 8000
|
Even though the command to start your Docker container exposes port 8000
|
||||||
(`docker run -p 8000:8000 -d --name jupyterhub jupyterhub/jupyterhub jupyterhub`),
|
(`docker run -p 8000:8000 -d --name jupyterhub jupyterhub/jupyterhub jupyterhub`),
|
||||||
it is possible that the IP address itself is not accessible/visible. As a result
|
it is possible that the IP address itself is not accessible/visible. As a result,
|
||||||
when you try http://localhost:8000 in your browser, you are unable to connect
|
when you try http://localhost:8000 in your browser, you are unable to connect
|
||||||
even though the container is running properly. One workaround is to explicitly
|
even though the container is running properly. One workaround is to explicitly
|
||||||
tell Jupyterhub to start at `0.0.0.0` which is visible to everyone. Try this
|
tell Jupyterhub to start at `0.0.0.0` which is visible to everyone. Try this
|
||||||
command:
|
command:
|
||||||
`docker run -p 8000:8000 -d --name jupyterhub jupyterhub/jupyterhub jupyterhub --ip 0.0.0.0 --port 8000`
|
`docker run -p 8000:8000 -d --name jupyterhub jupyterhub/jupyterhub jupyterhub --ip 0.0.0.0 --port 8000`
|
||||||
|
|
||||||
### How can I kill ports from JupyterHub managed services that have been orphaned?
|
### How can I kill ports from JupyterHub-managed services that have been orphaned?
|
||||||
|
|
||||||
I started JupyterHub + nbgrader on the same host without containers. When I try to restart JupyterHub + nbgrader with this configuration, errors appear that the service accounts cannot start because the ports are being used.
|
I started JupyterHub + nbgrader on the same host without containers. When I try to restart JupyterHub + nbgrader with this configuration, errors appear that the service accounts cannot start because the ports are being used.
|
||||||
|
|
||||||
@@ -92,7 +66,7 @@ Where `<service_port>` is the port used by the nbgrader course service. This con
|
|||||||
|
|
||||||
### Why am I getting a Spawn failed error message?
|
### Why am I getting a Spawn failed error message?
|
||||||
|
|
||||||
After successfully logging in to JupyterHub with a compatible authenticators, I get a 'Spawn failed' error message in the browser. The JupyterHub logs have `jupyterhub KeyError: "getpwnam(): name not found: <my_user_name>`.
|
After successfully logging in to JupyterHub with a compatible authenticator, I get a 'Spawn failed' error message in the browser. The JupyterHub logs have `jupyterhub KeyError: "getpwnam(): name not found: <my_user_name>`.
|
||||||
|
|
||||||
This issue occurs when the authenticator requires a local system user to exist. In these cases, you need to use a spawner
|
This issue occurs when the authenticator requires a local system user to exist. In these cases, you need to use a spawner
|
||||||
that does not require an existing system user account, such as `DockerSpawner` or `KubeSpawner`.
|
that does not require an existing system user account, such as `DockerSpawner` or `KubeSpawner`.
|
||||||
@@ -109,23 +83,9 @@ sudo MY_ENV=abc123 \
|
|||||||
/srv/jupyterhub/jupyterhub
|
/srv/jupyterhub/jupyterhub
|
||||||
```
|
```
|
||||||
|
|
||||||
### How can I view the logs for JupyterHub or the user's Notebook servers when using the DockerSpawner?
|
|
||||||
|
|
||||||
Use `docker logs <container>` where `<container>` is the container name defined within `docker-compose.yml`. For example, to view the logs of the JupyterHub container use:
|
|
||||||
|
|
||||||
docker logs hub
|
|
||||||
|
|
||||||
By default, the user's notebook server is named `jupyter-<username>` where `username` is the user's username within JupyterHub's db. So if you wanted to see the logs for user `foo` you would use:
|
|
||||||
|
|
||||||
docker logs jupyter-foo
|
|
||||||
|
|
||||||
You can also tail logs to view them in real time using the `-f` option:
|
|
||||||
|
|
||||||
docker logs -f hub
|
|
||||||
|
|
||||||
## Errors
|
## Errors
|
||||||
|
|
||||||
### 500 error after spawning my single-user server
|
### Error 500 after spawning my single-user server
|
||||||
|
|
||||||
You receive a 500 error when accessing the URL `/user/<your_name>/...`.
|
You receive a 500 error when accessing the URL `/user/<your_name>/...`.
|
||||||
This is often seen when your single-user server cannot verify your user cookie
|
This is often seen when your single-user server cannot verify your user cookie
|
||||||
@@ -185,10 +145,10 @@ If you receive a 403 error, the API token for the single-user server is likely
|
|||||||
invalid. Commonly, the 403 error is caused by resetting the JupyterHub
|
invalid. Commonly, the 403 error is caused by resetting the JupyterHub
|
||||||
database (either removing jupyterhub.sqlite or some other action) while
|
database (either removing jupyterhub.sqlite or some other action) while
|
||||||
leaving single-user servers running. This happens most frequently when using
|
leaving single-user servers running. This happens most frequently when using
|
||||||
DockerSpawner, because Docker's default behavior is to stop/start containers
|
DockerSpawner because Docker's default behavior is to stop/start containers
|
||||||
which resets the JupyterHub database, rather than destroying and recreating
|
that reset the JupyterHub database, rather than destroying and recreating
|
||||||
the container every time. This means that the same API token is used by the
|
the container every time. This means that the same API token is used by the
|
||||||
server for its whole life, until the container is rebuilt.
|
server for its whole life until the container is rebuilt.
|
||||||
|
|
||||||
The fix for this Docker case is to remove any Docker containers seeing this
|
The fix for this Docker case is to remove any Docker containers seeing this
|
||||||
issue (typically all containers created before a certain point in time):
|
issue (typically all containers created before a certain point in time):
|
||||||
@@ -201,14 +161,14 @@ your server again.
|
|||||||
|
|
||||||
##### Proxy settings (403 GET)
|
##### Proxy settings (403 GET)
|
||||||
|
|
||||||
When your whole JupyterHub sits behind a organization proxy (_not_ a reverse proxy like NGINX as part of your setup and _not_ the configurable-http-proxy) the environment variables `HTTP_PROXY`, `HTTPS_PROXY`, `http_proxy` and `https_proxy` might be set. This confuses the jupyterhub-singleuser servers: When connecting to the Hub for authorization they connect via the proxy instead of directly connecting to the Hub on localhost. The proxy might deny the request (403 GET). This results in the singleuser server thinking it has a wrong auth token. To circumvent this you should add `<hub_url>,<hub_ip>,localhost,127.0.0.1` to the environment variables `NO_PROXY` and `no_proxy`.
|
When your whole JupyterHub sits behind an organization proxy (_not_ a reverse proxy like NGINX as part of your setup and _not_ the configurable-http-proxy) the environment variables `HTTP_PROXY`, `HTTPS_PROXY`, `http_proxy`, and `https_proxy` might be set. This confuses the Jupyterhub single-user servers: When connecting to the Hub for authorization they connect via the proxy instead of directly connecting to the Hub on localhost. The proxy might deny the request (403 GET). This results in the single-user server thinking it has the wrong auth token. To circumvent this you should add `<hub_url>,<hub_ip>,localhost,127.0.0.1` to the environment variables `NO_PROXY` and `no_proxy`.
|
||||||
|
|
||||||
### Launching Jupyter Notebooks to run as an externally managed JupyterHub service with the `jupyterhub-singleuser` command returns a `JUPYTERHUB_API_TOKEN` error
|
### Launching Jupyter Notebooks to run as an externally managed JupyterHub service with the `jupyterhub-singleuser` command returns a `JUPYTERHUB_API_TOKEN` error
|
||||||
|
|
||||||
[JupyterHub services](https://jupyterhub.readthedocs.io/en/stable/reference/services.html) allow processes to interact with JupyterHub's REST API. Example use-cases include:
|
[JupyterHub services](https://jupyterhub.readthedocs.io/en/stable/reference/services.html) allow processes to interact with JupyterHub's REST API. Example use-cases include:
|
||||||
|
|
||||||
- **Secure Testing**: provide a canonical Jupyter Notebook for testing production data to reduce the number of entry points into production systems.
|
- **Secure Testing**: provide a canonical Jupyter Notebook for testing production data to reduce the number of entry points into production systems.
|
||||||
- **Grading Assignments**: provide access to shared Jupyter Notebooks that may be used for management tasks such grading assignments.
|
- **Grading Assignments**: provide access to shared Jupyter Notebooks that may be used for management tasks such as grading assignments.
|
||||||
- **Private Dashboards**: share dashboards with certain group members.
|
- **Private Dashboards**: share dashboards with certain group members.
|
||||||
|
|
||||||
If possible, try to run the Jupyter Notebook as an externally managed service with one of the provided [jupyter/docker-stacks](https://github.com/jupyter/docker-stacks).
|
If possible, try to run the Jupyter Notebook as an externally managed service with one of the provided [jupyter/docker-stacks](https://github.com/jupyter/docker-stacks).
|
||||||
@@ -222,7 +182,7 @@ If you launch a Jupyter Notebook with the `jupyterhub-singleuser` command direct
|
|||||||
Did you launch it manually?
|
Did you launch it manually?
|
||||||
```
|
```
|
||||||
|
|
||||||
If you plan on testing `jupyterhub-singleuser` independently from JupyterHub, then you can set the api token environment variable. For example, if were to run the single-user Jupyter Notebook on the host, then:
|
If you plan on testing `jupyterhub-singleuser` independently from JupyterHub, then you can set the API token environment variable. For example, if you were to run the single-user Jupyter Notebook on the host, then:
|
||||||
|
|
||||||
export JUPYTERHUB_API_TOKEN=my_secret_token
|
export JUPYTERHUB_API_TOKEN=my_secret_token
|
||||||
jupyterhub-singleuser
|
jupyterhub-singleuser
|
||||||
@@ -256,7 +216,7 @@ You would then set in your `jupyterhub_config.py` file the `ssl_key` and
|
|||||||
#### Example
|
#### Example
|
||||||
|
|
||||||
Your certificate provider gives you the following files: `example_host.crt`,
|
Your certificate provider gives you the following files: `example_host.crt`,
|
||||||
`Entrust_L1Kroot.txt` and `Entrust_Root.txt`.
|
`Entrust_L1Kroot.txt`, and `Entrust_Root.txt`.
|
||||||
|
|
||||||
Concatenate the files appending the chain cert and root cert to your host cert:
|
Concatenate the files appending the chain cert and root cert to your host cert:
|
||||||
|
|
||||||
@@ -289,7 +249,7 @@ with npmbox:
|
|||||||
python3 -m pip wheel jupyterhub
|
python3 -m pip wheel jupyterhub
|
||||||
npmbox configurable-http-proxy
|
npmbox configurable-http-proxy
|
||||||
|
|
||||||
### I want access to the whole filesystem, but still default users to their home directory
|
### I want access to the whole filesystem and still default users to their home directory
|
||||||
|
|
||||||
Setting the following in `jupyterhub_config.py` will configure access to
|
Setting the following in `jupyterhub_config.py` will configure access to
|
||||||
the entire filesystem and set the default to the user's home directory.
|
the entire filesystem and set the default to the user's home directory.
|
||||||
@@ -321,7 +281,7 @@ For instance:
|
|||||||
python3 -m pip install jupyterlab
|
python3 -m pip install jupyterlab
|
||||||
jupyter serverextension enable --py jupyterlab --sys-prefix
|
jupyter serverextension enable --py jupyterlab --sys-prefix
|
||||||
|
|
||||||
The important thing is that jupyterlab is installed and enabled in the
|
The important thing is that JupyterLab is installed and enabled in the
|
||||||
single-user notebook server environment. For system users, this means
|
single-user notebook server environment. For system users, this means
|
||||||
system-wide, as indicated above. For Docker containers, it means inside
|
system-wide, as indicated above. For Docker containers, it means inside
|
||||||
the single-user docker image, etc.
|
the single-user docker image, etc.
|
||||||
@@ -334,14 +294,14 @@ notebook servers to default to JupyterLab:
|
|||||||
### How do I set up JupyterHub for a workshop (when users are not known ahead of time)?
|
### How do I set up JupyterHub for a workshop (when users are not known ahead of time)?
|
||||||
|
|
||||||
1. Set up JupyterHub using OAuthenticator for GitHub authentication
|
1. Set up JupyterHub using OAuthenticator for GitHub authentication
|
||||||
2. Configure admin list to have workshop leaders be listed with administrator privileges.
|
2. Configure the admin list to have workshop leaders be listed with administrator privileges.
|
||||||
|
|
||||||
Users will need a GitHub account to login and be authenticated by the Hub.
|
Users will need a GitHub account to log in and be authenticated by the Hub.
|
||||||
|
|
||||||
### How do I set up rotating daily logs?
|
### How do I set up rotating daily logs?
|
||||||
|
|
||||||
You can do this with [logrotate](https://linux.die.net/man/8/logrotate),
|
You can do this with [logrotate](https://linux.die.net/man/8/logrotate),
|
||||||
or pipe to `logger` to use syslog instead of directly to a file.
|
or pipe to `logger` to use Syslog instead of directly to a file.
|
||||||
|
|
||||||
For example, with this logrotate config file:
|
For example, with this logrotate config file:
|
||||||
|
|
||||||
@@ -362,6 +322,52 @@ Or use syslog:
|
|||||||
|
|
||||||
jupyterhub | logger -t jupyterhub
|
jupyterhub | logger -t jupyterhub
|
||||||
|
|
||||||
|
### Toree integration with HDFS rack awareness script
|
||||||
|
|
||||||
|
The Apache Toree kernel will have an issue when running with JupyterHub if the standard HDFS
|
||||||
|
rack awareness script is used. This will materialize in the logs as a repeated WARN:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
16/11/29 16:24:20 WARN ScriptBasedMapping: Exception running /etc/hadoop/conf/topology_script.py some.ip.address
|
||||||
|
ExitCodeException exitCode=1: File "/etc/hadoop/conf/topology_script.py", line 63
|
||||||
|
print rack
|
||||||
|
^
|
||||||
|
SyntaxError: Missing parentheses in call to 'print'
|
||||||
|
|
||||||
|
at `org.apache.hadoop.util.Shell.runCommand(Shell.java:576)`
|
||||||
|
```
|
||||||
|
|
||||||
|
In order to resolve this issue, there are two potential options.
|
||||||
|
|
||||||
|
1. Update HDFS core-site.xml, so the parameter "net.topology.script.file.name" points to a custom
|
||||||
|
script (e.g. /etc/hadoop/conf/custom_topology_script.py). Copy the original script and change the first line point
|
||||||
|
to a python two installation (e.g. /usr/bin/python).
|
||||||
|
2. In spark-env.sh add a Python 2 installation to your path (e.g. export PATH=/opt/anaconda2/bin:$PATH).
|
||||||
|
|
||||||
|
### Where do I find Docker images and Dockerfiles related to JupyterHub?
|
||||||
|
|
||||||
|
Docker images can be found at the [JupyterHub organization on DockerHub](https://hub.docker.com/u/jupyterhub/).
|
||||||
|
The Docker image [jupyterhub/singleuser](https://hub.docker.com/r/jupyterhub/singleuser/)
|
||||||
|
provides an example single-user notebook server for use with DockerSpawner.
|
||||||
|
|
||||||
|
Additional single-user notebook server images can be found at the [Jupyter
|
||||||
|
organization on DockerHub](https://hub.docker.com/r/jupyter/) and information
|
||||||
|
about each image at the [jupyter/docker-stacks repo](https://github.com/jupyter/docker-stacks).
|
||||||
|
|
||||||
|
### How can I view the logs for JupyterHub or the user's Notebook servers when using the DockerSpawner?
|
||||||
|
|
||||||
|
Use `docker logs <container>` where `<container>` is the container name defined within `docker-compose.yml`. For example, to view the logs of the JupyterHub container use:
|
||||||
|
|
||||||
|
docker logs hub
|
||||||
|
|
||||||
|
By default, the user's notebook server is named `jupyter-<username>` where `username` is the user's username within JupyterHub's db. So if you wanted to see the logs for user `foo` you would use:
|
||||||
|
|
||||||
|
docker logs jupyter-foo
|
||||||
|
|
||||||
|
You can also tail logs to view them in real-time using the `-f` option:
|
||||||
|
|
||||||
|
docker logs -f hub
|
||||||
|
|
||||||
## Troubleshooting commands
|
## Troubleshooting commands
|
||||||
|
|
||||||
The following commands provide additional detail about installed packages,
|
The following commands provide additional detail about installed packages,
|
||||||
@@ -385,35 +391,3 @@ jupyter kernelspec list
|
|||||||
```bash
|
```bash
|
||||||
jupyterhub --debug
|
jupyterhub --debug
|
||||||
```
|
```
|
||||||
|
|
||||||
### Toree integration with HDFS rack awareness script
|
|
||||||
|
|
||||||
The Apache Toree kernel will an issue, when running with JupyterHub, if the standard HDFS
|
|
||||||
rack awareness script is used. This will materialize in the logs as a repeated WARN:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
16/11/29 16:24:20 WARN ScriptBasedMapping: Exception running /etc/hadoop/conf/topology_script.py some.ip.address
|
|
||||||
ExitCodeException exitCode=1: File "/etc/hadoop/conf/topology_script.py", line 63
|
|
||||||
print rack
|
|
||||||
^
|
|
||||||
SyntaxError: Missing parentheses in call to 'print'
|
|
||||||
|
|
||||||
at `org.apache.hadoop.util.Shell.runCommand(Shell.java:576)`
|
|
||||||
```
|
|
||||||
|
|
||||||
In order to resolve this issue, there are two potential options.
|
|
||||||
|
|
||||||
1. Update HDFS core-site.xml, so the parameter "net.topology.script.file.name" points to a custom
|
|
||||||
script (e.g. /etc/hadoop/conf/custom_topology_script.py). Copy the original script and change the first line point
|
|
||||||
to a python two installation (e.g. /usr/bin/python).
|
|
||||||
2. In spark-env.sh add a Python 2 installation to your path (e.g. export PATH=/opt/anaconda2/bin:$PATH).
|
|
||||||
|
|
||||||
### Where do I find Docker images and Dockerfiles related to JupyterHub?
|
|
||||||
|
|
||||||
Docker images can be found at the [JupyterHub organization on DockerHub](https://hub.docker.com/u/jupyterhub/).
|
|
||||||
The Docker image [jupyterhub/singleuser](https://hub.docker.com/r/jupyterhub/singleuser/)
|
|
||||||
provides an example single user notebook server for use with DockerSpawner.
|
|
||||||
|
|
||||||
Additional single user notebook server images can be found at the [Jupyter
|
|
||||||
organization on DockerHub](https://hub.docker.com/r/jupyter/) and information
|
|
||||||
about each image at the [jupyter/docker-stacks repo](https://github.com/jupyter/docker-stacks).
|
|
||||||
|
@@ -6,12 +6,28 @@ that appear when JupyterHub renders pages.
|
|||||||
To run the service as a hub-managed service simply include in your JupyterHub
|
To run the service as a hub-managed service simply include in your JupyterHub
|
||||||
configuration file something like:
|
configuration file something like:
|
||||||
|
|
||||||
|
:notebook:**Info**: You can run the announcement service example from the `examples`
|
||||||
|
directory, using one of the several services provided by JupyterHub.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
# absolute path to announcement.py
|
||||||
|
announcement_py = str(Path(__file__).parent.joinpath("announcement.py").resolve())
|
||||||
|
|
||||||
|
#ensure get_config() is added in
|
||||||
|
c = get_config()
|
||||||
|
|
||||||
|
...
|
||||||
|
..
|
||||||
|
|
||||||
c.JupyterHub.services = [
|
c.JupyterHub.services = [
|
||||||
{
|
{
|
||||||
'name': 'announcement',
|
'name': 'announcement',
|
||||||
'url': 'http://127.0.0.1:8888',
|
'url': 'http://127.0.0.1:8888',
|
||||||
'command': [sys.executable, "-m", "announcement", "--port", "8888"],
|
'command': [sys.executable, announcement_py, "--port", "8888"],
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
c = get_config()
|
||||||
|
|
||||||
# To run the announcement service managed by the hub, add this.
|
# To run the announcement service managed by the hub, add this.
|
||||||
|
|
||||||
port = 9999
|
port = 9999
|
||||||
|
Reference in New Issue
Block a user