github.com/alibaba/ilogtail/pkg@v0.0.0-20250526110833-c53b480d046c/helper/k8smeta/k8s_meta_manager.go (about) 1 package k8smeta 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 "sync" 8 "sync/atomic" 9 "time" 10 11 "k8s.io/client-go/kubernetes" 12 "k8s.io/client-go/rest" 13 "k8s.io/client-go/tools/clientcmd" 14 controllerConfig "sigs.k8s.io/controller-runtime/pkg/client/config" 15 16 "github.com/alibaba/ilogtail/pkg/flags" 17 "github.com/alibaba/ilogtail/pkg/logger" 18 "github.com/alibaba/ilogtail/pkg/selfmonitor" 19 ) 20 21 var metaManager *MetaManager 22 23 var onceManager sync.Once 24 25 type MetaCache interface { 26 Get(key []string) map[string][]*ObjectWrapper 27 GetSize() int 28 GetQueueSize() int 29 List() []*ObjectWrapper 30 Filter(filterFunc func(*ObjectWrapper) bool, limit int) []*ObjectWrapper 31 RegisterSendFunc(key string, sendFunc SendFunc, interval int) 32 UnRegisterSendFunc(key string) 33 init(*kubernetes.Clientset) 34 watch(stopCh <-chan struct{}) 35 } 36 37 type FlushCh struct { 38 Ch chan *K8sMetaEvent 39 ConfigName string 40 } 41 42 type MetaManager struct { 43 clientset *kubernetes.Clientset 44 stopCh chan struct{} 45 46 ready atomic.Bool 47 48 metadataHandler *metadataHandler 49 cacheMap map[string]MetaCache 50 linkGenerator *LinkGenerator 51 linkRegisterMap map[string][]string 52 registerLock sync.RWMutex 53 54 // self metrics 55 projectNames map[string]int 56 metricRecord selfmonitor.MetricsRecord 57 addEventCount selfmonitor.CounterMetric 58 updateEventCount selfmonitor.CounterMetric 59 deleteEventCount selfmonitor.CounterMetric 60 cacheResourceGauge selfmonitor.GaugeMetric 61 queueSizeGauge selfmonitor.GaugeMetric 62 httpRequestCount selfmonitor.CounterMetric 63 httpAvgDelayMs selfmonitor.CounterMetric 64 httpMaxDelayMs selfmonitor.GaugeMetric 65 } 66 67 func GetMetaManagerInstance() *MetaManager { 68 onceManager.Do(func() { 69 metaManager = &MetaManager{ 70 stopCh: make(chan struct{}), 71 } 72 metaManager.metadataHandler = newMetadataHandler(metaManager) 73 metaManager.cacheMap = make(map[string]MetaCache) 74 for _, resource := range AllResources { 75 metaManager.cacheMap[resource] = newK8sMetaCache(metaManager.stopCh, resource) 76 } 77 metaManager.linkGenerator = NewK8sMetaLinkGenerator(metaManager.cacheMap) 78 metaManager.linkRegisterMap = make(map[string][]string) 79 metaManager.projectNames = make(map[string]int) 80 }) 81 return metaManager 82 } 83 84 func (m *MetaManager) Init(configPath string) (err error) { 85 var config *rest.Config 86 if len(configPath) > 0 { 87 config, err = clientcmd.BuildConfigFromFlags("", configPath) 88 if err != nil { 89 return err 90 } 91 } else { 92 // 创建 Kubernetes 客户端配置 93 config = controllerConfig.GetConfigOrDie() 94 } 95 // 创建 Kubernetes 客户端 96 clientset, err := kubernetes.NewForConfig(config) 97 if err != nil { 98 return err 99 } 100 m.clientset = clientset 101 102 m.metricRecord = selfmonitor.MetricsRecord{} 103 m.addEventCount = selfmonitor.NewCounterMetricAndRegister(&m.metricRecord, selfmonitor.MetricRunnerK8sMetaAddEventTotal) 104 m.updateEventCount = selfmonitor.NewCounterMetricAndRegister(&m.metricRecord, selfmonitor.MetricRunnerK8sMetaUpdateEventTotal) 105 m.deleteEventCount = selfmonitor.NewCounterMetricAndRegister(&m.metricRecord, selfmonitor.MetricRunnerK8sMetaDeleteEventTotal) 106 m.cacheResourceGauge = selfmonitor.NewGaugeMetricAndRegister(&m.metricRecord, selfmonitor.MetricRunnerK8sMetaCacheSize) 107 m.queueSizeGauge = selfmonitor.NewGaugeMetricAndRegister(&m.metricRecord, selfmonitor.MetricRunnerK8sMetaQueueSize) 108 m.httpRequestCount = selfmonitor.NewCounterMetricAndRegister(&m.metricRecord, selfmonitor.MetricRunnerK8sMetaHTTPRequestTotal) 109 m.httpAvgDelayMs = selfmonitor.NewAverageMetricAndRegister(&m.metricRecord, selfmonitor.MetricRunnerK8sMetaHTTPAvgDelayMs) 110 m.httpMaxDelayMs = selfmonitor.NewMaxMetricAndRegister(&m.metricRecord, selfmonitor.MetricRunnerK8sMetaHTTPMaxDelayMs) 111 112 go func() { 113 startTime := time.Now() 114 for _, cache := range m.cacheMap { 115 cache.init(clientset) 116 } 117 m.ready.Store(true) 118 logger.Info(context.Background(), "init k8s meta manager", "success", "latancy (ms)", fmt.Sprintf("%d", time.Since(startTime).Milliseconds())) 119 }() 120 return nil 121 } 122 123 func (m *MetaManager) Run(stopCh chan struct{}) { 124 m.stopCh = stopCh 125 m.runServer() 126 } 127 128 func (m *MetaManager) IsReady() bool { 129 return m.ready.Load() 130 } 131 132 func (m *MetaManager) RegisterSendFunc(projectName, configName, resourceType string, sendFunc SendFunc, interval int) { 133 if cache, ok := m.cacheMap[resourceType]; ok { 134 cache.RegisterSendFunc(configName, func(events []*K8sMetaEvent) { 135 defer panicRecover() 136 sendFunc(events) 137 m.registerLock.RLock() 138 for _, linkType := range m.linkRegisterMap[configName] { 139 if strings.HasPrefix(linkType, resourceType) { 140 linkEvents := m.linkGenerator.GenerateLinks(events, linkType) 141 if linkEvents != nil { 142 sendFunc(linkEvents) 143 } 144 } 145 } 146 m.registerLock.RUnlock() 147 }, interval) 148 m.registerLock.Lock() 149 if cnt, ok := m.projectNames[projectName]; ok { 150 m.projectNames[projectName] = cnt + 1 151 } else { 152 m.projectNames[projectName] = 1 153 } 154 m.registerLock.Unlock() 155 return 156 } 157 // register link 158 if !isEntity(resourceType) { 159 m.registerLock.Lock() 160 if _, ok := m.linkRegisterMap[configName]; !ok { 161 m.linkRegisterMap[configName] = make([]string, 0) 162 } 163 m.linkRegisterMap[configName] = append(m.linkRegisterMap[configName], resourceType) 164 m.registerLock.Unlock() 165 } else { 166 logger.Error(context.Background(), "ENTITY_PIPELINE_REGISTER_ERROR", "resourceType not support", resourceType) 167 } 168 } 169 170 func (m *MetaManager) UnRegisterAllSendFunc(projectName, configName string) { 171 for _, cache := range m.cacheMap { 172 cache.UnRegisterSendFunc(configName) 173 } 174 m.registerLock.Lock() 175 if cnt, ok := m.projectNames[projectName]; ok { 176 if cnt == 1 { 177 delete(m.projectNames, projectName) 178 } else { 179 m.projectNames[projectName] = cnt - 1 180 } 181 } 182 delete(m.linkRegisterMap, configName) 183 m.registerLock.Unlock() 184 } 185 186 func GetMetaManagerMetrics() []map[string]string { 187 manager := GetMetaManagerInstance() 188 if manager == nil || !manager.IsReady() { 189 return nil 190 } 191 // cache 192 queueSize := 0 193 cacheSize := 0 194 for _, cache := range manager.cacheMap { 195 queueSize += cache.GetQueueSize() 196 cacheSize += cache.GetSize() 197 } 198 manager.queueSizeGauge.Set(float64(queueSize)) 199 manager.cacheResourceGauge.Set(float64(cacheSize)) 200 // set labels 201 manager.registerLock.RLock() 202 projectName := make([]string, 0) 203 projectName = append(projectName, *flags.DefaultLogProject) 204 for name := range manager.projectNames { 205 projectName = append(projectName, name) 206 } 207 manager.registerLock.RUnlock() 208 manager.metricRecord.Labels = []selfmonitor.LabelPair{ 209 { 210 Key: selfmonitor.MetricLabelKeyMetricCategory, 211 Value: selfmonitor.MetricLabelValueMetricCategoryRunner, 212 }, 213 { 214 Key: selfmonitor.MetricLabelKeyClusterID, 215 Value: *flags.ClusterID, 216 }, 217 { 218 Key: selfmonitor.MetricLabelKeyRunnerName, 219 Value: selfmonitor.MetricLabelValueRunnerNameK8sMeta, 220 }, 221 { 222 Key: selfmonitor.MetricLabelKeyProject, 223 Value: strings.Join(projectName, " "), 224 }, 225 } 226 227 return []map[string]string{ 228 manager.metricRecord.ExportMetricRecords(), 229 } 230 } 231 232 func (m *MetaManager) runServer() { 233 go m.metadataHandler.K8sServerRun(m.stopCh) 234 } 235 236 func isEntity(resourceType string) bool { 237 return !strings.Contains(resourceType, LINK_SPLIT_CHARACTER) 238 }