-
Notifications
You must be signed in to change notification settings - Fork 504
Make k8s Ingress class used by Linkerd configurable (#1433) #1584
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
Make k8s Ingress class used by Linkerd configurable (#1433) #1584
Conversation
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.
⭐️ Looks good to me. Thanks for working on improving test coverage!
| import com.twitter.util.Future | ||
| import io.buoyant.test.Awaits | ||
| import org.scalatest.FunSuite | ||
| import com.twitter.finagle.http.{Request => FRequest, Response => FResponse} |
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.
TIOLI, but as far as I can tell, the renaming import shouldn't be necessary here?
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.
Indeed. I'm happy with keeping the name, but something for consideration: Because there are so many types called things like Request, Response, Logger, and Service in the classpath, at SoundCloud we had a convention that every time we imported one of those we'd rename it so that we could identify at a glance where it came from. e.g. we'd always do
import com.twitter.finagle.http.{Request => FinagleRequest, Response => FinagleResponse}
import com.soundcloud.ourinternalstuff.http.{Request => ScRequest, Response => ScResponse}But if we don't follow anything like this convention I'm happy to simplify.
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.
In general, I think our convention is to rename imports only when necessary. If you were importing both finagle.http.Request and a type from Linkerd called Request, then I think we would rename the type from Finagle. But in most of our code that I've seen where we don't have to deal with namespace clashes, we tend not to rename imports by default.
c343ed7 to
0006c5d
Compare
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.
General approach looks good.
| fail(s"unexpected request for [${req.uri}]: $req") | ||
| } | ||
|
|
||
| test("builds cache with the existing ingress if only one configured") { |
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.
Are these test names backwards? This test has many ingresses configured, right?
| assert(await(cache.matchPath(host, "/some-path")).get.svc == "echo") | ||
| assert(await(cache.matchPath(host, "/non-existing-path")).isEmpty) | ||
| } | ||
|
|
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.
should we also test the case where there are multiple ingresses with the linkerd class configured? Or is that tested elsewhere?
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.
Uh... good catch. I'll add the test.
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.
thanks for improving our test coverage!
| val service = mkIngressApiServiceReturning(ingressResourceListWithManyAnnotatedIngresses) | ||
| val cache = new IngressCache(None, service, annotationClass) | ||
| assert(await(cache.matchPath(host, "/istio-only")).isEmpty) | ||
| assert(await(cache.matchPath(host, "/ngix-only")).isEmpty) |
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'm a little confused why this path isn't matched, since I don't see a "kubernetes.io/ingress.class" specified for nginx-ingress, and we should still use the ingress if no ingress.class is specified.
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.
My understanding is that the way this should work is:
- If there is only one ingress resource, we use it
- If there are more than one ingress resources, we only use the one annotated with 'linkerd' (or whatever we configure it to be)
Do you think that on (2) we should also add and any other ingress resources without annotations?
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 see anything in the ingress resource spec that dictates controller annotation behavior. In lieu of a good spec, I try to follow other ingress controllers' behavior. So for traefik https://docs.traefik.io/user-guide/kubernetes/#excluding-an-ingress-from-trfik
You can control which ingress Træfik cares about by using the kubernetes.io/ingress.class annotation. By default if the annotation is not set at all Træfik will include the ingress. If the annotation is set to anything other than traefik or a blank string Træfik will ignore it.
and nginx https://github.com/kubernetes/ingress/tree/master/controllers/nginx
Setting the annotation kubernetes.io/ingress.class to any value other than "nginx" or the empty string, will force the NGINX Ingress controller to ignore your Ingress. Do this if you wish to use one of the other Ingress controllers at the same time as the NGINX controller.
| assert(await(cache.matchPath(host, "/linkerd-only")).get.svc == "echo") | ||
| } | ||
|
|
||
| test("builds cache with only valid ingresses when more than one configured") { |
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'm a bit confused about these test names. It seems like this is the test that tests a single configured ingress, whereas the test above is the one with "more than one [ingress class] configured".
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.
Yeah, I've flipped these by mistake :P
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.
Can't believe I missed that...thanks for fixing this, @pcalcado !
86cbfbd to
7de636e
Compare
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.
⭐ 🍣 Looks good to me!
| val service = mkIngressApiServiceReturning(ingressResourceListWithManyAnnotatedIngresses) | ||
| val cache = new IngressCache(None, service, annotationClass) | ||
| assert(await(cache.matchPath(host, "/istio-only")).isEmpty) | ||
| assert(await(cache.matchPath(host, "/ngix-only")).isEmpty) |
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.
looking at this line for another 10 seconds, I see there's a typo in nginx
|
If you're interested in adding tests for the config, I'd recommend writing a ConfigTest. We have a bunch of examples of this, eg https://github.com/linkerd/linkerd/blob/a9c1627d389fab206faac44d1f674695207ff5cd/namerd/storage/consul/src/test/scala/io/buoyant/namerd/storage/consul/ConsulConfigTest.scala |
76f58b9 to
221d343
Compare
221d343 to
6cac3df
Compare
| assert(await(cache.matchPath(host, "/linkerd-only")).get.svc == "echo") | ||
| } | ||
|
|
||
| test("when multiple ingress resources with desired annotation class, only adds the first one") { |
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 does not describe the behavior I expect to see. Linkerd IngressCache will add as many ingress resources as have correct annotations. Whether linkerd chooses to match to echo1 or echo2 is undefined in this case
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.
Aha! Now I understand what you meant earlier, thanks! I've changed it to match specific routes and to be more liberal on the shared one, given which Controller would be picked is undefined. wdyt?
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 looks great, thanks for all the updates!
6cac3df to
a3f82bb
Compare
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.
woop woop 🌟
## 1.2.0 2017-09-07 * **Breaking Change**: `io.l5d.mesh`, `io.l5d.thriftNameInterpreter`, linkerd admin, and namerd admin now serve on 127.0.0.1 by default (instead of 0.0.0.0). * **Breaking Change**: Removed support for PKCS#1-formatted keys. PKCS#1 formatted keys must be converted to PKCS#8 format. * Added experimental `io.l5d.dnssrv` namer for DNS SRV records (#1611) * Kubernetes * Added an experimental `io.l5d.k8s.configMap` interpreter for reading dtabs from a Kubernetes ConfigMap (#1603). This interpreter will respond to changes in the ConfigMap, allowing for dynamic dtab updates without the need to run Namerd. * Made ingress controller's ingress class annotation configurable (#1584). * Fixed an issue where Linkerd would continue routing traffic to endpoints of a service after that service was removed (#1622). * Major refactoring and performance improvements to `io.l5d.k8s` and `io.l5d.k8s.ns` namers (#1603). * Ingress controller now checks all available ingress resources before using a default backend (#1607). * Ingress controller now correctly routes requests with host headers that contain ports (#1607). * HTTP/2 * Fixed an issue where long-running H2 streams would eventually hang (#1598). * Fixed a memory leak on long-running H2 streams (#1598) * Added a user-friendly error message when a HTTP/2 router receives a HTTP/1 request (#1618) * HTTP/1 * Removed spurious `ReaderDiscarded` exception logged on HTTP/1 retries (#1609) * Consul * Added support for querying Consul by specific service health states (#1601) * Consul namers and Dtab store now fall back to a last known good state on Consul observation errors (#1597) * Improved log messages for Consul observation errors (#1597) * TLS * Removed support for PKCS#1 keys (#1590) * Added validation to prevent incompatible `disableValidation: true` and `clientAuth` settings in TLS client configurations (#1621) * Changed `io.l5d.mesh`, `io.l5d.thriftNameInterpreter`, linkerd admin, and namerd admin to serve on 127.0.0.1 by default (instead of 0.0.0.0) (#1366) * Deprecated `io.l5d.statsd` telemeter.
* Use url query params for tap/top form filters * Add comment explaining react-url-query onChange handlers Signed-off-by: Kevin Lingerfelt <[email protected]>
As per #1433 , sometimes one has many different Ingress Resource and Ingress Controller deployed. One common example seems to be when you have one Controller provided by a cloud (e.g. GCE), another one for Linkerd, and a third one provided by Istio. Linkerd, like most controllers, will ignore any Ingress Resource not meant for it, and the way to indicate which one is meant for Linkerds is by using the
kubernetes.io/ingress.classannotation.Initially, Linkerd would always look for any Ingress annotated as
linkerd. This change allows for users to configure what annotation value Linkerd should look for.