什么是evaluator
大家都知道,Kubernetes中使用resourcequota对配额进行管理。配额的管理涉及两个步骤:1、计算请求所需要的资源;2、比较并更新配额。所以解读resourcequota将分为两次进行。
evaluator就是用来计算请求所需要的资源的。
GenericEvaluator
GenericEvaluator实现了evaluator,是一个基础的evaluator。
我们先来看下GenericEvaluator的定义,在/pkg/quota/generic/evaluator.go中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 
  | type GenericEvaluator struct { 	 	Name string 	 	InternalGroupKind unversioned.GroupKind 	 	InternalOperationResources map[admission.Operation][]api.ResourceName 	 	MatchedResourceNames []api.ResourceName 	 	MatchesScopeFunc MatchesScopeFunc 	 	UsageFunc UsageFunc 	 	ListFuncByNamespace ListFuncByNamespace 	 	 	GetFuncByNamespace GetFuncByNamespace 	 	ConstraintsFunc ConstraintsFunc } 
  | 
其中:
- Name: 表示该Evaluator的名称;
 
- InternalGroupKind: 表明该Evaluator所处理资源的内部的类型;
 
- InternalOperationResources: 表明该Evaluator所支持的请求的类型,如Create, Update等及这些操作所支持的资源;
 
- MatchedResourceNames: 表明该Evaluator所对应的资源名称,如ResourceCPU, ResourcePods等;
 
- MatchesScopeFunc: resourcequota的scope判断函数。resourcequota只处理满足scope判断函数的请求(即只统计部分对象的配额),目前有Terminating, NotTerminating, BestEffort, NotBestEffort这些Scope;
 
- UsageFunc: 用来计算对象所占资源;
 
- ListFuncByNamespace: 对象List函数;
 
- GetFuncByNamespace: 对象获取函数;
 
- ConstraintsFunc: 对对象申请的资源进行合理性检查,如requests<limits。
 
Matches()
Matches()方法判断该Evaluator及resourceQuota是否需要处理该请求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 
  | func (g *GenericEvaluator) Matches(resourceQuota *api.ResourceQuota, item runtime.Object) bool { 	if resourceQuota == nil { 		return false 	} 	 	matchResource := false 	 	for resourceName := range resourceQuota.Status.Hard { 		if g.MatchesResource(resourceName) { 			matchResource = true 			break 		} 	} 	 	matchScope := true 	for _, scope := range resourceQuota.Spec.Scopes { 		matchScope = matchScope && g.MatchesScope(scope, item) 	} 	return matchResource && matchScope } func (g *GenericEvaluator) MatchesResource(resourceName api.ResourceName) bool { 	for _, matchedResourceName := range g.MatchedResourceNames { 		if resourceName == matchedResourceName { 			return true 		} 	} 	return false } func (g *GenericEvaluator) MatchesScope(scope api.ResourceQuotaScope, object runtime.Object) bool { 	return g.MatchesScopeFunc(scope, object) } 
  | 
Usage()
Usage()方法可以计算object所需要的资源。
1 2 3 4 
  | func (g *GenericEvaluator) Usage(object runtime.Object) api.ResourceList { 	return g.UsageFunc(object) } 
  | 
UsageStats()
UsageStats()可以计算出某命名空间下某类对象的资源使用情况。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 
  | func (g *GenericEvaluator) UsageStats(options quota.UsageStatsOptions) (quota.UsageStats, error) { 	 	result := quota.UsageStats{Used: api.ResourceList{}} 	for _, resourceName := range g.MatchedResourceNames { 		result.Used[resourceName] = resource.MustParse("0") 	} 	 	items, err := g.ListFuncByNamespace(options.Namespace, api.ListOptions{ 		LabelSelector: labels.Everything(), 	}) 	if err != nil { 		return result, fmt.Errorf("%s: Failed to list %v: %v", g.Name, g.GroupKind(), err) 	} 	for _, item := range items { 		 		matchesScopes := true 		for _, scope := range options.Scopes { 			if !g.MatchesScope(scope, item) { 				matchesScopes = false 			} 		} 		 		 		if matchesScopes { 			result.Used = quota.Add(result.Used, g.Usage(item)) 		} 	} 	return result, nil } 
  | 
PodEvaluator
上小节介绍了Evaluator,在这小节将以PodEvaluator。PodEvaluator可以计算Pod的所需资源量。
PodEvaluator定义在/pkg/quota/evaluator/core/pods.go中,其本身就是一个Evaluator:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 
  | func NewPodEvaluator(kubeClient clientset.Interface, f informers.SharedInformerFactory) quota.Evaluator { 	computeResources := []api.ResourceName{ 		api.ResourceCPU, 		api.ResourceMemory, 		api.ResourceRequestsCPU, 		api.ResourceRequestsMemory, 		api.ResourceLimitsCPU, 		api.ResourceLimitsMemory, 	} 	 	allResources := append(computeResources, api.ResourcePods) 	 	listFuncByNamespace := listPodsByNamespaceFuncUsingClient(kubeClient) 	if f != nil { 		listFuncByNamespace = generic.ListResourceUsingInformerFunc(f, unversioned.GroupResource{Resource: "pods"}) 	} 	return &generic.GenericEvaluator{ 		Name:              "Evaluator.Pod", 		InternalGroupKind: api.Kind("Pod"), 		 		InternalOperationResources: map[admission.Operation][]api.ResourceName{ 			admission.Create: allResources, 			 			 		}, 		GetFuncByNamespace: func(namespace, name string) (runtime.Object, error) { 			return kubeClient.Core().Pods(namespace).Get(name) 		}, 		ConstraintsFunc:      PodConstraintsFunc, 		MatchedResourceNames: allResources, 		MatchesScopeFunc:     PodMatchesScopeFunc, 		UsageFunc:            PodUsageFunc, 		ListFuncByNamespace:  listFuncByNamespace, 	} } 
  | 
这里要着重说下listFuncByNamespace,有listPodsByNamespaceFuncUsingClient和ListResourceUsingInformerFunc两种,而且ListResourceUsingInformerFunc优先级更高,具体由NewPodEvaluator()的参数来控制。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 
  | func listPodsByNamespaceFuncUsingClient(kubeClient clientset.Interface) generic.ListFuncByNamespace { 	 	 	 	 	return func(namespace string, options api.ListOptions) ([]runtime.Object, error) { 		itemList, err := kubeClient.Core().Pods(namespace).List(options) 		if err != nil { 			return nil, err 		} 		results := make([]runtime.Object, 0, len(itemList.Items)) 		for i := range itemList.Items { 			results = append(results, &itemList.Items[i]) 		} 		return results, nil 	} } 
  | 
1 2 3 4 5 6 7 8 9 10 
  | func ListResourceUsingInformerFunc(f informers.SharedInformerFactory, groupResource unversioned.GroupResource) ListFuncByNamespace { 	return func(namespace string, options api.ListOptions) ([]runtime.Object, error) { 		informer, err := f.ForResource(groupResource) 		if err != nil { 			return nil, err 		} 		return informer.Lister().ByNamespace(namespace).List(options.LabelSelector) 	} } 
  | 
 
PodUsageFunc()
PodUsageFunc()函数用来计算Pod的所需资源。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 
  | func PodUsageFunc(object runtime.Object) api.ResourceList { 	pod, ok := object.(*api.Pod) 	if !ok { 		return api.ResourceList{} 	} 	 	if !QuotaPod(pod) { 		return api.ResourceList{} 	} 	 	 	requests := api.ResourceList{} 	limits := api.ResourceList{} 	 	for i := range pod.Spec.Containers { 		requests = quota.Add(requests, pod.Spec.Containers[i].Resources.Requests) 		limits = quota.Add(limits, pod.Spec.Containers[i].Resources.Limits) 	} 	 	 	 	for i := range pod.Spec.InitContainers { 		requests = quota.Max(requests, pod.Spec.InitContainers[i].Resources.Requests) 		limits = quota.Max(limits, pod.Spec.InitContainers[i].Resources.Limits) 	} 	return podUsageHelper(requests, limits) } func podUsageHelper(requests api.ResourceList, limits api.ResourceList) api.ResourceList { 	result := api.ResourceList{} 	 	result[api.ResourcePods] = resource.MustParse("1") 	if request, found := requests[api.ResourceCPU]; found { 		result[api.ResourceCPU] = request 		result[api.ResourceRequestsCPU] = request 	} 	if limit, found := limits[api.ResourceCPU]; found { 		result[api.ResourceLimitsCPU] = limit 	} 	if request, found := requests[api.ResourceMemory]; found { 		result[api.ResourceMemory] = request 		result[api.ResourceRequestsMemory] = request 	} 	if limit, found := limits[api.ResourceMemory]; found { 		result[api.ResourceLimitsMemory] = limit 	} 	return result } 
  | 
GenericRegistry
如PodEvaluator这样的Evaluator有非常多个,所以需要有一个地方来管理这些Evaluator,这个管理Evaluator的就是GenericRegistry。
GenericRegistry定义在/pkg/quota/generic/registry.go中:
1 2 3 4 5 6 7 8 9 10 11 12 13 
  | type GenericRegistry struct { 	 	InternalEvaluators map[unversioned.GroupKind]quota.Evaluator } ```  可以看出,GenericRegistry中有字段InternalEvaluators,里面记录了GK和对应Evaluator的映射关系。可以通过Evaluators()方法获取InternalEvaluators。 ``` Go func (r *GenericRegistry) Evaluators() map[unversioned.GroupKind]quota.Evaluator { 	return r.InternalEvaluators } 
  | 
GenericRegistry的生成函数定义在/pkg/quota/evaluator/core/registry.go中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 
  | func NewRegistry(kubeClient clientset.Interface, f informers.SharedInformerFactory) quota.Registry { 	pod := NewPodEvaluator(kubeClient, f) 	service := NewServiceEvaluator(kubeClient) 	replicationController := NewReplicationControllerEvaluator(kubeClient) 	resourceQuota := NewResourceQuotaEvaluator(kubeClient) 	secret := NewSecretEvaluator(kubeClient) 	configMap := NewConfigMapEvaluator(kubeClient) 	persistentVolumeClaim := NewPersistentVolumeClaimEvaluator(kubeClient, f) 	return &generic.GenericRegistry{ 		InternalEvaluators: map[unversioned.GroupKind]quota.Evaluator{ 			pod.GroupKind():                   pod, 			service.GroupKind():               service, 			replicationController.GroupKind(): replicationController, 			secret.GroupKind():                secret, 			configMap.GroupKind():             configMap, 			resourceQuota.GroupKind():         resourceQuota, 			persistentVolumeClaim.GroupKind(): persistentVolumeClaim, 		}, 	} } 
  | 
可以看出,NewRegistry()会把PodEvaluator, ReplicationControllerEvaluator, ResourceQuotaEvaluator, SecretEvaluator, ConfigMapEvaluator, PersistentVolumeClaimEvaluator注册到GenericRegistry。
入口
整个Evaluator的入口定义在/pkg/quota/install/registry.go中:
1 2 3 4 5 6 
  | func NewRegistry(kubeClient clientset.Interface, f informers.SharedInformerFactory) quota.Registry { 	 	return core.NewRegistry(kubeClient, f) } 
  | 
这里的core.NewRegistry()就是上面的NewRegistry(),返回GenericRegistry。得到GenericRegistry后,通过调用Evaluators()方法,即可获取全部的Evaluator。