Skip to content

Commit 8d94cf6

Browse files
authored
feat: add node name filter for pod owner cache to track local pods only (#4881)
Signed-off-by: Cyclinder Kuo <[email protected]>
1 parent 72c9368 commit 8d94cf6

File tree

6 files changed

+101
-18
lines changed

6 files changed

+101
-18
lines changed

charts/spiderpool/templates/daemonset.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,10 @@ spec:
200200
valueFrom:
201201
fieldRef:
202202
fieldPath: metadata.namespace
203+
- name: SPIDERPOOL_NODE_NAME
204+
valueFrom:
205+
fieldRef:
206+
fieldPath: spec.nodeName
203207
- name: SPIDERPOOL_LOG_LEVEL
204208
value: {{ .Values.spiderpoolAgent.debug.logLevel | quote }}
205209
- name: SPIDERPOOL_ENABLED_METRIC

cmd/spiderpool-agent/cmd/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ var envInfo = []envConf{
5757
{"SPIDERPOOL_ENABLED_DEBUG_METRIC", "false", false, nil, &agentContext.Cfg.EnableDebugLevelMetric, nil},
5858
{"SPIDERPOOL_POD_NAMESPACE", "", true, &agentContext.Cfg.AgentPodNamespace, nil, nil},
5959
{"SPIDERPOOL_POD_NAME", "", true, &agentContext.Cfg.AgentPodName, nil, nil},
60+
{"SPIDERPOOL_NODE_NAME", "", true, &agentContext.Cfg.NodeName, nil, nil},
6061
{"SPIDERPOOL_HEALTH_PORT", "5710", true, &agentContext.Cfg.HttpPort, nil, nil},
6162
{"SPIDERPOOL_METRIC_HTTP_PORT", "5711", true, &agentContext.Cfg.MetricHttpPort, nil, nil},
6263
{"SPIDERPOOL_GOPS_LISTEN_PORT", "5712", false, &agentContext.Cfg.GopsListenPort, nil, nil},
@@ -84,6 +85,7 @@ type Config struct {
8485
EnableDebugLevelMetric bool
8586
AgentPodNamespace string
8687
AgentPodName string
88+
NodeName string
8789
EnableReleaseConflictIPsForStateless bool
8890

8991
HttpPort string

cmd/spiderpool-agent/cmd/metrics_server.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88
"fmt"
99
"net/http"
1010

11+
"go.uber.org/zap"
12+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1113
"k8s.io/client-go/informers"
1214

1315
"github.com/spidernet-io/spiderpool/pkg/constant"
@@ -29,10 +31,22 @@ func initAgentMetricsServer(ctx context.Context) {
2931
var cache podownercache.CacheInterface
3032
// nolint is used to disable the golint warning for the following line.
3133
if agentContext.Cfg.EnableRDMAMetric { //nolint:golint
32-
logger.Info("enable rdma metric exporter")
33-
informerFactory := informers.NewSharedInformerFactory(agentContext.ClientSet, 0)
34+
logger.Info("enable rdma metric exporter",
35+
zap.String("nodeName", agentContext.Cfg.NodeName))
36+
37+
// Create informer factory with field selector to only watch pods on this node
38+
informerFactory := informers.NewSharedInformerFactoryWithOptions(
39+
agentContext.ClientSet,
40+
0,
41+
informers.WithTweakListOptions(func(options *metav1.ListOptions) {
42+
// Filter pods by node name
43+
options.FieldSelector = fmt.Sprintf("spec.nodeName=%s", agentContext.Cfg.NodeName)
44+
}),
45+
)
46+
3447
podInformer := informerFactory.Core().V1().Pods().Informer()
3548
informerFactory.Start(ctx.Done())
49+
informerFactory.WaitForCacheSync(ctx.Done())
3650

3751
cache, err = podownercache.New(ctx, podInformer, agentContext.CRDManager.GetClient())
3852
if err != nil {

pkg/constant/k8s.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ const ClusterDefaultInterfaceName = "eth0"
158158
const (
159159
MultusDefaultNetAnnot = "v1.multus-cni.io/default-network"
160160
MultusNetworkAttachmentAnnot = "k8s.v1.cni.cncf.io/networks"
161+
MultusNetworkStatus = "k8s.v1.cni.cncf.io/network-status"
161162
ResourceNameAnnot = "k8s.v1.cni.cncf.io/resourceName"
162163
ResourceNameOvsCniValue = "ovs-cni.network.kubevirt.io"
163164
)

pkg/podownercache/pod_owner_cache.go

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ package podownercache
55

66
import (
77
"context"
8+
"strings"
9+
10+
"github.com/spidernet-io/spiderpool/pkg/constant"
811
"github.com/spidernet-io/spiderpool/pkg/lock"
912
"github.com/spidernet-io/spiderpool/pkg/logutils"
1013
"go.uber.org/zap"
@@ -24,6 +27,8 @@ type PodOwnerCache struct {
2427
cacheLock lock.RWMutex
2528
pods map[types.NamespacedName]Pod
2629
ipToPod map[string]types.NamespacedName
30+
// Cache for final owner references to reduce API calls, using pod NamespacedName as key
31+
ownerCache map[types.NamespacedName]*OwnerInfo
2732
}
2833

2934
type Pod struct {
@@ -50,11 +55,12 @@ func New(ctx context.Context, podInformer cache.SharedIndexInformer, apiReader c
5055
logger.Info("create PodOwnerCache informer")
5156

5257
res := &PodOwnerCache{
53-
ctx: ctx,
54-
apiReader: apiReader,
55-
cacheLock: lock.RWMutex{},
56-
pods: make(map[types.NamespacedName]Pod),
57-
ipToPod: make(map[string]types.NamespacedName),
58+
ctx: ctx,
59+
apiReader: apiReader,
60+
cacheLock: lock.RWMutex{},
61+
pods: make(map[types.NamespacedName]Pod),
62+
ipToPod: make(map[string]types.NamespacedName),
63+
ownerCache: make(map[types.NamespacedName]*OwnerInfo),
5864
}
5965

6066
_, err := podInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
@@ -70,11 +76,20 @@ func New(ctx context.Context, podInformer cache.SharedIndexInformer, apiReader c
7076
return res, nil
7177
}
7278

73-
func (s *PodOwnerCache) onPodAdd(obj interface{}) {
79+
func (s *PodOwnerCache) onPodAdd(obj any) {
7480
if pod, ok := obj.(*corev1.Pod); ok {
7581
if pod.Spec.HostNetwork {
7682
return
7783
}
84+
85+
if pod.Annotations[constant.MultusNetworkStatus] == "" {
86+
return
87+
}
88+
89+
if !strings.Contains(pod.Annotations[constant.MultusNetworkStatus], "rdma-device") {
90+
return
91+
}
92+
7893
if len(pod.Status.PodIPs) > 0 {
7994
ips := make([]string, 0, len(pod.Status.PodIPs))
8095
for _, p := range pod.Status.PodIPs {
@@ -123,6 +138,23 @@ func (s *PodOwnerCache) onPodDel(obj interface{}) {
123138
func (s *PodOwnerCache) getFinalOwner(obj metav1.Object) (*OwnerInfo, error) {
124139
var finalOwner *OwnerInfo
125140

141+
// Create pod NamespacedName as the cache key
142+
podKey := types.NamespacedName{
143+
Namespace: obj.GetNamespace(),
144+
Name: obj.GetName(),
145+
}
146+
147+
// Check if we already have a cached final owner for this pod
148+
s.cacheLock.RLock()
149+
cachedOwner, exists := s.ownerCache[podKey]
150+
s.cacheLock.RUnlock()
151+
152+
if exists {
153+
// If we found a cached result, return it immediately
154+
logger.Sugar().Debugf("Using cached owner for pod %s/%s", obj.GetNamespace(), obj.GetName())
155+
return cachedOwner, nil
156+
}
157+
126158
for {
127159
ownerRefs := obj.GetOwnerReferences()
128160
if len(ownerRefs) == 0 {
@@ -131,6 +163,8 @@ func (s *PodOwnerCache) getFinalOwner(obj metav1.Object) (*OwnerInfo, error) {
131163

132164
// Assuming the first owner reference
133165
ownerRef := ownerRefs[0]
166+
167+
// If not in cache, create the owner info
134168
finalOwner = &OwnerInfo{
135169
APIVersion: ownerRef.APIVersion,
136170
Kind: ownerRef.Kind,
@@ -148,12 +182,12 @@ func (s *PodOwnerCache) getFinalOwner(obj metav1.Object) (*OwnerInfo, error) {
148182
Name: ownerRef.Name,
149183
}, ownerObj)
150184
if err != nil {
151-
if errors.IsForbidden(err) {
152-
logger.Sugar().Debugf("forbidden to get owner of pod %s/%s", obj.GetNamespace(), obj.GetName())
153-
return nil, nil
154-
}
155-
if errors.IsNotFound(err) {
156-
logger.Sugar().Debugf("owner not found for pod %s/%s", obj.GetNamespace(), obj.GetName())
185+
if errors.IsForbidden(err) || errors.IsNotFound(err) {
186+
logger.Sugar().Debugf("%v for pod %s/%s", err, obj.GetNamespace(), obj.GetName())
187+
// Cache the negative result
188+
s.cacheLock.Lock()
189+
s.ownerCache[podKey] = nil
190+
s.cacheLock.Unlock()
157191
return nil, nil
158192
}
159193
return nil, err
@@ -163,6 +197,19 @@ func (s *PodOwnerCache) getFinalOwner(obj metav1.Object) (*OwnerInfo, error) {
163197
obj = ownerObj
164198
}
165199

200+
// Cache the final owner (or nil if no owner found)
201+
s.cacheLock.Lock()
202+
s.ownerCache[podKey] = finalOwner
203+
s.cacheLock.Unlock()
204+
205+
if finalOwner != nil {
206+
logger.Sugar().Debugf("Cached final owner %s/%s of kind %s for pod %s/%s",
207+
finalOwner.Namespace, finalOwner.Name, finalOwner.Kind,
208+
podKey.Namespace, podKey.Name)
209+
} else {
210+
logger.Sugar().Debugf("No owner found for pod %s/%s", podKey.Namespace, podKey.Name)
211+
}
212+
166213
return finalOwner, nil
167214
}
168215

pkg/podownercache/pod_owner_cache_test.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1717
kruntime "k8s.io/apimachinery/pkg/runtime"
1818
"k8s.io/apimachinery/pkg/runtime/schema"
19+
types "k8s.io/apimachinery/pkg/types"
1920
"k8s.io/client-go/informers"
2021
"k8s.io/client-go/kubernetes/fake"
2122
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -42,6 +43,12 @@ func TestPodOwnerCache(t *testing.T) {
4243
Name: "test-rs",
4344
},
4445
},
46+
Annotations: map[string]string{
47+
"k8s.v1.cni.cncf.io/network-status": `[{
48+
"name": "rdma-device",
49+
"interface": "eth0"
50+
}]`,
51+
},
4552
},
4653
Status: corev1.PodStatus{
4754
PodIPs: []corev1.PodIP{
@@ -56,6 +63,12 @@ func TestPodOwnerCache(t *testing.T) {
5663
ObjectMeta: v1.ObjectMeta{
5764
Name: "test-pod-2",
5865
Namespace: "test-ns",
66+
Annotations: map[string]string{
67+
"k8s.v1.cni.cncf.io/network-status": `[{
68+
"name": "rdma-device",
69+
"interface": "eth0"
70+
}]`,
71+
},
5972
},
6073
Status: corev1.PodStatus{
6174
PodIPs: []corev1.PodIP{
@@ -197,8 +210,9 @@ func TestGetFinalOwnerForbidden(t *testing.T) {
197210

198211
mockClient := &MockForbiddenClient{}
199212
cache := &PodOwnerCache{
200-
ctx: context.Background(),
201-
apiReader: mockClient,
213+
ctx: context.Background(),
214+
apiReader: mockClient,
215+
ownerCache: map[types.NamespacedName]*OwnerInfo{},
202216
}
203217

204218
// Create a mock pod object
@@ -242,8 +256,9 @@ func TestGetFinalOwnerNotFound(t *testing.T) {
242256

243257
mockClient := &MockNotFoundClient{}
244258
cache := &PodOwnerCache{
245-
ctx: context.Background(),
246-
apiReader: mockClient,
259+
ctx: context.Background(),
260+
apiReader: mockClient,
261+
ownerCache: map[types.NamespacedName]*OwnerInfo{},
247262
}
248263

249264
// Create a mock pod object

0 commit comments

Comments
 (0)