-
Notifications
You must be signed in to change notification settings - Fork 30
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
Traefik v2 #133
Traefik v2 #133
Conversation
- Renamed frontends and backedns to routers and services, respectively. - Traefik API paths at /api/providers/{provider_name} no longer work, so search /api/http/{services|routers} instead - Traefik file provider doesn't like arbitrary data (any more?), so have put JupyterHub's 'data' object into the dynamic configuration file in separate root keys. To Do: - Haven't touched the consul or etcd providers, other than to rename 'frontends' and 'backends', as above. - Test, test, test. Additionally, have renamed TraefikTomlProxy to TraefikFileProviderProxy, and edited relevant traefik_utils functions so the proxy provider should now work with either yaml or toml files. (need to test). - jupyterhub_config.py will now need to reference the proxy class 'traefik_file', e.g.:- c.JupyterHub.proxy_class = 'traefik_file' c.TraefikFileProviderProxy = '/path/to/rules.toml'
…ng initial work done in previous commit:- 41a5ef3 Also, see issue: jupyterhub#97 - Relevant documentation has been updated in README.md, docs/source/file.md (renamed from toml.md) - KV providers (consul and etcd) have been updated to use new Traefik KV paths, as per:- https://doc.traefik.io/traefik/reference/dynamic-configuration/kv/ - requirements.txt now makes toml an optional dependency as well as ruamel.yaml. This latter module is required by jupyterhub anyway, so should already be present on a system running JupyterHub. - The (thoroughly excellent) test system has had a bit of an overhaul:- - There were issues with repeated launching and shutting down of external `consul` and `etcd` servers, causing test failures. Added code to gracefully shutdown consul and wait for servers to launch (within `tests/conftest.py`) before continuing with the tests. - `traefik` v2 no longer has a 'storeconfig' command. Therefore, to load a pre-baked configuration file into the KV stores, have had to resort to loading configurations with either `etcdctl txn` or `consul kv import` commands. - The external file provider now watches a directory instead of a file, so have added a pre-baked dynamic_config directory (and file), where the rules.toml file will be saved and managed by the TraefikFileProviderProxy. - Removed the previous traefik_{consul_config,etcd_config}.toml files, (which acted as traefik static configuration files), and instead applied the static KV configuration using the CLI. - Refactored some of the text fixtures to try and re-use fixtures and make them (hopefully) a bit easier to follow. - Have duplicated the file_proxy and external_file_proxy pytest fixtures to test both toml and yaml files. (Would have preferred to parametrize the existing fixtures to avoid duplicating them, but couldn't figure out how). - `tests/test_traefik_api_auth.py` - Have had to make the test give traefik more of a chance to read its dynamic config before running the test. Previously, in traefik v1, the api authentication would be configured in the static config. Now the api 'middleware' is configured in the dynamic config, the previous wait condition of just waiting for the port to come up didn't give traefik enough time to set up the API authentication on that entrypoint / router. - All tests now pass on my dev system, woohoo!
documentation, examples and performance test suite. These are replaced by `traefik_file` and `TraefikFileProviderProxy`, respectively.
…elation to issue: jupyterhub#97 Although all tests passed on my test system, the github workflow tests failed with the etcd tests, for the following reasons:- - Hadn't actually tested etcd-3.4.15, the default version installed by the install script. I'd used the default ubuntu version, 3.2.26. I'm not sure if this caused issues (maybe?, see next point), but some new warnings are emitted about the log parameters for instance. - The tests mainly failed due to what I thought was a nasty race-condition between successive TraefikEtcdProxy test fixture calls. The `proxy()` fixture in `tests/test_proxy.py` doesn't appear to fully destroy the dependent Proxy classes between test runs. In the case of TraefikEtcdProxy, this leaves the etcd3/grpc client open through the end of one test and into the next test. Then the next TraefikEtcdProxy test gets a connection error. I don't know why only one grpc client is allowed - is this related to the etcd version? - but regardless, the less than ideal solution is to manually call `TraefikEtcdProxy.kv_client.close()` during the teardown of the external_etcd* test runs. This is also manually called now by `TraefikEtcdProxy.stop()`, when `should_start=True`. (This took me days to figure out!!) Some further modifications to the code include:- - Changed the KV store structure for jupyterhub-specific information. All jupyterhub routespecs, targets and data are now stored as:- jupyterhub/ -/routes/{escaped_routespec} = {target} -/targets/{escaped_target} = {data} N.B. I think this can be condensed to one single request. Atm, to get the {data} for a routespec, two KV get requests are required: 1. to get the {target}, and 2. to get the {data} using that {target}. The {target} is also in the traefik configuration, so it seems like unnecessary duplication of information and redirection. - Added `log_level` and `traefik_log_level` config parameters to the base Proxy class. The first sets the log level for the logger (and handler) of the Proxy class. The latter sets traefik's log level, if `should_start=True`. - General tidy up, removing excessive debug statements and commented-out code.
077a625, and later. The change in this commit made `jupyterhub_traefik/install.py` not download any versions of traefik, consul or etcd where the checksums were not present. Further, (and this was a change made in a later commit faa2832), the default version of etcd was updated to 3.4.15 and although this was present in the checksums, for some reason it did not install properly in the github workflow. Finally, updated some assert statements in tests/proxytest.py, to instead run `assert_equal(val, cmp)`, which makes the pytest error message easier to follow.
`proxy.kv_separator` in the wrong place, causing faulty target lookups in the etcd database.
Thanks for submitting your first pull request! You are awesome! 🤗 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is great GREAT! Thanks for this amazing work @alexleach 🎉
I think this should be kept (at least for now) as a separate branch, as Traefik 1.7 is still being actively maintained
Yes, you're right, that would be the best choice. I've created a new branch trafik-v2
and edited this PR to be opened against this branch instead of master
.
However I do think that the TraefikFileProviderProxy, TraefikEtcdProxy and TraefikConsulProxy classes could be somewhat optimised
They definitely need some ❤️ But as you said, this PR is already big as it is, so we could do these once this is done. But, please feel free to open issues with any improvement ideas you have.
I will do my best to review these changes in the following days. Thanks once again @alexleach!
Thanks for the positive feedback, very encouraging! I'm now trying to use this in my own (first) jupyterhub set up, and have a couple of issues that I need to iron out. This will affect the code in this branch, so I think there may need to be some design decisions, and further configuration settings. I'll explain my setup first, and then go into the issues. Architecture
I've configured Jupyterhub to authenticate using https://github.com/jupyterhub/oauthenticator. OAuth requires a redirect URL with https, so I need the jupyterhub routers to listen on my Limitations There are a couple of issues with the current traefik-v2 implementation, as I see it:-
Proposals I think a couple of configurable options need to be added to the base
Is a single traefik entrypoint enough? Are there instances where jupyterhub should have both http and https entrypoints? I think not, but maybe if jupyterhub-traefik-proxy starts traefik and certificates are configured, then port 80 should be redirected to port 443? I am going to add the two options above and try and get them working on my setup. Ideally, further unit tests would be added to test these options though, and maybe the redirect feature can be added later. Thoughts, comments and suggestions welcome! |
… routers. As mentioned in jupyterhub#133 (comment) configurable options have been added to the base TraefikProxy class:- - TraefikProxy.traefik_tls Setting this to `True ` will set the traefik tls option on each jupyterhub-configured traefik router - TraefikProxy.default_entrypoint A string that should match the traefik entryPoint, for which each jupyterhub-configured service will be attached. - TraefikProxy.traefik_entrypoints A list of strings, where each entrypoint should match traefik-configured entrypoints. If empty, then just use the default_entrypoint I'm not sure if this is the best way to do this to be honest. It looks like jupyterhub's `bind_url` predicates use of a single port anyway. So, is only a default_entrypoint necessary? Maybe these configuration options aren't required and should just be figured out from a combination of the other jupyterhub configuration variables (e.g. is bind_url http or https), and pulled from existing jupyterhub configuration variables anyway?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking great @alexleach! I did an initial pass and left a few comments and questions, but I'm planning to test this by hand to better understand the new traefik architecture and API and hopefully provide more useful feedback.
Is a single traefik entrypoint enough? Are there instances where jupyterhub should have both http and https entrypoints? I think not, but maybe if jupyterhub-traefik-proxy starts traefik and certificates are configured, then port 80 should be redirected to port 443?
I don't think so either. At some point, I tried embedding in the proxy, traefik's Let's Encrypt support and I think I made the same assumption (either a http or a https entrypoint). Ref here.
docs/source/install.md
Outdated
@@ -69,7 +69,7 @@ | |||
## Enabling traefik-proxy in JupyterHub | |||
|
|||
|
|||
[TraefikTomlProxy](https://github.com/jupyterhub/traefik-proxy/blob/master/jupyterhub_traefik_proxy/toml.py), [TraefikEtcdProxy](https://github.com/jupyterhub/traefik-proxy/blob/master/jupyterhub_traefik_proxy/etcd.py) and [TraefikConsulProxy](https://github.com/jupyterhub/traefik-proxy/blob/master/jupyterhub_traefik_proxy/consul.py) are custom proxy implementations that subclass [Proxy](https://github.com/jupyterhub/jupyterhub/blob/master/jupyterhub/proxy.py) and can register in JupyterHub config using `c.JupyterHub.proxy_class` entrypoint. | |||
[TraefikFileProviderProxy](https://github.com/jupyterhub/traefik-proxy/blob/Traefik_v2/jupyterhub_traefik_proxy/fileprovider.py), [TraefikEtcdProxy](https://github.com/jupyterhub/traefik-proxy/blob/Traefik_v2/jupyterhub_traefik_proxy/etcd.py) and [TraefikConsulProxy](https://github.com/jupyterhub/traefik-proxy/blob/Traefik_v2/jupyterhub_traefik_proxy/consul.py) are custom proxy implementations that subclass [Proxy](https://github.com/jupyterhub/jupyterhub/blob/Traefik_v2/jupyterhub/proxy.py) and can register in JupyterHub config using `c.JupyterHub.proxy_class` entrypoint. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the new branch is called traefik-v2
[TraefikFileProviderProxy](https://github.com/jupyterhub/traefik-proxy/blob/Traefik_v2/jupyterhub_traefik_proxy/fileprovider.py), [TraefikEtcdProxy](https://github.com/jupyterhub/traefik-proxy/blob/Traefik_v2/jupyterhub_traefik_proxy/etcd.py) and [TraefikConsulProxy](https://github.com/jupyterhub/traefik-proxy/blob/Traefik_v2/jupyterhub_traefik_proxy/consul.py) are custom proxy implementations that subclass [Proxy](https://github.com/jupyterhub/jupyterhub/blob/Traefik_v2/jupyterhub/proxy.py) and can register in JupyterHub config using `c.JupyterHub.proxy_class` entrypoint. | |
[TraefikFileProviderProxy](https://github.com/jupyterhub/traefik-proxy/blob/traefik-v2/jupyterhub_traefik_proxy/fileprovider.py), [TraefikEtcdProxy](https://github.com/jupyterhub/traefik-proxy/blob/traefik-v2/jupyterhub_traefik_proxy/etcd.py) and [TraefikConsulProxy](https://github.com/jupyterhub/traefik-proxy/blob/traefik-v2/jupyterhub_traefik_proxy/consul.py) are custom proxy implementations that subclass [Proxy](https://github.com/jupyterhub/jupyterhub/blob/traefik-v2/jupyterhub/proxy.py) and can register in JupyterHub config using `c.JupyterHub.proxy_class` entrypoint. |
docs/source/install.md
Outdated
@@ -78,13 +78,13 @@ you can load a specific config file and start JupyterHub using: | |||
$ jupyterhub -f /path/to/jupyterhub_config.py | |||
``` | |||
|
|||
There is an example configuration file [here](https://github.com/jupyterhub/traefik-proxy/blob/master/examples/jupyterhub_config.py) that configures JupyterHub to run with *TraefikEtcdProxy* as the proxy and uses dummyauthenticator and simplespawner to enable testing without administrative privileges. | |||
There is an example configuration file [here](https://github.com/jupyterhub/traefik-proxy/blob/Traefik_v2/examples/jupyterhub_config.py) that configures JupyterHub to run with *TraefikEtcdProxy* as the proxy and uses dummyauthenticator and simplespawner to enable testing without administrative privileges. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
jupyterhub_traefik_proxy/consul.py
Outdated
provider_config = { | ||
"consul": { | ||
"rootKey": self.kv_traefik_prefix, | ||
#"watch": True, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the watch
option gone in v2 or was it not doing anything already?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Certain providers still have a watch
option (ie. docker, file, marathon, rancher) , but not the consul provider. IIRC, traefik throws an error if you try and add watch
where not expected.
Ref: https://doc.traefik.io/traefik/reference/static-configuration/file/
# A: Although defined in the traefik docs, they appear to | ||
# do nothing, and CONSUL_HTTP_TOKEN needs to be used instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I remember having issues with this :( I think username/password
were documented in the traefik v1 docs too (and they're clearly in the v2 docs https://doc.traefik.io/traefik/providers/consul/#username) but I couldn't make them work in practice.
Does username/password auth works in Traefik v2 now? It looks like CONSUL_HTTP_TOKEN
is still being used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct, I tried with user / password auth, but with no success. I referenced a github comment where it mentions traefik uses libkv for the consul provider. For some reason, this needs the environment variable, and the arguments passed to traefik don't actually appear to do anything...
jupyterhub_traefik_proxy/proxy.py
Outdated
self._generate_htpassword() | ||
api_url = urlparse(self.traefik_api_url) | ||
api_path = api_url.path if api_url.path else '/api' | ||
api_credentials = "{0}:{1}".format( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe use f-strings here also to be consistent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ha, yes! I have been converting many of the %s style format-strings to f-strings too, so may as well here. Thanks
return "/".join( | ||
[proxy.kv_traefik_prefix, "http", "routers", router_alias, "service"] | ||
) | ||
#return proxy.kv_traefik_prefix + "routers/" + router_alias + "/service" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#return proxy.kv_traefik_prefix + "routers/" + router_alias + "/service" |
proxy.kv_traefik_prefix + frontend_rule_entry + separator + "rule" | ||
router_rule_entry = separator.join( | ||
[proxy.kv_traefik_prefix, router_rule_entry, "rule"] | ||
#proxy.kv_traefik_prefix + router_rule_entry + separator + "rule" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#proxy.kv_traefik_prefix + router_rule_entry + separator + "rule" |
def persist_dynamic_conf(file_path, routes_dict): | ||
# FIXME: Only used by fileprovider, remove? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This confused me a bit since there's another similarly named proxy specific method persist_dynamic_config
. But this one from utils
doesn't look to be used anymore, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, just double checked and it isn't used any more. Was thinking about merging those methods into the TraefikProxy
base class tbh. Either way, I have removed those standalone functions from traefik_utils.py
in my working copy now. I did think that they might make nice static or class methods maybe, but it's been too long since I've written either...
@@ -31,14 +31,14 @@ | |||
"metadata": {}, | |||
"outputs": [], | |||
"source": [ | |||
"toml_df_concurrent = pd.read_csv('~/results/toml_methods_concurrent.csv')\n", | |||
"file_df_concurrent = pd.read_csv('~/results/file_methods_concurrent.csv')\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should be modifying anything performance-related yet. With traefik's v2 architecture change, I expect the results to be slightly different, so we definetly need to re-run the perf tests with the new traefik version (maybe even chage/improve them).
However, I think this should be tackled in a different PR. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. It would definitely be good to compare any performance differences between the two traefik major versions, and ofc this branch of jupyterhub-traefik-proxy vs master. I haven't touched or even run the performance suite yet, other than to replace any mention of 'toml' with 'file'. I doubt there would be much of a performance difference between the toml
and yaml
file providers (so maybe worth running both?), but you never know...
In terms of this branch vs master, I'd suspect master to be more performant at this stage, as I feel I've added various conditional statements without removing any. Further, especially wrt. traefik startup, the separation of various traefik configuration options (e.g. the API auth settings) from the static config into the provider config, adds quite a significant delay in _wait_for_static_config
.
Hi, I've saved your suggested changes (although I haven't touched the logger, which I'm not really too sure on atm tbh, see response to your comment) to my working tree and hope to commit that soon to my traefik-v2-tls branch, assuming the test suite passes. What I'm currently doing is running the test suite with all the proxytest fixtures using
Having had a good think about this, and using jupyterhub with traefik in practice for the last week or so, I think the best course of action is to determine the desired entrypoint scheme from I created a new branch, because I thought there was enough going on with this PR already! But TLS support is definitely required in any production setting, so I think it's important to get it right. Once I'm happy with that branch, I'll merge it into my traefik-v2 branch, and I guess it will be appended to this PR. |
…with the traefik entrypoint. * Removed the import of all TraefikProxy derived classes in jupyterhub_traefik_proxy/__init__.py. Only one needed at a time, never all of them. * When using an external traefik proxy, the TraefikProxy classes will now query traefik's API for the entrypoint that matches the assigned public_url. See `TraefikProxy._get_traefik_entrypoint()`. * Only a single entrypoint is allowed by this manner (reverting suggested change in previous commit 3501d08) to have multiple, configurable entrypoints. * Done away with configurable option `traefik_tls`, instead determining it from the scheme of `public_url`, i.e. http or https. * Fixed docstrings in kv_proxy.py, if sphinx complained. * Removed the `debug` Boolean trait from TraefikProxy, instead relying on `traefik_log_level` and `log_level`, for setting traefik's log level, and the TraefikProxy log level, respectively. * Documentation fixes: updated docs/sphinxext/autodoc_traits.py to match master, at https://github.com/jupyterhub/autodoc-traits/ * Implemented various suggested changes by @GeorgianaElena in jupyterhub#133 * Removed the standalone configuration loading and dumping functions from traefik_utils, leaving them only in TraefikConfigFileHandler. * Updated test suite so works when testing https URLs (without validation, as traefik will self-sign certificates) as well as http URLs. Currently, proxytest.py will do either http or https. Should it run both?
Ah, I changed the name of my Traefik_v2 branch to |
Remove old, commented-out code, as per @GeorgianaElena's review Co-authored-by: Georgiana Elena <[email protected]>
Hiya, So, in my previous big commit 50e59d6, I tried to remove any extraneous options with respect to entrypoints and TLS configuration. I thought a smart way of doing this was to check the scheme (http or https) in In production however, my configuration file just sets So, there's still a bit of work to do here:-
|
Hi.
Actually, I didn't get what do you mean. bind_url is used by Jupyterhub to start Tornado web server and listen for requests. Traefik cannot use the same config value because the same port number is already used by hub itself. Could you please provide a part of your configuration? |
@@ -19,7 +19,7 @@ depending on how traefik store its routing configuration. | |||
|
|||
For **smaller**, single-node deployments: | |||
|
|||
* TraefikTomlProxy |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, TraefikFileProviderProxy now supports both yaml and toml configuration files. It seemed inappropriate to leave it as TraefikTomlProxy, when yaml files can also easily be supported.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see, thank you.
@@ -424,14 +438,14 @@ async def test_websockets(proxy, launch_backend): | |||
launch_backend(default_backend_port, "ws") | |||
|
|||
await exponential_backoff( | |||
utils.check_host_up, "Traefik not reacheable", ip="localhost", port=traefik_port | |||
utils.check_host_up, "Traefik not reacheable", ip="127.0.0.1", port=traefik_port |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
localhost
was resolving to ::1
in my test container. I'm running everything in docker containers, where IPv6 is disabled by default, so I don't think ::1
is a usable address. I was experiencing a load of 'cannot bind ::1 address' test error messages, which I hoped this would fix. Those errors might have been caused by some other problem, I admit. I haven't specifically reverted this change and re-tested after everything else works tbh.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
localhost was resolving to ::1 in my test container
It looks like something is wrong with your Docker installation. For example, you have IPv6 disabled on the kernel level (/proc/sys/net/ipv6/conf/all/disable_ipv6
is set to 1), but there is no ipv6: false
in your /etc/docker/daemon.json
file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought IPv6 was just disabled by default with docker: https://docs.docker.com/config/daemon/ipv6/
On my current system:-
$ cat /proc/sys/net/ipv6/conf/all/disable_ipv6
0
$ ls /etc/docker/
key.json
$
However, also (while in the container):-
root@8933dcac4db4:/srv/jupyterhub# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.23.0.4 8933dcac4db4
root@8933dcac4db4:/srv/jupyterhub# openssl s_client -connect ip6-localhost:8081
CONNECTED(00000003)
^C
root@8933dcac4db4:/srv/jupyterhub#
So yes, changing localhost
to 127.0.0.1
was probably not what fixed whatever issue I was facing at the time!
I mean why do you need:
at all? Why not |
That's the exact plan! 😄 The jupyterhub server is actually listening on http://:8081, with an http connection. It's traefik that's listening at https://:443/jupyter, not jupyterhub itself. e.g. When I launch my jupyterhub container, I get these startup messages for instance:-
So here, what was configured as the |
But why not just set |
Hey @alexleach! Thanks a lot for thinking everything through and trying to make this as better as possible. I really appreciate it! I was thinking that before moving further with this, we could split this PR into smaller ones. The reasoning behind this would be: To make it easier to review and mergeI must confess, that every time I tried to review this PR, I felt overwhelmed about all the changes here and not being very familiar with everything that changed in traefik v2. It's also a bit hard to remember everything when context-switching from other work. To have the discussions and decisions around a certain topic (file-provider, consul, etcd, tls) in their own contextThis would make the discussions around different design decision easier to follow. I believe you're using this branch in your personal setup, right? If so, maybe creating different branches for the new PRs would be the way to go. We could also create issues to help with dividing and organizing the work in smaller tasks. What do think @alexleach? I would really love to see this work being added to |
The same thing just occurred to me 👍
I guess we can make it configurable, but then |
Hi @GeorgianaElena, thanks for the comment 😄
Excellent, glad to hear it! 🥳
Oh dear.. Yes it has become a big PR (!), many commits and there seems to be more and more of them required! I agree that browsing through the changes here on github is overwhelming, it takes ages to scroll through the diffs to find a code comment for instance!
Tbh, I don't have confidence that my git-foo is good enough to backtrack all my changes into smaller, bite size chunks. I wanted the test-suite to fully pass ofc, so moving to traefik v2 required changes to all of the proxy providers at once. I agree that renaming Also agreed that some of the test-suite changes were perhaps excessive. Again though, I tried to make sure all the tests passed. Traefik v2 seems to take a lot longer to start the API than v1, as it is configured through the 'dynamic config', and not the static config file now. Making sure everything was fully started (e.g. consul, then traefik, then traefik's API) before the test functions began was a big challenge.
I have been switching, I was using my https://github.com/alexleach/traefik-proxy/tree/traefik-v2-tls branch, then when I thought that was working, merged that back into https://github.com/alexleach/traefik-proxy/tree/Traefik_v2 (thereby adding to this PR!) and started using that again... For my working jupyterhub container, I actually use pip to install from my github repo. It was working perfectly for me back on commit alexleach@3501d08, but the TLS implementation was very broken for anything other than an external file provider proxy. The reason I've been adding more changes recently, especially wrt. TLS is that it seems that having a broken TLS implementation would be a regression. Something best avoided?
I understand why you'd want to reduce the size of this PR and break it down into smaller chunks, but I don't really know where to start or how, I've gone too far down the rabbit hole! Help! 😬 |
This is just a wrong config option. It should be |
I have tried playing around with e.g. with
This doesn't actually route, as the traefik service needs to be configured with the container name. So, with
This routes, but I still have the same issue. i.e. My traefik service is not TLS enabled, and I've just changed the internal urls on my docker network for no major benefit. TLS is not required on the internal docker network at this stage, as for me at least, I'm running everything on the same host. |
Hiya, I've had a go at rebasing and cherry-picking some of my commits and created a traefik-v2-file branch, dedicated to getting the traefik v2 file provider working with both toml and yaml configuration files. https://github.com/jupyterhub/traefik-proxy/compare/master...alexleach:traefik-v2-file?expand=1 It's still quite a large body of work, and the consul and etcd providers definitely(!) don't work in this branch. However, is this an easier starting point? If so, should I try and create a new branch for the KV providers from this point? |
It's looking great @alexleach!
Yeah, makes sense not to work. We could potentially "deactivate" running the tests in the CI for these other proxies, by removing them from this list traefik-proxy/tests/test_proxy.py Lines 11 to 24 in d8d729c
New ideaHowever I'm thinking we could maybe simplify things even further. What I have in mind is:
I'm really not sure what's the best solution here @alexleach, but I'm happy we can work things out together! What do you think about the idea above? (also pinging @minrk, @yuvipanda and @consideRatio ☀️ any advice would be really helpful 👀 ) |
Hi @GeorgianaElena , I've just had a chance to get back to this now, mainly to get my traefik-v2-file branch passing all relevant tests. As per my comment on your recent PR (#134 (comment)), I think your suggestion above makes sense, i.e. Remove anything related to TKvProxy, consul and etcd and focus on the file provider for the initial traefik-v2 PR. However, I'm not sure where to take it from here tbh. Maybe the best course of action for me is to stop(!) until a path forward is agreed, as I don't want to mess up the commit history any more than it already is, and I'm already nervous about how I'm going to merge against your recent PR! Happy to do that though, but some direction would be really appreciated, e.g. should I rebase against your clean-for-traefikv2 fork, or to the main repo's traefik-v2 branch after you commit your PR? Will await instruction and work on something else before I do anything more to this, either way! Kind regards, |
… the traefik entrypoint. * When using an external traefik proxy, the TraefikProxy classes will now query traefik's API for the entrypoint that matches the assigned public_url. See `TraefikProxy._get_traefik_entrypoint()`. * Only a single entrypoint is allowed by this manner (reverting suggested change in previous commit 3501d08) to have multiple, configurable entrypoints. * Done away with configurable option `traefik_tls`, instead determining it from the scheme of `public_url`, i.e. http or https. * Fixed docstrings in kv_proxy.py, if sphinx complained. * Implemented various suggested changes by @GeorgianaElena in jupyterhub#133 * Removed the standalone configuration loading and dumping functions from traefik_utils, leaving them only in TraefikConfigFileHandler. * Updated test suite so works when testing https URLs (without validation, as traefik will self-sign certificates) as well as http URLs. Currently, proxytest.py will do either http or https. Should it run both?
Hi @GeorgianaElena , I hope you're well. I've had a chance this morning to rebase my traefik-v2-file branch against the main traefik-v2 branch. This is I hope about as minimal an initial set of changes as I could make it, but does have some issues wrt. TLS and traefik entrypoints:-
You can check out the diff here. Let me know if you'd like me to make a PR from this branch. The documentation could potentially do with a prune as well, considering that consul and etcd proxies are not yet supported... I have made another branch as well, traefik-v2-file-tls. For this, I cherry-picked some code from my Traefik_V2 branch, where TLS is enabled and entrypoints dynamically determined from the traefik api. Not sure if better to make a PR of everything in traefik-v2-file-tls, or easier to start with traefik-v2-file, and then make a follow-up PR with traefik-v2-file-tls? Let me know what works better for you 🙂 |
Hey @alexleach! Thanks a lot for getting back to this! 🌻 I think tackling one thing at a time is the way to go. Opening a first PR, with the file provider (even though TLS won't work) is fine IMO. We can deal with anything that's missing in the next iteration. Regarding the docs, yeah, I agree. There is extra info there that needs to go. But we can update those once we have something stable. What do you think? |
finally managed to merge this as #145, thanks @alexleach and @dolfinus! |
As mentioned in #97, I've done quite a bit of work to try and get https://github.com/jupyterhub/traefik-proxy working with Traefik v2.
I think this should be kept (at least for now) as a separate branch, as Traefik 1.7 is still being actively maintained. Hopefully this is a good start to getting out a release compatible with Traefik v2.
To do:-
traefik_utils.py
.Desired:-
routespec
, two sequentialget
requests against the KV store are needed, one to getjupyterhub/routes/{routespec}
, which gives the value{target}
and another to getjupyterhub/targets/{escaped_target}
, which has the value{data}
. This to me seems like it could be reduced to a single get request, as{target}
is already known bytraefik
and doesn't need to be stored separately from the traefik config.traefik_utils.py
), that might be unnecessary. I wanted to get a Traefik v2 implementation passing all tests before spending time optimising any of this though.