8000 Uncomment EndpointSliceAccess function by mateiidavid · Pull Request #4760 · linkerd/linkerd2 · GitHub
[go: up one dir, main page]

Skip to content

Uncomment EndpointSliceAccess function - #4760

Merged
adleong merged 1 commit into
linkerd:mainfrom
mateiidavid:enable-endpoint-slices
Jul 20, 2020
Merged

adleong merged 1 commit into
linkerd:mainfrom
mateiidavid:enable-endpoint-slices

Conversation

@mateiidavid
@mateiidavid mateiidavid commented Jul 15, 2020 •
Copy link
Copy Markdown
Contributor 10BC8

What


Tests


  • Although I haven't extensively tested all edge cases in the context of this PR, I did test that everything comes together nicely. To this, may approach has been:
    • Test how the flag behaves when we have (and don't have) support for slices in the cluster;
    • Test how the destination service behaves in combination with the flag and feature gate.

I tested a total of three broad scenarios:

  1. When minikube has no EndpointSlices:
# install should fail when flag is enabled
$ target/cli/darwin/linkerd install --enable-endpoint-slices
# output
Error: --enableEndpointSlice=true not supported: no EndpointSlice resources exist in the cluster

# install should succeed when flag disabled
# everything should work as normal
# dest service should watch endpoints
$ k logs <dest-service-pod> -f destination
#output
ime="2020-07-15T19:40:22Z" level=debug msg="Watching Endpoints resources" addr=":8086" component=endpoints-watcher
time="2020-07-15T19:40:22Z" level=info msg="waiting for caches to sync"
I0715 19:40:22.143369       1 reflector.go:150] Starting reflector *v1.Service (10m0s) from pkg/mod/k8s.io/client-go@v0.17.4/tools/cache/reflector.go:105
  • When the flag is disabled, works as expected, when flag is enabled, works as expected.
  • No hanging on syncing cache, not watching wrong resource.
  1. When minikube has EndpointSlice support, but not Linkerd installed with EndpointSlice support:
# Install should succeed
$ target/cli/darwin/linkerd install
# Output:
<installed successfully>

# Destination service should watch Endpoints
# shouldn't crash, shouldn't hang on informer syncing:
$ k logs <dest-service-pod> -f destination
# Output:
time="2020-07-15T20:09:44Z" level=debug msg="Watching Endpoints resources" addr=":8086" component=endpoints-watcher
time="2020-07-15T20:09:44Z" level=info msg="waiting for caches to sync"
<starting reflector> # forgot to copy line
# more logs in between
time="2020-07-15T20:34:05Z" level=debug msg="Sending destination add: add:{addrs:{addr:{ip:{ipv4:2886795270}  port:9996}  weight:10000}}" addr=":8086" component=endpoint-translator remote="127.0.0.1:49108" service="172.17.0.6:9996"
  • When installed in a cluster with EndpointSlice support but without support in Linkerd, the right resource is watched
  • No errors, no hanging on cache syncing
  1. When minikube has EndpointSlice support, with Linkerd installed with EndpointSlice support:
# Install should succeed (resource active in cluster)
$ target/cli/darwin/linkerd install --enable-endpoint-slices
# Output:
<installed successfully>

# Destination service should watch slices
# shouldn't error out, should transmit updates to other control plane
# components (i.e finding endpoints in slices)
$ k logs <dest-service-pod> -f destination
# Output:
time="2020-07-15T20:12:09Z" level=debug msg="Watching EndpointSlice resources" addr=":8086" component=endpoints-watcher
time="2020-07-15T20:12:09Z" level=info msg="waiting for caches to sync"
I0715 20:12:09.463803       1 reflector.go:150] Starting reflector *v1.Pod (10m0s) from pkg/mod/k8s.io/client-go@v0.17.4/tools/cache/reflector.go:105

time="2020-07-15T20:12:09Z" level=debug msg="Adding EndpointSlice for linkerd/linkerd-dst" addr=":8086" component=service-publisher ns=linkerd svc=linkerd-dst
time="2020-07-15T20:12:09Z" level=debug msg="Adding EndpointSlice for linkerd/linkerd-sp-validator" addr=":8086" component=service-publisher ns=linkerd svc=linkerd-sp-validator
# ... extra logs in between
time="2020-07-15T20:12:20Z" level=debug msg="Sending destination add: add:{addrs:{addr:{ip:{ipv4:2886795273}  port:4191}  weight:10000  metric_labels:{key}
  • Everything works as expected, no nasty errors, destination messages are being sent to the proxy

My conclusion is that at first glance everything seems to be working well enough to have them enabled for experimental use. The same messages are being sent as for the Endpoints resource, the flag does a well enough job of preventing installation when the resource does not exist and a well enough job of allowing the installation to proceed when the access criteria is met.

Signed-off-by: Matei David matei.david.35@gmail.com

Signed-off-by: Matei David <matei.david.35@gmail.com>
@mateiidavid
mateiidavid requested a review from a team as a code owner July 15, 2020 20:35
@adleong adleong left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In your example 3 you install linkerd with target/cli/darwin/linkerd install. I don't see the endpoint slices flag there so I would expect Linkerd to use Endpoints.

Comment thread pkg/k8s/authz.go
//
// return errors.New("no EndpointSlice resources exist in the cluster")
//}
func checkEndpointSlicesExist(k8sClient kubernetes.Interface) error {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This prevents EndpointSlices mode from being enabled if there are no EndpointSlices resources in the cluster.

Essentially, we're using the existence of an EndpointSlice as a proxy for if the cluster has enabled the EndpointSlices controller. But I wonder if this is actually always correct. Is it possible for EndpointSlices controller to be enabled on the cluster, but for no EndpointSlices resources to exist? Typically there will be services in the kube-system namespace that will have EndpointsSlices, but can we always rely on this? What if all of those services were deleted? Are there kubernetes distributions that don't create any services by default?

I'm on the fence about this but I'm leaning towards removing this check. The downside to removing it is that it opens the door for users to shoot themselves in the foot by enabling EndpointSlices mode in Linkerd for clusters that have the EndpointSlices resource type but don't run the EndpointSlices controller. The upside is that we don't have to worry about install failing if a cluster somehow has no EndpointSlices resources.

@mateiidavid mateiidavid Jul 16, 2020 •
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is a very good point @adleong and I'm happy it's been brought up. I was going to argue for the opposite actually; I think we should only check for the existence of an EndpointSlice in the cluster rather than only check if the resource exists, or rather than checking for both. I'll describe my thoughts below, let me know how you feel about it and what you think.

First, I agree that using the existence of an EndpointSlice as a proxy for the controller's enablement involves a high degree of uncertainty -- we have no way of knowing for sure whether kube-system namespace will have any EndpointSlices, or whether the services even exists to begin with. One recurring EndpointSlice however that should exist when the controller is turned on, is the slice for thekubernetes service. This is just an assumption on my side, but even if all of the kube-system services are deleted or non-existent, the kubernetes service should still be created?

I find it that it's more likely for people to shoot themselves in the foot or experience undefined behaviour, especially when they run k8s v1.18.0+ if we check whether the resource exists in the cluster. Again, this is an assumption, but since slices are enabled by default, if the slice controller is turned off it means it has been turned off intentionally. Moreover, in this scenario if for whatever reason the flag has been turned on without checking for existence of at least an EndpointSlice, the destination service will just crash (since the resource will have been created in the cluster but the controller is off). I'm not sure how likely this scenario is, but this is what has been in the back of my mind when working on this.

To have a tl;dr:

The upside is that we don't have to worry about install failing if a cluster somehow has no EndpointSlices resources
I find it more likely that there will exist a resource in the cluster especially in the newer versions of k8s and we should treat the controller as the source of the truth rather than the resource itself.

On the other hand, I see your point. I think if we remove this check we mitigate some of the risk that stems from the uncertainty you have described. In my mind, removing this check gives us a more predictive feel for how the EndpointSlices should work -- if the cluster supports the resource and you have enabled the flag, then that's what the destination service will use. I think this makes the assumption that users will be more responsible in knowing what the feature does and in adopting the feature. However, we can't always guarantee that if the resource exists, the slices are created -- I see more room for failure here.

If I had to take my chances between a user mistake and a cluster bootstrapping and/or service failure though, I'd go for the user making a mistake; it is more likely that the operator will miss something (self-evident from me pasting the wrong logs in this PR!) but I have seen an increasing amount of people rooting for the ability to do whatever they want.

I hope this point of view makes sense in the context you brought up, I might just be scratching the surface here but I thought I'd weigh in. Another option is to keep both in, of course. Excuse my inexperienced point of view if my worries are unfounded! :)

I'd like to also get your input on this @zaharidichev since you have reviewed the previous PR about adding EndpointSlices to the destination service.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the thoughtful and articulate response, @Matei207. I think you're right. It does seem reasonably safe to assume that the kubernetes service should always exist and have an endpoints (or EndpointSlices) object. So I'm on board with making this the source of truth.

You also mention potentially removing the check to see if the resource type exists. My question is: what happens on clusters that do not have the EndpointSlices resource type? If the EndpointSlices list simply fails with an error that we can handle and interpret to mean that EndpointSlices should be disabled, that's great. If this causes a panic or a hang, then I don't think we can remove the check.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

My question is: what happens on clusters that do not have the EndpointSlices resource type

Hmm, hate to disappoint after receiving compliments for my previous answer but I haven't given this much thought. I'm not 100% sure, but in the case that the resource does not exist, the error message would just be a NotFound. I think under the hood client-go makes REST calls to the apiserver. By this logic, trying to list the resource would give a 404.

I imagine the error would look similar to these logs (taken from a support question slack):

go@v0.17.4/tools/cache/reflector.go:105: Failed to list *v1beta1.EndpointSlice: the server could not find the requested resource

N.B in the logs above the k8s version was v1.14.0.

I'm not sure if the same would be thrown when directly trying to list the slices, that was an error propagated by an informer so the behaviour might be different. At the same time, the only reason I'd advocate for removing the check is to avoid making two calls; not sure how expensive the calls client-go makes are, but if they're not excessively detrimental to the performance I'm leaning more towards the side of safety. It also looks idiomatic to me and easier to figure out what's going on if we keep both in.

@mateiidavid
Copy link
Copy Markdown
Contributor Author

@adleong sorry about that, I think I made a typo when I copied the logs from my notes. I'll add some pictures with timestamps to show you the output of the commands just to be sure:
Screen Shot 2020-07-16 at 1 08 38 AM
Screen Shot 2020-07-16 at 1 09 08 AM

Will edit the body of the PR so it's not misleading.

@adleong adleong left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎉 👣 🔪

@zaharidichev zaharidichev left a comment
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That all makes sense! Thanks for the extra detail!

@adleong adleong changed the title service topologies: final step for EndpointSlices Uncomment EndpointSliceAccess function Jul 20, 2020
@adleong
adleong merged commit 146c593 into linkerd:main Jul 20, 2020
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.

3 participants

0