Skip to content

Commit bb5f63a

Browse files
committed
perf(license): reduce controller cache memory
1 parent 7afc77e commit bb5f63a

6 files changed

Lines changed: 396 additions & 4 deletions

File tree

controllers/license/cmd/manager/main.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,18 @@ import (
2222
"os"
2323

2424
licensev1 "github.com/labring/sealos/controllers/license/api/v1"
25+
licensecache "github.com/labring/sealos/controllers/license/internal/cache"
2526
"github.com/labring/sealos/controllers/license/internal/controller"
2627
utilid "github.com/labring/sealos/controllers/license/internal/util/clusterid"
2728
"github.com/labring/sealos/controllers/license/internal/util/rate"
2829
notificationv1 "github.com/labring/sealos/controllers/pkg/notification/api/v1"
30+
userv1 "github.com/labring/sealos/controllers/user/api/v1"
2931
"k8s.io/apimachinery/pkg/runtime"
3032
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
3133
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
3234
_ "k8s.io/client-go/plugin/pkg/client/auth"
3335
ctrl "sigs.k8s.io/controller-runtime"
36+
"sigs.k8s.io/controller-runtime/pkg/client"
3437
ccontroler "sigs.k8s.io/controller-runtime/pkg/controller"
3538
"sigs.k8s.io/controller-runtime/pkg/healthz"
3639
"sigs.k8s.io/controller-runtime/pkg/log/zap"
@@ -48,6 +51,7 @@ func init() {
4851

4952
utilruntime.Must(licensev1.AddToScheme(scheme))
5053
utilruntime.Must(notificationv1.AddToScheme(scheme))
54+
utilruntime.Must(userv1.AddToScheme(scheme))
5155
//+kubebuilder:scaffold:scheme
5256
}
5357

@@ -131,7 +135,11 @@ func main() {
131135
}
132136

133137
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
134-
Scheme: scheme,
138+
Scheme: scheme,
139+
Cache: licensecache.Options(),
140+
Client: client.Options{Cache: &client.CacheOptions{
141+
DisableFor: licensecache.UncachedObjects(),
142+
}},
135143
Metrics: metricsServerOptions,
136144
HealthProbeBindAddress: probeAddr,
137145
LeaderElection: enableLeaderElection,
@@ -180,6 +188,10 @@ func main() {
180188
ClusterID: clusterID,
181189
CreateTimestamp: *createTime,
182190
}
191+
if err = licensecache.SetupInformers(mgr); err != nil {
192+
setupLog.Error(err, "unable to set up license cache informers")
193+
os.Exit(1)
194+
}
183195
if err = reconciler.SetupWithManager(mgr, rateOpts); err != nil {
184196
setupLog.Error(err, "unable to create controller", "controller", "License")
185197
os.Exit(1)

controllers/license/config/rbac/role.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ kind: ClusterRole
44
metadata:
55
name: manager-role
66
rules:
7+
- apiGroups:
8+
- ""
9+
resourceNames:
10+
- kube-system
11+
- ns-admin
12+
resources:
13+
- namespaces
14+
verbs:
15+
- get
716
- apiGroups:
817
- ""
918
resources:

controllers/license/deploy/charts/license-controller/templates/clusterrole.yaml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,9 @@ metadata:
55
rules:
66
- apiGroups: [ "" ]
77
resources: [ "namespaces" ]
8-
resourceNames: [ "kube-system" ]
8+
resourceNames: [ "kube-system", "ns-admin" ]
99
verbs:
1010
- get
11-
- list
12-
- watch
1311
- apiGroups:
1412
- ""
1513
resources:
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Copyright 2026 labring.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package cache
16+
17+
import (
18+
"context"
19+
"fmt"
20+
21+
licensev1 "github.com/labring/sealos/controllers/license/api/v1"
22+
notificationv1 "github.com/labring/sealos/controllers/pkg/notification/api/v1"
23+
userv1 "github.com/labring/sealos/controllers/user/api/v1"
24+
corev1 "k8s.io/api/core/v1"
25+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26+
ctrl "sigs.k8s.io/controller-runtime"
27+
ctrlcache "sigs.k8s.io/controller-runtime/pkg/cache"
28+
"sigs.k8s.io/controller-runtime/pkg/client"
29+
)
30+
31+
// Options retains only the fields used for event delivery and node validation.
32+
func Options() ctrlcache.Options {
33+
return ctrlcache.Options{
34+
ReaderFailOnMissingInformer: true,
35+
DefaultTransform: ctrlcache.TransformStripManagedFields(),
36+
ByObject: map[client.Object]ctrlcache.ByObject{
37+
&licensev1.License{}: {Transform: transformLicense},
38+
&corev1.Node{}: {Transform: transformNode},
39+
},
40+
}
41+
}
42+
43+
// UncachedObjects keeps reads that require complete or low-frequency objects on the API server.
44+
func UncachedObjects() []client.Object {
45+
return []client.Object{
46+
&licensev1.License{},
47+
&corev1.Namespace{},
48+
&notificationv1.Notification{},
49+
&userv1.User{},
50+
}
51+
}
52+
53+
// SetupInformers registers the Node informer used by license validation. The License
54+
// informer is registered by the controller builder.
55+
func SetupInformers(mgr ctrl.Manager) error {
56+
if _, err := mgr.GetCache().GetInformer(context.Background(), &corev1.Node{}); err != nil {
57+
return fmt.Errorf("register node informer: %w", err)
58+
}
59+
return nil
60+
}
61+
62+
func transformLicense(obj any) (any, error) {
63+
license, ok := obj.(*licensev1.License)
64+
if !ok {
65+
return obj, nil
66+
}
67+
68+
return &licensev1.License{
69+
TypeMeta: license.TypeMeta,
70+
ObjectMeta: projectObjectMeta(license.ObjectMeta),
71+
}, nil
72+
}
73+
74+
func transformNode(obj any) (any, error) {
75+
node, ok := obj.(*corev1.Node)
76+
if !ok {
77+
return obj, nil
78+
}
79+
80+
return &corev1.Node{
81+
TypeMeta: node.TypeMeta,
82+
ObjectMeta: projectObjectMeta(node.ObjectMeta),
83+
Status: corev1.NodeStatus{
84+
Allocatable: copyNodeAllocatable(node.Status.Allocatable),
85+
},
86+
}, nil
87+
}
88+
89+
func copyNodeAllocatable(source corev1.ResourceList) corev1.ResourceList {
90+
var result corev1.ResourceList
91+
for _, name := range []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory} {
92+
if quantity, ok := source[name]; ok {
93+
if result == nil {
94+
result = make(corev1.ResourceList, 2)
95+
}
96+
result[name] = quantity.DeepCopy()
97+
}
98+
}
99+
return result
100+
}
101+
102+
func projectObjectMeta(in metav1.ObjectMeta) metav1.ObjectMeta {
103+
out := metav1.ObjectMeta{
104+
Name: in.Name,
105+
Namespace: in.Namespace,
106+
UID: in.UID,
107+
ResourceVersion: in.ResourceVersion,
108+
Generation: in.Generation,
109+
CreationTimestamp: in.CreationTimestamp,
110+
}
111+
if in.DeletionTimestamp != nil {
112+
out.DeletionTimestamp = in.DeletionTimestamp.DeepCopy()
113+
}
114+
if in.DeletionGracePeriodSeconds != nil {
115+
gracePeriod := *in.DeletionGracePeriodSeconds
116+
out.DeletionGracePeriodSeconds = &gracePeriod
117+
}
118+
return out
119+
}

0 commit comments

Comments
 (0)