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

Dynamic proxy #564

Closed
wants to merge 56 commits into from
Closed

Conversation

abiosoft
Copy link

@abiosoft abiosoft commented Feb 2, 2016

Dynamic Proxy.

Supports Etcd, Consul and ZooKeeper using github.com/docker/libkv.

Demonstration Video: https://youtu.be/I0Kax0F1XWM

Examples

Etcd

proxy / etcd://127.0.0.1:2379/caddyserver.com

Consul

proxy / consul://127.0.0.1:8500/caddyserver.com

mholt and others added 17 commits January 13, 2016 00:29
I've built this on Go 1.6 beta 1 and made some changes to be more compatible. Namely, I removed the use of the /x/net/http2 package and let net/http enable h2 by default; updated the way h2 is disabled (if the user requires it); moved TLS_FALLBACK_SCSV to the front of the cipher suites list (all values not accepted by http2 must go after those allowed by it); removed the NextProto default of http/1.1; set the http.Server.TLSConfig value to the TLS config used by the listener (we left it nil before, but this prevents automatic enabling of h2).

It is very likely there is more to do, but at least already Caddy uses HTTP/2 when built with Go 1.6.
Implements "on-demand TLS" as I call it, which means obtaining TLS certificates on-the-fly during TLS handshakes if a certificate for the requested hostname is not already available. Only the first request for a new hostname will experience higher latency; subsequent requests will get the new certificates right out of memory.

Code still needs lots of cleanup but the feature is basically working.
Conflicts:
	middleware/proxy/upstream.go
@InAnimaTe
Copy link

So after watching your video, this definitely does seem to be shaping up! I'm really glad you've taken the plunge into getting support for dynamic backends at least started!

Based on some experience and seeing what others provide, I have some input that may not exactly apply to this specific PR but can at least spawn discussion and thinking for future additions to this end goal.

  1. It would be really cool if Caddy could provide the ability to consume proxy based configuration via container runtime labels or variables. You could consume a label/variable like caddy.port=2015 telling the proxy to utilize the public port entry in etcd mapped to 2015. You could even define http or https backend connectivity i.e caddy.protocol=https or weight caddy.weight=7 for this particular backend.

Note that this depends on what registrator dumps in your K/V store based on metadata it finds from your docker socket! I know for a fact a lot of things are possible with environment variables.

  1. Not sure much about the etcd entry with the appended /caddy-2015 but to me, the only data in the actual front-end proxy configuration (relating to the container infra) should be the name of the service. In example, if I have a service bugzilla, I should only really need to reference /bugzilla in etcd. That's, for all intensive purposes, the key for which back-end containers register themselves with a front-end.
  2. Global definition of backend store locations is definitely something I'd like to see. A lot of the time, docker infrastructure has multiple redundant proxies all making backend connections to a multitude of container hosts. For an entire deployment like this, the proxies would essentially utilize the same K/V store and service discovery system for the entire cluster. Maybe utilize a variable or something for this i.e. proxy / main_etcd_store://bugzilla with something like dynamic etcd etcd://192.168.1.19:4444 setup globally. Keep reading for more ideas in this realm.
  3. Re-iteration on the last point, why don't you allow for sub-service declarations under a specific from and even specify the destination K/V store right in the stanza i.e.
proxy / {
  bugzilla {
    destination: etcd
    max_fails 7
    health_check /bugs
  }
  jira {
    fail_timeout 30
    destination: consul
  }
}

So this says look in the globally defined etcd K/V for bugzilla and health check any backend container endpoints @ /bugs to ensure a proper response is returned. Likewise for jira, just a tad different.

Finally, I haven't used Caddy extensively yet but it seems it doesn't yet support Name Based Proxying? This feature is a must for Caddy to compete long-term as a docker load-balancer and reverse proxy.
Something like this would be very exciting:

proxy / {
  bitbucket {
    name: git.example.com
    destination: zookeeper

I'm subscribed to this thread so post replies and lets work together to figure out the best way to do this!

@faddat
Copy link
Contributor

faddat commented Feb 6, 2016

....and now I am subscribed as well. Is there an IRC or messaging client that the three of us have in common?

@mholt
Copy link
Member

mholt commented Feb 6, 2016

@faddat Join us on gitter for dev chat: https://gitter.im/mholt/caddy

Vadim Petrov and others added 8 commits February 10, 2016 18:03
fastcgi: New function DialWithDialer to create FCGIClient with custom Dialer.
Biggest change is no longer using standard library's tls.Config.getCertificate function to get a certificate during TLS handshake. Implemented our own cache which can be changed dynamically at runtime, even during TLS handshakes. As such, restarts are no longer required after certificate renewals or OCSP updates.

We also allow loading multiple certificates and keys per host, even by specifying a directory (tls got a new 'load' command for that).

Renamed the letsencrypt package to https in a gradual effort to become more generic; and https is more fitting for what the package does now.

There are still some known bugs, e.g. reloading where a new certificate is required but port 80 isn't currently listening, will cause the challenge to fail. There's still plenty of cleanup to do and tests to write. It is especially confusing right now how we enable "on-demand" TLS during setup and keep track of that. But this change should basically work so far.
After 10 certificates are issued, no new certificate requests are allowed for 10 minutes after a successful issuance.
@mholt
Copy link
Member

mholt commented Apr 17, 2016

After Caddy 0.9 is released (not next week, but the release after -- not sure when that is yet), Caddy will be in a much better position to have this merged. Not quite sure of the details yet but I'll work closely with @abiosoft at that point.

@thalesfsp
Copy link

@mholt What will be the performance impact of this PR? Benchmark?

@mholt
Copy link
Member

mholt commented May 11, 2016

@thalesfsp No clue, honestly - @abiosoft might know better. I would imagine it would only have minimal, if any, impact, since as I understand it, the updating of proxies is done in the background.

@thalesfsp
Copy link

@mholt Awesome! I hope and will wait for @abiosoft come with some benchmark :)

@mholt
Copy link
Member

mholt commented May 12, 2016

You can always perform your own, too.

@abiosoft
Copy link
Author

I expect it to have little to no impact

@mholt
Copy link
Member

mholt commented Jun 5, 2016

It's amazing this PR can still be merged 😄 That will not be the case for long though.

The 0.9 changes are in a branch and will soon be in master. I don't yet have the proxy middleware brought over to that branch but I will soon, and then these changes can possibly go on top.

@pwFoo
Copy link

pwFoo commented Jun 8, 2016

I use caddy as reverse proxy with docker-gen for my docker host and it works great. But etcd support sounds like a better solution. Can't wait to see this feature and the howto to use it ;)

@thalesfsp
Copy link

@mholt Whats the plan to when merge this PR?

@mholt
Copy link
Member

mholt commented Jun 11, 2016

I think it depends on @abiosoft's schedule.

@stp-ip
Copy link

stp-ip commented Jul 7, 2016

Would this lay the groundwork for caddy being able to supply an ingress service to kubernetes? As far as I see it... an ingress service is basically a dynamic proxy using the k8s apiserver instead of general key-value stores.

@thalesfsp
Copy link

@abiosoft @mholt What's the ETA to be merged?

@abiosoft
Copy link
Author

No ETAs, sorry. I plan to resume work on this after 0.9 :)

There is a very good chance it will make it in before 1.0 and could even be earlier depending on Caddy's priorities.

@hemsleyk
Copy link

A+

Would really help with Rancher / Kubernetes environments.

@pwFoo
Copy link

pwFoo commented Jul 28, 2016

Yes, would use it with rancher...

@thalesfsp
Copy link

@mholt @abiosoft 0.9 released ;)

@abiosoft
Copy link
Author

Okay, good news :)

Work is about to resume on this. However, I wanna make this a pluggable feature so proxy will only be making use of it, rather than having it built into proxy. This will make it easy to bring the feature to any other directive or plugin that needs it.

Still, no ETA 😄 but I will keep this thread updated.

@InAnimaTe
Copy link

@abiosoft great idea! much better and extensible way to implement.

Have you had anymore thoughts on implementation details? I'm wondering if it's not worth getting this working the original intended way (when you created this PR), and then move on to other ways later (since this PR is quite large both in conversation and commits).

Additionally, I've had some other ideas about how this could work based on other projects that have come along (i.e. Fabio, Traefik, etc..) and attempted to provide LE functionality with dynamic backends.

I would love to talk through some of this directly with you guys @abiosoft @faddat @stp-ip and others..
Seems to be a #caddy on freenode that I just joined. Ping me and we can chat (notifications go to my phone). Or maybe just create a new forum thread; whatever's easier.

@abiosoft
Copy link
Author

@InAnimaTe I'm rarely on irc :( What about Gopher's slack ?

@InAnimaTe
Copy link

@abiosoft That works! I just joined. Go ahead and make a channel and invite me plz ;)

@hazcod
Copy link

hazcod commented Dec 7, 2016

Is this PR still going? Also, will this support native docker swarm?

@faddat
Copy link
Contributor

faddat commented Dec 8, 2016 via email

@wendigo
Copy link

wendigo commented Dec 8, 2016

Maybe it is time to write it once again? :)

@hazcod
Copy link

hazcod commented Jan 3, 2017

I've put some thought in this and isn't it cleaner to do this via docker-gen ?
Altough I am unsure how it works for swarm/multiple hosts.

@mholt
Copy link
Member

mholt commented Jan 24, 2017

I think I'm going to close this PR -- it's almost a year old, but I hope it will soon make it to Caddy -- if not into core, then maybe it would do well as a plugin? Thanks for all the work you've put into it, @abiosoft, I hope we can use it someday. :)

@mholt mholt closed this Jan 24, 2017
@mholt mholt removed the discussion 💬 The right solution needs to be found label Jan 24, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet