Skip to content

Commit e51632a

Browse files
M00nF1sholiviassss
authored andcommitted
add tags cache for elb (kubernetes-sigs#3550)
1 parent 2ca0a68 commit e51632a

File tree

6 files changed

+293
-21
lines changed

6 files changed

+293
-21
lines changed

controllers/ingress/group_controller.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,14 @@ const (
4646
func NewGroupReconciler(cloud aws.Cloud, k8sClient client.Client, eventRecorder record.EventRecorder,
4747
finalizerManager k8s.FinalizerManager, networkingSGManager networkingpkg.SecurityGroupManager,
4848
networkingSGReconciler networkingpkg.SecurityGroupReconciler, subnetsResolver networkingpkg.SubnetsResolver,
49-
controllerConfig config.ControllerConfig, backendSGProvider networkingpkg.BackendSGProvider,
49+
elbv2TaggingManager elbv2deploy.TaggingManager, controllerConfig config.ControllerConfig, backendSGProvider networkingpkg.BackendSGProvider,
5050
sgResolver networkingpkg.SecurityGroupResolver, logger logr.Logger) *groupReconciler {
5151

5252
annotationParser := annotations.NewSuffixAnnotationParser(annotations.AnnotationPrefixIngress)
5353
authConfigBuilder := ingress.NewDefaultAuthConfigBuilder(annotationParser)
5454
enhancedBackendBuilder := ingress.NewDefaultEnhancedBackendBuilder(k8sClient, annotationParser, authConfigBuilder, controllerConfig.IngressConfig.TolerateNonExistentBackendService, controllerConfig.IngressConfig.TolerateNonExistentBackendAction)
5555
referenceIndexer := ingress.NewDefaultReferenceIndexer(enhancedBackendBuilder, authConfigBuilder, logger)
5656
trackingProvider := tracking.NewDefaultProvider(ingressTagPrefix, controllerConfig.ClusterName)
57-
elbv2TaggingManager := elbv2deploy.NewDefaultTaggingManager(cloud.ELBV2(), cloud.VpcID(), controllerConfig.FeatureGates, cloud.RGT(), logger)
5857
modelBuilder := ingress.NewDefaultModelBuilder(k8sClient, eventRecorder,
5958
cloud.EC2(), cloud.ELBV2(), cloud.ACM(),
6059
annotationParser, subnetsResolver,
@@ -63,7 +62,7 @@ func NewGroupReconciler(cloud aws.Cloud, k8sClient client.Client, eventRecorder
6362
controllerConfig.DefaultSSLPolicy, controllerConfig.DefaultTargetType, backendSGProvider, sgResolver,
6463
controllerConfig.EnableBackendSecurityGroup, controllerConfig.DisableRestrictedSGRules, controllerConfig.FeatureGates.Enabled(config.EnableIPTargetType), logger)
6564
stackMarshaller := deploy.NewDefaultStackMarshaller()
66-
stackDeployer := deploy.NewDefaultStackDeployer(cloud, k8sClient, networkingSGManager, networkingSGReconciler,
65+
stackDeployer := deploy.NewDefaultStackDeployer(cloud, k8sClient, networkingSGManager, networkingSGReconciler, elbv2TaggingManager,
6766
controllerConfig, ingressTagPrefix, logger)
6867
classLoader := ingress.NewDefaultClassLoader(k8sClient, true)
6968
classAnnotationMatcher := ingress.NewDefaultClassAnnotationMatcher(controllerConfig.IngressConfig.IngressClass)

controllers/service/service_controller.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
"sigs.k8s.io/aws-load-balancer-controller/pkg/aws"
1515
"sigs.k8s.io/aws-load-balancer-controller/pkg/config"
1616
"sigs.k8s.io/aws-load-balancer-controller/pkg/deploy"
17-
"sigs.k8s.io/aws-load-balancer-controller/pkg/deploy/elbv2"
17+
elbv2deploy "sigs.k8s.io/aws-load-balancer-controller/pkg/deploy/elbv2"
1818
"sigs.k8s.io/aws-load-balancer-controller/pkg/deploy/tracking"
1919
"sigs.k8s.io/aws-load-balancer-controller/pkg/k8s"
2020
"sigs.k8s.io/aws-load-balancer-controller/pkg/model/core"
@@ -38,19 +38,18 @@ const (
3838
func NewServiceReconciler(cloud aws.Cloud, k8sClient client.Client, eventRecorder record.EventRecorder,
3939
finalizerManager k8s.FinalizerManager, networkingSGManager networking.SecurityGroupManager,
4040
networkingSGReconciler networking.SecurityGroupReconciler, subnetsResolver networking.SubnetsResolver,
41-
vpcInfoProvider networking.VPCInfoProvider, controllerConfig config.ControllerConfig,
41+
vpcInfoProvider networking.VPCInfoProvider, elbv2TaggingManager elbv2deploy.TaggingManager, controllerConfig config.ControllerConfig,
4242
backendSGProvider networking.BackendSGProvider, sgResolver networking.SecurityGroupResolver, logger logr.Logger) *serviceReconciler {
4343

4444
annotationParser := annotations.NewSuffixAnnotationParser(serviceAnnotationPrefix)
4545
trackingProvider := tracking.NewDefaultProvider(serviceTagPrefix, controllerConfig.ClusterName)
46-
elbv2TaggingManager := elbv2.NewDefaultTaggingManager(cloud.ELBV2(), cloud.VpcID(), controllerConfig.FeatureGates, cloud.RGT(), logger)
4746
serviceUtils := service.NewServiceUtils(annotationParser, serviceFinalizer, controllerConfig.ServiceConfig.LoadBalancerClass, controllerConfig.FeatureGates)
4847
modelBuilder := service.NewDefaultModelBuilder(annotationParser, subnetsResolver, vpcInfoProvider, cloud.VpcID(), trackingProvider,
4948
elbv2TaggingManager, cloud.EC2(), controllerConfig.FeatureGates, controllerConfig.ClusterName, controllerConfig.DefaultTags, controllerConfig.ExternalManagedTags,
5049
controllerConfig.DefaultSSLPolicy, controllerConfig.DefaultTargetType, controllerConfig.FeatureGates.Enabled(config.EnableIPTargetType), serviceUtils,
5150
backendSGProvider, sgResolver, controllerConfig.EnableBackendSecurityGroup, controllerConfig.DisableRestrictedSGRules)
5251
stackMarshaller := deploy.NewDefaultStackMarshaller()
53-
stackDeployer := deploy.NewDefaultStackDeployer(cloud, k8sClient, networkingSGManager, networkingSGReconciler, controllerConfig, serviceTagPrefix, logger)
52+
stackDeployer := deploy.NewDefaultStackDeployer(cloud, k8sClient, networkingSGManager, networkingSGReconciler, elbv2TaggingManager, controllerConfig, serviceTagPrefix, logger)
5453
return &serviceReconciler{
5554
k8sClient: k8sClient,
5655
eventRecorder: eventRecorder,

main.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package main
1818

1919
import (
2020
"os"
21+
elbv2deploy "sigs.k8s.io/aws-load-balancer-controller/pkg/deploy/elbv2"
2122

2223
"github.com/go-logr/logr"
2324
"github.com/spf13/pflag"
@@ -112,11 +113,12 @@ func main() {
112113
backendSGProvider := networking.NewBackendSGProvider(controllerCFG.ClusterName, controllerCFG.BackendSecurityGroup,
113114
cloud.VpcID(), cloud.EC2(), mgr.GetClient(), controllerCFG.DefaultTags, ctrl.Log.WithName("backend-sg-provider"))
114115
sgResolver := networking.NewDefaultSecurityGroupResolver(cloud.EC2(), cloud.VpcID())
116+
elbv2TaggingManager := elbv2deploy.NewDefaultTaggingManager(cloud.ELBV2(), cloud.VpcID(), controllerCFG.FeatureGates, cloud.RGT(), ctrl.Log)
115117
ingGroupReconciler := ingress.NewGroupReconciler(cloud, mgr.GetClient(), mgr.GetEventRecorderFor("ingress"),
116-
finalizerManager, sgManager, sgReconciler, subnetResolver,
118+
finalizerManager, sgManager, sgReconciler, subnetResolver, elbv2TaggingManager,
117119
controllerCFG, backendSGProvider, sgResolver, ctrl.Log.WithName("controllers").WithName("ingress"))
118120
svcReconciler := service.NewServiceReconciler(cloud, mgr.GetClient(), mgr.GetEventRecorderFor("service"),
119-
finalizerManager, sgManager, sgReconciler, subnetResolver, vpcInfoProvider,
121+
finalizerManager, sgManager, sgReconciler, subnetResolver, vpcInfoProvider, elbv2TaggingManager,
120122
controllerCFG, backendSGProvider, sgResolver, ctrl.Log.WithName("controllers").WithName("service"))
121123
tgbReconciler := elbv2controller.NewTargetGroupBindingReconciler(mgr.GetClient(), mgr.GetEventRecorderFor("targetGroupBinding"),
122124
finalizerManager, tgbResManager,

pkg/deploy/elbv2/tagging_manager.go

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ package elbv2
22

33
import (
44
"context"
5+
"sync"
6+
"time"
7+
8+
"k8s.io/apimachinery/pkg/util/cache"
59

610
awssdk "github.com/aws/aws-sdk-go/aws"
711
elbv2sdk "github.com/aws/aws-sdk-go/service/elbv2"
@@ -18,6 +22,8 @@ import (
1822
const (
1923
// ELBV2 API supports up to 20 resource per DescribeTags API call.
2024
defaultDescribeTagsChunkSize = 20
25+
// cache ttl for tags on ELB resources.
26+
defaultResourceTagsCacheTTL = 20 * time.Minute
2127
)
2228

2329
// LoadBalancer with it's tags.
@@ -103,6 +109,8 @@ func NewDefaultTaggingManager(elbv2Client services.ELBV2, vpcID string, featureG
103109
featureGates: featureGates,
104110
logger: logger,
105111
describeTagsChunkSize: defaultDescribeTagsChunkSize,
112+
resourceTagsCache: cache.NewExpiring(),
113+
resourceTagsCacheTTL: defaultResourceTagsCacheTTL,
106114
rgt: rgt,
107115
}
108116
}
@@ -117,7 +125,11 @@ type defaultTaggingManager struct {
117125
featureGates config.FeatureGates
118126
logger logr.Logger
119127
describeTagsChunkSize int
120-
rgt services.RGT
128+
// cache for tags on ELB resources.
129+
resourceTagsCache *cache.Expiring
130+
resourceTagsCacheTTL time.Duration
131+
resourceTagsCacheMutex sync.RWMutex
132+
rgt services.RGT
121133
}
122134

123135
func (m *defaultTaggingManager) ReconcileTags(ctx context.Context, arn string, desiredTags map[string]string, opts ...ReconcileTagsOption) error {
@@ -128,7 +140,7 @@ func (m *defaultTaggingManager) ReconcileTags(ctx context.Context, arn string, d
128140
reconcileOpts.ApplyOptions(opts)
129141
currentTags := reconcileOpts.CurrentTags
130142
if currentTags == nil {
131-
tagsByARN, err := m.describeResourceTagsNative(ctx, []string{arn})
143+
tagsByARN, err := m.describeResourceTags(ctx, []string{arn})
132144
if err != nil {
133145
return err
134146
}
@@ -153,6 +165,7 @@ func (m *defaultTaggingManager) ReconcileTags(ctx context.Context, arn string, d
153165
if _, err := m.elbv2Client.AddTagsWithContext(ctx, req); err != nil {
154166
return err
155167
}
168+
m.invalidateResourceTagsCache(arn)
156169
m.logger.Info("added resource tags",
157170
"arn", arn)
158171
}
@@ -170,6 +183,7 @@ func (m *defaultTaggingManager) ReconcileTags(ctx context.Context, arn string, d
170183
if _, err := m.elbv2Client.RemoveTagsWithContext(ctx, req); err != nil {
171184
return err
172185
}
186+
m.invalidateResourceTagsCache(arn)
173187
m.logger.Info("removed resource tags",
174188
"arn", arn)
175189
}
@@ -193,7 +207,7 @@ func (m *defaultTaggingManager) ListListeners(ctx context.Context, lbARN string)
193207
}
194208
var tagsByARN map[string]map[string]string
195209
if m.featureGates.Enabled(config.ListenerRulesTagging) {
196-
tagsByARN, err = m.describeResourceTagsNative(ctx, lsARNs)
210+
tagsByARN, err = m.describeResourceTags(ctx, lsARNs)
197211
if err != nil {
198212
return nil, err
199213
}
@@ -226,7 +240,7 @@ func (m *defaultTaggingManager) ListListenerRules(ctx context.Context, lsARN str
226240
}
227241
var tagsByARN map[string]map[string]string
228242
if m.featureGates.Enabled(config.ListenerRulesTagging) {
229-
tagsByARN, err = m.describeResourceTagsNative(ctx, lrARNs)
243+
tagsByARN, err = m.describeResourceTags(ctx, lrARNs)
230244
if err != nil {
231245
return nil, err
232246
}
@@ -242,6 +256,7 @@ func (m *defaultTaggingManager) ListListenerRules(ctx context.Context, lsARN str
242256
return sdkLRs, err
243257
}
244258

259+
// TODO: we can refactor this by store provisioned LB's ARN as annotations on Ingress/Service, thus avoid this heavy lookup calls when RGT is not available.
245260
func (m *defaultTaggingManager) ListLoadBalancers(ctx context.Context, tagFilters ...tracking.TagFilter) ([]LoadBalancerWithTags, error) {
246261
if m.featureGates.Enabled(config.EnableRGTAPI) {
247262
return m.listLoadBalancersRGT(ctx, tagFilters)
@@ -254,7 +269,6 @@ func (m *defaultTaggingManager) ListTargetGroups(ctx context.Context, tagFilters
254269
return m.listTargetGroupsRGT(ctx, tagFilters)
255270
}
256271
return m.listTargetGroupsNative(ctx, tagFilters)
257-
258272
}
259273

260274
func (m *defaultTaggingManager) listLoadBalancersRGT(ctx context.Context, tagFilters []tracking.TagFilter) ([]LoadBalancerWithTags, error) {
@@ -311,7 +325,7 @@ func (m *defaultTaggingManager) listLoadBalancersNative(ctx context.Context, tag
311325
lbARNsWithinVPC = append(lbARNsWithinVPC, lbARN)
312326
lbByARNWithinVPC[lbARN] = lb
313327
}
314-
tagsByARN, err := m.describeResourceTagsNative(ctx, lbARNsWithinVPC)
328+
tagsByARN, err := m.describeResourceTags(ctx, lbARNsWithinVPC)
315329
if err != nil {
316330
return nil, err
317331
}
@@ -391,7 +405,7 @@ func (m *defaultTaggingManager) listTargetGroupsNative(ctx context.Context, tagF
391405
tgARNsWithinVPC = append(tgARNsWithinVPC, tgARN)
392406
tgByARNWithinVPC[tgARN] = tg
393407
}
394-
tagsByARN, err := m.describeResourceTagsNative(ctx, tgARNsWithinVPC)
408+
tagsByARN, err := m.describeResourceTags(ctx, tgARNsWithinVPC)
395409
if err != nil {
396410
return nil, err
397411
}
@@ -416,9 +430,34 @@ func (m *defaultTaggingManager) listTargetGroupsNative(ctx context.Context, tagF
416430
return matchedTGs, nil
417431
}
418432

419-
// describeResourceTagsNative describes tags for elbv2 resources.
433+
func (m *defaultTaggingManager) describeResourceTags(ctx context.Context, arns []string) (map[string]map[string]string, error) {
434+
m.resourceTagsCacheMutex.Lock()
435+
defer m.resourceTagsCacheMutex.Unlock()
436+
437+
tagsByARN := make(map[string]map[string]string, len(arns))
438+
var arnsWithoutTagsCache []string
439+
for _, arn := range arns {
440+
if rawTagsCacheItem, exists := m.resourceTagsCache.Get(arn); exists {
441+
tagsCacheItem := rawTagsCacheItem.(map[string]string)
442+
tagsByARN[arn] = tagsCacheItem
443+
} else {
444+
arnsWithoutTagsCache = append(arnsWithoutTagsCache, arn)
445+
}
446+
}
447+
tagsByARNFromAWS, err := m.describeResourceTagsFromAWS(ctx, arnsWithoutTagsCache)
448+
if err != nil {
449+
return nil, err
450+
}
451+
for arn, tags := range tagsByARNFromAWS {
452+
m.resourceTagsCache.Set(arn, tags, m.resourceTagsCacheTTL)
453+
tagsByARN[arn] = tags
454+
}
455+
return tagsByARN, nil
456+
}
457+
458+
// describeResourceTagsFromAWS describes tags for elbv2 resources.
420459
// returns tags indexed by resource ARN.
421-
func (m *defaultTaggingManager) describeResourceTagsNative(ctx context.Context, arns []string) (map[string]map[string]string, error) {
460+
func (m *defaultTaggingManager) describeResourceTagsFromAWS(ctx context.Context, arns []string) (map[string]map[string]string, error) {
422461
tagsByARN := make(map[string]map[string]string, len(arns))
423462
arnsChunks := algorithm.ChunkStrings(arns, m.describeTagsChunkSize)
424463
for _, arnsChunk := range arnsChunks {
@@ -436,6 +475,13 @@ func (m *defaultTaggingManager) describeResourceTagsNative(ctx context.Context,
436475
return tagsByARN, nil
437476
}
438477

478+
func (m *defaultTaggingManager) invalidateResourceTagsCache(arn string) {
479+
m.resourceTagsCacheMutex.Lock()
480+
defer m.resourceTagsCacheMutex.Unlock()
481+
482+
m.resourceTagsCache.Delete(arn)
483+
}
484+
439485
// convert tags into AWS SDK tag presentation.
440486
func convertTagsToSDKTags(tags map[string]string) []*elbv2sdk.Tag {
441487
if len(tags) == 0 {

0 commit comments

Comments
 (0)