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  }