-
Notifications
You must be signed in to change notification settings - Fork 7.6k
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
Istio MCS Generating ServiceExports #29763
Conversation
😊 Welcome @josephpeacock! This is either your first contribution to the Istio istio repo, or it's been You can learn more about the Istio working groups, code of conduct, and contributing guidelines Thanks for contributing! Courtesy of your friendly welcome wagon. |
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.
From the implement, could not see when the serviceExport will be consumed and by who
@@ -3620,6 +3620,11 @@ rules: | |||
- apiGroups: [""] | |||
resources: ["secrets"] | |||
verbs: ["get", "watch", "list"] | |||
|
|||
#Used for MCS serviceexport management | |||
- apiGroups: [""] |
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 this in core group, i think it can not be.
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 unfamiliar with the manifests, could you recommend a more appropriate place?
#Used for MCS serviceexport management | ||
- apiGroups: [""] | ||
resources: ["serviceexports"] | ||
verbs: ["create", "delete"] |
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.
no get
list
needed?
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.
and watch, probably update and patch will be needed as well?
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 PR only needs create/delete on serviceexports. The eventual PR to consume them will likely need the ability to watch, but I want to add the minimal set of permissions necessary for this functionality.
queue queue.Instance | ||
serviceInformer cache.SharedInformer | ||
|
||
clusterLocalHosts []string //hosts marked as cluster-local, which will not have serviceeexports generated |
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.
what is this for, concerned about the peformance
return false | ||
} | ||
|
||
func (sc *ServiceExportController) createServiceExportIfNotPresent(service *v1.Service) error { |
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.
Who will consume the ServiceExports created 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.
The short answer is anyone will be able to. I'm working in parallel with @nmittler on the implementation of the Istio MCS RFC. I took "phase 2", and there is another issue open for "phase 1" (#29384)
The consumption of ServiceExports is out of scope for this PR.
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.
It is not clear how this works from the RFC, should wait for the draft implement.
As i read through the mcs-api desgin, it is not clear to me how this can solve multicluster topology issue.
Can you elaborate on how the EndpointSlice create is used? https://github.com/kubernetes/enhancements/tree/master/keps/sig-multicluster/1645-multi-cluster-services-api#importing-services
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.
The basic MCS flow is:
- Something generates a
ServiceExport
for a service in a cluster - The MCS controller (Istio?) sees the
ServiceExport
and createsServiceImport
andEndpointSlice
s in all of the other clusters in the clusterset (i.e. mesh). - In the other clusters, the
ServiceImport
andEndpointSlice
s are used by K8s to program kube proxy to allow service calls to span clusters.
What this PR is attempting to accomplish is 1. This simply creates the ServiceExport
resource ... it does nothing with EndpointSlice
s. This will have no real impact on the system if there is no MCS controller performing the ServiceImport
.
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 really understand why Istio is responsible for this. I presume MCSD will have multiple implementors, otherwise its not really useful. Will linkerd, consul, etc all be sending similar PRs, writing the same exact implementation of the same thing in 3 slightly different ways?
I would have expected the MCSD repo to have a controller, which is either deployed standalone, or maybe, once its past experimental, linked into Istiod as a library to reduce the deployment complexity.
I am a bit concerned that every project is going to implement the same controller slightly different and we will not actually have a consistent API like was desired.
#Used for MCS serviceexport management | ||
- apiGroups: [""] | ||
resources: ["serviceexports"] | ||
verbs: ["create", "delete"] |
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.
and watch, probably update and patch will be needed as well?
@@ -79,6 +79,14 @@ type Multicluster struct { | |||
secretNamespace string | |||
secretController *secretcontroller.Controller | |||
syncInterval time.Duration | |||
|
|||
//MCS Settings - settings for behavior of controllers relating to MCS | |||
mcsSettings *MCSSettings |
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.
nit: there is no need for this to be a pointer as far as I know
queue queue.Instance | ||
serviceInformer cache.SharedInformer | ||
|
||
clusterLocalHosts []string //hosts marked as cluster-local, which will not have serviceeexports generated |
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 am concerned about the API here. Why are we mixing an Istio API ("cluster local") with the MCSD api? Isn't the goal of MCSD that we are just another implementor?
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.
Isn't the goal of MCSD that we are just another implementor?
Yes, but one implementation detail that we get to determine is which services are exported (the API intentionally leaves that up to whatever entity is generating serviceExports). So we're piggybacking off of this Istio API with the assumption that cluster local hosts should not be exported for MCS.
|
||
_, err := sc.client.MulticlusterV1alpha1().ServiceExports(service.Namespace).Create(context.TODO(), &serviceExport, metav1.CreateOptions{}) | ||
|
||
if err != nil && strings.Contains(err.Error(), "already exists") { |
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.
nit: use errors.IsAlreadyExists
_, err := sc.client.MulticlusterV1alpha1().ServiceExports(service.Namespace).Create(context.TODO(), &serviceExport, metav1.CreateOptions{}) | ||
|
||
if err != nil && strings.Contains(err.Error(), "already exists") { | ||
err = nil //This is the error thrown by the client if there is already an object with the name in the namespace. If that's true, we do nothing |
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.
what if the contents are 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.
For this implementation, we are making the intentional choice that we don't care, and don't support cases in which some other entity (either human or 3rd party MCS controller) modifies a ServiceExport. So if it exists, we stop processing (to minimize cases where the other entity overwrite may be desired behavior).
} | ||
|
||
func (sc *ServiceExportController) doInitialFullSync() { | ||
allServices, err := sc.serviceClient.Services("").List(context.TODO(), metav1.ListOptions{}) |
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.
Calling .List() is not acceptable for performance, we should be using the informer cache. Direct API calls like this have bit us many times in the past
@howardjohn @hzxuzhonghu Maybe this is something we should discuss at the next Environments working group meeting? I was under the impression that the approved RFC represented an agreement that we were going to build the specified functionality into Istio. In meeting with @nmittler, we decided that phases one and two from that document could be done in parallel, and that I would put together a PR encompassing only stage two. I'm happy to shelve or permanently close this PR if it's agreed that building MCS functionality into Istio is the wrong direction for the project. You both had some very good specific feedback in the code as well, and I appreciate the prompt review. But I'd like for us to agree on the big picture direction before I spend more time rebasing and/or updating this PR. |
To clarify a bit. I am not *against* this, I am just not sure it's the
right thing to do without more info (answers to questions above about the
wider ecosystem). The RFC is a bit light on the details. Discussion in env
WG (or this PR) SGTM! Thanks for working on this
…On Mon, Jan 4, 2021 at 8:14 AM josephpeacock ***@***.***> wrote:
@howardjohn <https://github.com/howardjohn> @hzxuzhonghu
<https://github.com/hzxuzhonghu> Maybe this is something we should
discuss at the next Environments working group meeting? I was under the
impression that the approved RFC
<https://docs.google.com/document/d/1K8hvQ83UcJ9a7U8oqXIefwr6pFJn-VBEi40Ak-fwQtk/edit#heading=h.xw1gqgyqs5b>
represented an agreement that we were going to build the specified
functionality into Istio. In meeting with @nmittler
<https://github.com/nmittler>, we decided that phases one and two from
that document could be done in parallel, and that I would put together a PR
encompassing only stage two.
I'm happy to shelve or permanently close this PR if it's agreed that
building MCS functionality into Istio is the wrong direction for the
project. You both had some very good specific feedback in the code as well,
and I appreciate the prompt review. But I'd like for us to agree on the big
picture direction before I spend more time rebasing and/or updating this PR.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#29763 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAEYGXM5F5DUYPPLCJH24FTSYHSNPANCNFSM4VHOXF5Q>
.
|
Fair enough, let me answer the questions that I feel that I can speak to:
I think this is the intention of the k8s spec. They explicitly say in their document that anything should be able to be an MCS controller:
In this case, I'd argue it's a question of value-add. Do we see value in building out MCS controller functionality in Istio? (with the alternative being having users need to use another MCS controller in tandem with Istio if they want that functionality). And I do think being able to use service names to route across multiple clusters would really simplify some multicluster Istio installations.
The only official k8s MCS repo that I know of at the moment is for the MCS API. I don't know if there is a plan for an official k8s MCS controller, or if they are intending to leave it entirely up to the community.
You're probably right that there may be opportunities for a wider conversation about how specific the API is and should be moving forward on the k8s side. But I'm not sure if that's relevant to Istio's implementation, unless we want to wait to implement until the spec is more well-defined. |
pilot/pkg/bootstrap/options.go
Outdated
|
||
MCSServiceExportEnabled bool | ||
|
||
ClusterLocalHosts []string |
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.
Doesn't this duplicate the configuration in MeshConfig?
pilot/pkg/bootstrap/server.go
Outdated
@@ -232,6 +232,11 @@ func NewServer(args *PilotArgs) (*Server, error) { | |||
s.initMeshNetworks(args, s.fileWatcher) | |||
s.initMeshHandlers() | |||
|
|||
e.PushContext.Mesh = e.Mesh() | |||
args.RegistryOptions.ClusterLocalHosts = e.PushContext.GetClusterLocalHosts(e) |
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 meshconfig be updated?
return sc.deleteServiceExportIfPresent(obj) | ||
} | ||
|
||
func convertToService(obj interface{}) (*v1.Service, error) { |
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.
We do this elsewhere ... can we use a common function?
return cm, nil | ||
} | ||
|
||
func (sc *ServiceExportController) isServiceClusterLocal(service *v1.Service) bool { |
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 we move this function to the context?
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 not sure what you mean by this, can you clarify?
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.
The context is where you're getting information regarding cluster-local services. Could it just expose this method instead of defining it here?
//cannot use the auto-generated client as it hardcodes the namespace in the client struct, and we can't have one client per watched ns | ||
err := sc.client.MulticlusterV1alpha1().ServiceExports(service.Namespace).Delete(context.TODO(), service.Name, metav1.DeleteOptions{}) | ||
|
||
if err != nil && strings.Contains(err.Error(), "not found") { |
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 there a standard error here, similar to errors.IsAlreadyExists?
917fb42
to
937afc4
Compare
Ready for re-review. |
func (sc *ServiceExportController) createServiceExportIfNotPresent(service *v1.Service) error { | ||
serviceExport := v1alpha1.ServiceExport{} | ||
serviceExport.Namespace = service.Namespace | ||
serviceExport.Name = service.Name |
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.
Do you want to add an owner reference to this? This would also eliminate the need for handling deletions.
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.
That is actually something that is explicitly called out by the K8s MCS Spec, and was decided against. Instead, they chose to rely entirely on the name mapping. I tried to make this implementation match the spec as closely as possible.
1986696
to
10fa826
Compare
@josephpeacock: The following test failed, say
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
@josephpeacock thanks for all the help. I'm taking this over in #31401. Shall we just close this one out? |
Yup, let's do that. Thanks for taking this over! |
Taken over from istio#29763
Taken over from #29763 Co-authored-by: Joe Peacock <joe.peacock.joe@gmail.com>
This PR accomplishes stage 2 in the Istio MCS RFC
In short, it allows Istio to be configured to create ServiceExport objects for non cluster-local services in an Istio-managed cluster.
[ ] Configuration Infrastructure
[ ] Docs
[ ] Installation
[ X ] Networking
[ ] Performance and Scalability
[ ] Policies and Telemetry
[ ] Security
[ ] Test and Release
[ ] User Experience
[ ] Developer Infrastructure
Pull Request Attributes
Please check any characteristics that apply to this pull request.
[ ] Does not have any changes that may affect Istio users.