Skip to content

Commit 9700d0e

Browse files
committed
add metrics to track the managed resource count
1 parent 227315a commit 9700d0e

13 files changed

+270
-26
lines changed

Diff for: config/webhook/manifests.yaml

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
---
21
apiVersion: admissionregistration.k8s.io/v1
32
kind: MutatingWebhookConfiguration
43
metadata:

Diff for: docs/install/iam_policy.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242
"elasticloadbalancing:DescribeTags",
4343
"elasticloadbalancing:DescribeTrustStores",
4444
"elasticloadbalancing:DescribeListenerAttributes",
45-
"elasticloadbalancing:DescribeCapacityReservation"
45+
"elasticloadbalancing:DescribeCapacityReservation",
46+
"tag:GetResources"
4647
],
4748
"Resource": "*"
4849
},

Diff for: docs/install/iam_policy_cn.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242
"elasticloadbalancing:DescribeTags",
4343
"elasticloadbalancing:DescribeTrustStores",
4444
"elasticloadbalancing:DescribeListenerAttributes",
45-
"elasticloadbalancing:DescribeCapacityReservation"
45+
"elasticloadbalancing:DescribeCapacityReservation",
46+
"tag:GetResources"
4647
],
4748
"Resource": "*"
4849
},

Diff for: docs/install/iam_policy_iso.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
"elasticloadbalancing:DescribeTargetGroups",
4040
"elasticloadbalancing:DescribeTargetGroupAttributes",
4141
"elasticloadbalancing:DescribeTargetHealth",
42-
"elasticloadbalancing:DescribeTags"
42+
"elasticloadbalancing:DescribeTags",
43+
"tag:GetResources"
4344
],
4445
"Resource": "*"
4546
},

Diff for: docs/install/iam_policy_isob.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
"elasticloadbalancing:DescribeTargetGroups",
4040
"elasticloadbalancing:DescribeTargetGroupAttributes",
4141
"elasticloadbalancing:DescribeTargetHealth",
42-
"elasticloadbalancing:DescribeTags"
42+
"elasticloadbalancing:DescribeTags",
43+
"tag:GetResources"
4344
],
4445
"Resource": "*"
4546
},

Diff for: docs/install/iam_policy_isoe.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
"elasticloadbalancing:DescribeTargetGroups",
4040
"elasticloadbalancing:DescribeTargetGroupAttributes",
4141
"elasticloadbalancing:DescribeTargetHealth",
42-
"elasticloadbalancing:DescribeTags"
42+
"elasticloadbalancing:DescribeTags",
43+
"tag:GetResources"
4344
],
4445
"Resource": "*"
4546
},

Diff for: docs/install/iam_policy_isof.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
"elasticloadbalancing:DescribeTargetGroups",
4040
"elasticloadbalancing:DescribeTargetGroupAttributes",
4141
"elasticloadbalancing:DescribeTargetHealth",
42-
"elasticloadbalancing:DescribeTags"
42+
"elasticloadbalancing:DescribeTags",
43+
"tag:GetResources"
4344
],
4445
"Resource": "*"
4546
},

Diff for: docs/install/iam_policy_us-gov.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242
"elasticloadbalancing:DescribeTags",
4343
"elasticloadbalancing:DescribeTrustStores",
4444
"elasticloadbalancing:DescribeListenerAttributes",
45-
"elasticloadbalancing:DescribeCapacityReservation"
45+
"elasticloadbalancing:DescribeCapacityReservation",
46+
"tag:GetResources"
4647
],
4748
"Resource": "*"
4849
},

Diff for: main.go

+28-7
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,24 @@ limitations under the License.
1717
package main
1818

1919
import (
20-
"k8s.io/client-go/util/workqueue"
21-
"os"
22-
23-
elbv2deploy "sigs.k8s.io/aws-load-balancer-controller/pkg/deploy/elbv2"
24-
2520
"github.com/go-logr/logr"
2621
"github.com/spf13/pflag"
2722
zapraw "go.uber.org/zap"
2823
k8sruntime "k8s.io/apimachinery/pkg/runtime"
2924
"k8s.io/client-go/kubernetes"
3025
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
3126
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
27+
"k8s.io/client-go/util/workqueue"
3228
"k8s.io/klog/v2"
29+
"os"
3330
elbv2api "sigs.k8s.io/aws-load-balancer-controller/apis/elbv2/v1beta1"
3431
elbv2controller "sigs.k8s.io/aws-load-balancer-controller/controllers/elbv2"
3532
"sigs.k8s.io/aws-load-balancer-controller/controllers/ingress"
3633
"sigs.k8s.io/aws-load-balancer-controller/controllers/service"
3734
"sigs.k8s.io/aws-load-balancer-controller/pkg/aws"
3835
"sigs.k8s.io/aws-load-balancer-controller/pkg/aws/throttle"
3936
"sigs.k8s.io/aws-load-balancer-controller/pkg/config"
37+
elbv2deploy "sigs.k8s.io/aws-load-balancer-controller/pkg/deploy/elbv2"
4038
"sigs.k8s.io/aws-load-balancer-controller/pkg/inject"
4139
"sigs.k8s.io/aws-load-balancer-controller/pkg/k8s"
4240
awsmetrics "sigs.k8s.io/aws-load-balancer-controller/pkg/metrics/aws"
@@ -84,8 +82,6 @@ func main() {
8482
klog.SetLoggerWithOptions(appLogger, klog.ContextualLogger(true))
8583

8684
var awsMetricsCollector *awsmetrics.Collector
87-
lbcMetricsCollector := lbcmetrics.NewCollector(metrics.Registry)
88-
8985
if metrics.Registry != nil {
9086
awsMetricsCollector = awsmetrics.NewCollector(metrics.Registry)
9187
}
@@ -107,6 +103,17 @@ func main() {
107103
os.Exit(1)
108104
}
109105

106+
// track the k8s resources with finalizers contains "k8s.aws"
107+
// track the aws resources with cluster tag "elbv2.k8s.aws/cluster=$ClusterName"
108+
lbcMetricsCollector := lbcmetrics.NewCollector(
109+
metrics.Registry,
110+
mgr.GetClient(),
111+
cloud.RGT(),
112+
"k8s.aws",
113+
"elbv2.k8s.aws/cluster",
114+
controllerCFG.ClusterName,
115+
)
116+
110117
clientSet, err := kubernetes.NewForConfig(mgr.GetConfig())
111118
if err != nil {
112119
setupLog.Error(err, "unable to obtain clientSet")
@@ -163,6 +170,19 @@ func main() {
163170
os.Exit(1)
164171
}
165172

173+
// update of the managed resource metrics
174+
go func() {
175+
if err := lbcMetricsCollector.UpdateManagedK8sResourceMetrics(ctx); err != nil {
176+
setupLog.Error(err, "failed to update managed Kubernetes resource metrics")
177+
}
178+
if err := lbcMetricsCollector.UpdateManagedALBMetrics(ctx); err != nil {
179+
setupLog.Error(err, "failed to update managed ALB metrics")
180+
}
181+
if err := lbcMetricsCollector.UpdateManagedNLBMetrics(ctx); err != nil {
182+
setupLog.Error(err, "failed to update managed NLB metrics")
183+
}
184+
}()
185+
166186
// Add liveness probe
167187
err = mgr.AddHealthzCheck("health-ping", healthz.Ping)
168188
setupLog.Info("adding health check for controller")
@@ -210,6 +230,7 @@ func main() {
210230
setupLog.Error(err, "problem running manager")
211231
os.Exit(1)
212232
}
233+
213234
}
214235

215236
// loadControllerConfig loads the controller configuration.

Diff for: pkg/metrics/aws/instruments.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,13 @@ func newInstruments(registerer prometheus.Registerer) *instruments {
5959
Name: metricAPIRequestDurationSeconds,
6060
Help: "Latency of an individual HTTP request to the service endpoint",
6161
}, []string{labelService, labelOperation})
62-
63-
registerer.MustRegister(apiCallsTotal, apiCallDurationSeconds, apiCallRetries, apiRequestsTotal, apiRequestDurationSecond)
62+
registerer.MustRegister(
63+
apiCallsTotal,
64+
apiCallDurationSeconds,
65+
apiCallRetries,
66+
apiRequestsTotal,
67+
apiRequestDurationSecond,
68+
)
6469
return &instruments{
6570
apiCallsTotal: apiCallsTotal,
6671
apiCallDurationSeconds: apiCallDurationSeconds,

Diff for: pkg/metrics/lbc/collector.go

+148-4
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,81 @@
11
package lbc
22

33
import (
4+
"context"
5+
awssdk "github.com/aws/aws-sdk-go-v2/aws"
6+
rgtsdk "github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi"
7+
rgttypes "github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi/types"
48
"github.com/prometheus/client_golang/prometheus"
9+
corev1 "k8s.io/api/core/v1"
10+
networkingv1 "k8s.io/api/networking/v1"
11+
elbv2api "sigs.k8s.io/aws-load-balancer-controller/apis/elbv2/v1beta1"
12+
"sigs.k8s.io/aws-load-balancer-controller/pkg/aws/services"
13+
"strings"
14+
15+
"sigs.k8s.io/controller-runtime/pkg/client"
516
"time"
617
)
718

19+
const (
20+
networkLoadBalancerStr = "nlb"
21+
resourceTypeALB = "elasticloadbalancing:loadbalancer/app"
22+
resourceTypeNLB = "elasticloadbalancing:loadbalancer/net"
23+
)
24+
825
type MetricCollector interface {
926
// ObservePodReadinessGateReady this metric is useful to determine how fast pods are becoming ready in the load balancer.
1027
// Due to some architectural constraints, we can only emit this metric for pods that are using readiness gates.
1128
ObservePodReadinessGateReady(namespace string, tgbName string, duration time.Duration)
29+
30+
// UpdateManagedK8sResourceMetrics fetches and updates managed k8s resources metrics.
31+
UpdateManagedK8sResourceMetrics(ctx context.Context) error
32+
33+
// UpdateManagedALBMetrics updates managed ALB count metrics
34+
UpdateManagedALBMetrics(ctx context.Context) error
35+
36+
//UpdateManagedNLBMetrics updates managed NLB count metrics
37+
UpdateManagedNLBMetrics(ctx context.Context) error
1238
}
1339

1440
type collector struct {
15-
instruments *instruments
41+
instruments *instruments
42+
runtimeClient client.Client
43+
rgt services.RGT
44+
finalizerKeyWord string
45+
clusterTagKey string
46+
clusterTagVal string
1647
}
1748

1849
type noOpCollector struct{}
1950

2051
func (n *noOpCollector) ObservePodReadinessGateReady(_ string, _ string, _ time.Duration) {
2152
}
2253

23-
func NewCollector(registerer prometheus.Registerer) MetricCollector {
24-
if registerer == nil {
54+
func (n *noOpCollector) UpdateManagedK8sResourceMetrics(_ context.Context) error {
55+
return nil
56+
}
57+
58+
func (n *noOpCollector) UpdateManagedALBMetrics(_ context.Context) error {
59+
return nil
60+
}
61+
62+
func (n *noOpCollector) UpdateManagedNLBMetrics(_ context.Context) error {
63+
return nil
64+
}
65+
66+
func NewCollector(registerer prometheus.Registerer, runtimeClient client.Client, rgt services.RGT, finalizerKeyWord string, clusterTagKey string, clusterTagVal string) MetricCollector {
67+
if registerer == nil || runtimeClient == nil {
2568
return &noOpCollector{}
2669
}
2770

2871
instruments := newInstruments(registerer)
2972
return &collector{
30-
instruments: instruments,
73+
instruments: instruments,
74+
runtimeClient: runtimeClient,
75+
rgt: rgt,
76+
finalizerKeyWord: finalizerKeyWord,
77+
clusterTagKey: clusterTagKey,
78+
clusterTagVal: clusterTagVal,
3179
}
3280
}
3381

@@ -37,3 +85,99 @@ func (c *collector) ObservePodReadinessGateReady(namespace string, tgbName strin
3785
labelName: tgbName,
3886
}).Observe(duration.Seconds())
3987
}
88+
89+
func (c *collector) UpdateManagedK8sResourceMetrics(ctx context.Context) error {
90+
listOpts := &client.ListOptions{
91+
Namespace: "",
92+
}
93+
ingressCount, serviceCount, tgbCount := 0, 0, 0
94+
// Fetch ingress count
95+
ingressList := &networkingv1.IngressList{}
96+
err := c.runtimeClient.List(ctx, ingressList, listOpts)
97+
if err != nil {
98+
return err
99+
}
100+
for _, ingress := range ingressList.Items {
101+
for _, finalizer := range ingress.Finalizers {
102+
if strings.Contains(finalizer, c.finalizerKeyWord) {
103+
ingressCount++
104+
break
105+
}
106+
}
107+
}
108+
c.instruments.managedIngressCount.Set(float64(ingressCount))
109+
110+
// Fetch service count
111+
serviceList := &corev1.ServiceList{}
112+
err = c.runtimeClient.List(ctx, serviceList, listOpts)
113+
if err != nil {
114+
return err
115+
}
116+
for _, service := range serviceList.Items {
117+
hasMatchingFinalizer := false
118+
for _, finalizer := range service.Finalizers {
119+
if strings.Contains(finalizer, c.finalizerKeyWord) {
120+
hasMatchingFinalizer = true
121+
break
122+
}
123+
}
124+
125+
if hasMatchingFinalizer && service.Spec.LoadBalancerClass != nil && strings.Contains(*service.Spec.LoadBalancerClass, networkLoadBalancerStr) {
126+
serviceCount++
127+
}
128+
}
129+
c.instruments.managedServiceCount.Set(float64(serviceCount))
130+
131+
// Fetch TargetGroupBinding count
132+
tgbList := &elbv2api.TargetGroupBindingList{}
133+
err = c.runtimeClient.List(ctx, tgbList, listOpts)
134+
if err != nil {
135+
return err
136+
}
137+
for _, tgb := range tgbList.Items {
138+
for _, finalizer := range tgb.Finalizers {
139+
if strings.Contains(finalizer, c.finalizerKeyWord) {
140+
tgbCount++
141+
break
142+
}
143+
}
144+
}
145+
c.instruments.managedTGBCount.Set(float64(tgbCount))
146+
147+
return nil
148+
}
149+
150+
func (c *collector) UpdateManagedALBMetrics(ctx context.Context) error {
151+
count, err := c.getManagedAWSResourceMetrics(ctx, resourceTypeALB)
152+
if err != nil {
153+
return err
154+
}
155+
c.instruments.managedALBCount.Set(float64(count))
156+
return nil
157+
}
158+
159+
func (c *collector) UpdateManagedNLBMetrics(ctx context.Context) error {
160+
count, err := c.getManagedAWSResourceMetrics(ctx, resourceTypeNLB)
161+
if err != nil {
162+
return err
163+
}
164+
c.instruments.managedNLBCount.Set(float64(count))
165+
return nil
166+
}
167+
168+
func (c *collector) getManagedAWSResourceMetrics(ctx context.Context, resourceType string) (count int, err error) {
169+
req := &rgtsdk.GetResourcesInput{
170+
ResourceTypeFilters: []string{resourceType},
171+
TagFilters: []rgttypes.TagFilter{
172+
{
173+
Key: awssdk.String(c.clusterTagKey),
174+
Values: []string{c.clusterTagVal},
175+
},
176+
},
177+
}
178+
resources, err := c.rgt.GetResourcesAsList(ctx, req)
179+
if err != nil {
180+
return 0, err
181+
}
182+
return len(resources), nil
183+
}

0 commit comments

Comments
 (0)