Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

add redis implementation #230

Merged
merged 8 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ env:
jobs:
# Run "pytest tests" for various Python versions
pytest:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
timeout-minutes: 30
strategy:
# Keep running even if one variation of the job fail
Expand All @@ -45,6 +45,7 @@ jobs:
- python: "3.9"
backend: "consul"
- python: "3.10"
backend: "redis"
- python: "3.11"
steps:
# NOTE: In GitHub workflows, environment variables are set by writing
Expand All @@ -69,21 +70,31 @@ jobs:
python -m jupyterhub_traefik_proxy.install --output=./bin

pip freeze
- name: Install etcd, consul
- name: Install consul
if: matrix.backend == 'consul'
run: |
curl -L https://releases.hashicorp.com/consul/${CONSUL_VERSION}/consul_${CONSUL_VERSION}_linux_amd64.zip > consul.zip
unzip consul.zip -d ./bin consul

- name: Install etcd
if: matrix.backend == 'etcd'
run: |
curl -L https://github.com/etcd-io/etcd/releases/download/v${ETCD_DOWNLOAD_VERSION}/etcd-v${ETCD_DOWNLOAD_VERSION}-linux-amd64.tar.gz > etcd.tar.gz
tar -xzf etcd.tar.gz -C ./bin --strip-components=1 --wildcards '*/etcd*'

- name: Install redis
if: matrix.backend == 'redis'
run: |
sudo apt-get -y install redis-server

- name: Select tests
run: |
if [[ ! -z "${{ matrix.backend }}" ]]; then
# select backend subset
echo "PYTEST_ADDOPTS=-k ${{ matrix.backend }}" >> "${GITHUB_ENV}"
else
# default: select everything _but_ the etcd/consul backend tests
echo "PYTEST_ADDOPTS=-k 'not etcd and not consul'" >> "${GITHUB_ENV}"
# default: select everything _but_ the KV backend tests
echo "PYTEST_ADDOPTS=-k 'not etcd and not consul and not redis'" >> "${GITHUB_ENV}"
fi

- name: Run tests
Expand Down
1 change: 1 addition & 0 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ pytest
pytest-asyncio>=0.17,<0.23
pytest-cov
python-consul2
redis
websockets
11 changes: 11 additions & 0 deletions docs/source/api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@
:members:
```

```{eval-rst}
.. currentmodule:: jupyterhub_traefik_proxy.redis
```

### {class}`TraefikRedisProxy`

```{eval-rst}
.. autoconfigurable:: TraefikRedisProxy
:members:
```

```{eval-rst}
.. currentmodule:: jupyterhub_traefik_proxy.etcd
```
Expand Down
8 changes: 7 additions & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@
'myst_parser',
]

myst_enable_extensions = [
"colon_fence",
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

Expand Down Expand Up @@ -209,4 +212,7 @@
# -- Options for intersphinx extension ---------------------------------------

# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'https://docs.python.org/': None}
intersphinx_mapping = {
"python": ("https://docs.python.org/3", None),
"redis": ("https://redis-py.readthedocs.io/en/stable/", None),
}
6 changes: 3 additions & 3 deletions docs/source/consul.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Using TraefikConsulProxy

```{warning}
:::{warning}
While it works today (2023), there does not appear to be a maintained Python client for the consul API.
As such, using jupyterhub-traefik-proxy with consul is deprecated in jupyterhub-traefik-proxy 1.0.
You can use etcd instead to achieve the same functionality (and slightly better performance).
```
You can use redis instead to achieve the same functionality (and slightly better performance).
:::

[Consul](https://www.consul.io/)
is a distributed key-value store.
Expand Down
11 changes: 8 additions & 3 deletions docs/source/details.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,16 @@ TKvProxy is an adapter layer, implementing all of the above methods, based on a

TKvProxy is responsible for translating between key-value-friendly "flat" dictionaries and the 'true' nested dictionary format of the configuration (i.e. the nested dictionary `{"a": {"b": 5}}` will be flattened to `{"a/b": "5"}`).

Finally, we have our specific key-value store implementations: [](TraefikEtcdProxy) and [](TraefikConsulProxy).
Finally, we have our specific key-value store implementations:

- [](TraefikRedisProxy)
- [](TraefikEtcdProxy)
- [](TraefikConsulProxy)

These classes only need to implement:

1. configuration necessary to connect to the key-value provider
2. `_setup_traefik_static_config` to tell traefik how to talk to the same key-value provider
1. configuration necessary to connect to the key-value store
2. `_setup_traefik_static_config` to tell traefik how to talk to the key-value store
3. the above three `_kv_` methods for reading, writing, and deleting keys

## Testing jupyterhub-traefik-proxy
Expand Down
15 changes: 12 additions & 3 deletions docs/source/etcd.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
# Using TraefikEtcdProxy

:::{warning}
While it works today (2024), there does not appear to be a maintained, documented Python client for the etcd API.
We will keep an eye on etcd API clients,
but in the meantime we recommend using [redis](redis) as the backend.
:::

[Etcd](https://coreos.com/etcd/)
is a distributed key-value store.
This and TraefikConsulProxy is the choice to use when using jupyterhub-traefik-proxy
in a distributed setup, such as a Kubernetes cluster,
e.g. with multiple traefik-proxy instances.
With it, you can use JupyterHub with _distributed_ instances of traefik,
e.g. multiple replicas in kubernetes.

:::{seealso}
[TraefikRedisProxy](redis)
:::

## How-To install TraefikEtcdProxy

Expand Down
33 changes: 26 additions & 7 deletions docs/source/index.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,39 @@
# JupyterHub Traefik Proxy

An implementation of the JupyterHub proxy api with [traefik](https://traefik.io) : an extremely lightweight, portable reverse proxy implementation, that supports load balancing and can configure itself automatically and dynamically.
An implementation of the JupyterHub proxy api with [traefik](https://traefik.io): an extremely lightweight, portable reverse proxy implementation that supports load balancing and can configure itself automatically and dynamically.

## Why traefik?

Currently, the **default** proxy implementation for JupyterHub is [configurable-http-proxy](https://github.com/jupyterhub/configurable-http-proxy) (CHP), which stores the routing table in-memory. This might be the best approach in most of the cases, but because you can only run a single copy of the proxy at a time, it has its limitations when used in dynamic large scale systems.
Currently, the **default** proxy implementation for JupyterHub is [configurable-http-proxy](https://github.com/jupyterhub/configurable-http-proxy) (CHP), which stores the routing table in-memory. This might be the best approach in most cases, but because you can only run a single copy of the proxy at a time, it has its limitations when used in dynamic large scale systems.

When using a proxy implementation based on traefik, you can run multiple instances of traefik by using a distributed key-value store like [etcd](https://coreos.com/etcd) or [consul](https://www.consul.io/) to store the routing table. This makes the proxy **highly available** and improves the scalability and stability of the system.
Moreover it offers _HTTPS_ support through a straight-forward [ACME (Let's Encrypt)](https://docs.traefik.io/configuration/acme) configuration.
When using a proxy implementation based on traefik, you can run multiple instances of traefik by using a distributed key-value store like [redis](https://redis.io) to store the routing table. This makes the proxy **highly available** and improves the scalability and stability of the system.
Moreover, traefik offers _HTTPS_ support through a straight-forward [ACME (Let's Encrypt)](https://docs.traefik.io/configuration/acme) configuration.

There are three versions for the proxy, depending on how traefik stores the routes:
minrk marked this conversation as resolved.
Show resolved Hide resolved

- _for_ **smaller**, _single-node deployments_:
- _for_ **smaller**, _single-node deployments_, use plain files:
- TraefikFileProviderProxy
- _for_ **distributed** _setups_:
- _for_ **distributed** _setups_, use a key-value store:
- TraefikRedisProxy (recommended)
- TraefikEtcdProxy
- TraefikConsulProxy
- TraefikConsulProxy (deprecated)

### Picking a key-value backend

If you are planning to run a with a key-value backend, you'll have to pick which one.
The key-value store implementations are fairly equivalent.
If you already have a key-value store running, you can stick with that.
We currently recommend [redis](redis) as the default if you don't have specific reasons to pick another one.

The health of Python APIs for each key-value store is _very_ inconsistent.
As of January 2024, it appears that redis is the only key-value store supported by traefik with a well-supported Python client.
Consul support is deprecated, given its current client situation.
Etcd is in a slightly better situation, but may end up deprecated as well, given that we now have a redis implementation.
As a result, we recommend using redis.

etcd has one benefit over redis of being a single binary file to download and install,
while redis is typically installed via `apt`, etc.
But in most cases where traefik will actually be used with a key-value store, the store backend is very likely to be run in its own container where installation differences don't really come up.

## Contents

Expand All @@ -34,6 +52,7 @@ install

https
file
redis
etcd
consul
```
Expand Down
5 changes: 4 additions & 1 deletion docs/source/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@

If you want to use a key-value store to mediate configuration
(mainly for use in distributed deployments, such as containers),
you can get etcd or consul via their respective release pages:
you can get The key-value stores via their respective installation pages:
minrk marked this conversation as resolved.
Show resolved Hide resolved

- Install [`redis-server`](https://redis.io/docs/install/install-redis/)

- Install [`etcd`](https://github.com/etcd-io/etcd/releases)

Expand All @@ -70,6 +72,7 @@ you can get etcd or consul via their respective release pages:
Or, more likely, select the appropriate container image.
You will also need to install a Python client for the Key-Value store of your choice:

- `redis`
- `etcdpy`
- `python-consul2`

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind updating the section below (https://jupyterhub-traefik-proxy--230.org.readthedocs.build/en/230/install.html#enabling-traefik-proxy-in-jupyterhub) too, to add redis, and to make it the example config instead of etcd? I think it'd be nice to replace the GitHub source file links with links to the Using TraefikXXXProxy pages instead.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated, thanks

Expand Down
Loading