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

feat(kuma-cp) multiple outbound tags #831

Merged
merged 7 commits into from
Jun 17, 2020
Merged

Conversation

jakubdyszkiewicz
Copy link
Contributor

Summary

This PR introduces support for multiple tags in outbound section.
so instead of

outbound:
- port: 1234
  service: backend

we've got

outbound:
- port: 1234
  tags:
    service: backend

many tags are supported here, but service is required.

I introduced backward compatibility just like we did with "interface" field, meaning user can still use "service" field.

Additionally, this PR refactors TrafficRoute to use builtin mechanism in Envoy for such functionallity called load balancing subsets.
Every endpoint has metadata with tags. When we generate TCP Proxy or route for HTTP Connection Manager we can use Weighted Clusters providing metadata.
For this funcionallity to work, we need lb split settings on cluster.

On top of that, OutboundProxyGenerator was getting really big so I split it into many functions.

Documentation

  • In progress

@jakubdyszkiewicz jakubdyszkiewicz requested a review from a team June 15, 2020 10:49
Copy link
Contributor

@nickolaev nickolaev left a comment

Choose a reason for hiding this comment

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

Looks very impressive!

Makefile.e2e.mk Show resolved Hide resolved
@@ -14,7 +14,9 @@ spec:
outbound:
- address: 10.108.144.24
port: 443
service: test-app.playground.svc:443
tags:
service: test-app.playground.svc:443
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess test-app_playground_svc_443?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, but I don't want to introduce it in this PR.

pkg/xds/envoy/listeners/tcp_proxy_configurer_test.go Outdated Show resolved Hide resolved
var selectors []*envoy_api.Cluster_LbSubsetConfig_LbSubsetSelector
subsets := map[string]bool{} // we only need unique subsets
for _, tags := range e.tags {
keys := tags.WithoutTag(v1alpha1.ServiceTag).Keys() // service tag is not included in metadata
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you please use alias mesh_proto.ServiceTag?

@@ -47,16 +46,17 @@ func (c *TcpProxyConfigurer) tcpProxy() *envoy_tcp.TcpProxy {
proxy := envoy_tcp.TcpProxy{
StatPrefix: util_xds.SanitizeMetric(c.statsName),
}
if len(c.clusters) == 1 {
if len(c.clusters) == 1 && envoy_common.Metadata(c.clusters[0].Tags) == nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably makes sense to check len(c.cluster[0].Tags) == 0. If Tags is nil that expression also will be true. But it covers case when Tags is empty map. I think we don't want to generate TcpProxy_WeightedCluster_ClusterWeight with empty Tags map

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You may want to generate TcpProxy_WeightedCluster_ClusterWeight with empty tags map. TrafficRoute from web to backend with split 50% to backend and 50% to backend-api (different name, but without tags).

@@ -44,16 +44,17 @@ type RouteConfigurer struct {

func (c RouteConfigurer) routeAction() *envoy_route.RouteAction {
routeAction := envoy_route.RouteAction{}
if len(c.clusters) == 1 {
if len(c.clusters) == 1 && envoy_common.Metadata(c.clusters[0].Tags) == nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

And probably the same here?

for _, outbound := range outbounds {
// Determine the list of destination clusters
// For one outbound listener it may contain many clusters (ex. TrafficRoute to many destinations)
clusters, err := g.determineClusters(proxy, outbound)
Copy link
Contributor

Choose a reason for hiding this comment

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

clusters and allClusters are not mapped to Envoy clusters 1 to 1, maybe make sense to consider renaming to subset or something like that

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, changed ClusterInfo to ClusterSubsets. and ClusterInfo#Name to ClusterSubset#ClusterName. I think it make more sense now.

func (_ OutboundProxyGenerator) generateEDS(proxy *model.Proxy, clusters envoy_common.Clusters) model.ResourceSet {
var resources model.ResourceSet
for _, clusterName := range clusters.ClusterNames() {
serviceName := clusters.Tags(clusterName)[0][kuma_mesh.ServiceTag]
Copy link
Contributor

Choose a reason for hiding this comment

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

Does serviceName equal to clusterName?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For now it does, but just for safety I don't want to make this assumption.

@nickolaev nickolaev requested a review from lobkovilya June 16, 2020 17:40
func (_ OutboundProxyGenerator) generateEds(ctx xds_context.Context, proxy *model.Proxy, clusters []envoy_common.ClusterInfo) (resources []*model.Resource, allEndpoints []model.Endpoint, _ error) {
for _, cluster := range clusters {
serviceName := cluster.Tags[kuma_mesh.ServiceTag]
func (_ OutboundProxyGenerator) generateCDS(ctx xds_context.Context, proxy *model.Proxy, clusters envoy_common.Clusters) (model.ResourceSet, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

When it comes to acronyms I thought we always make just the first letter capital. But I know that according to a convention - https://github.com/golang/go/wiki/CodeReviewComments#initialisms, letters should be in a consistent case. So do we want to follow it everywhere now?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, that's why I changed generateEds to generateEDS

@jakubdyszkiewicz jakubdyszkiewicz merged commit 971c1a7 into master Jun 17, 2020
@jakubdyszkiewicz jakubdyszkiewicz deleted the feat/outbound-tags branch October 15, 2020 11:54
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