kubectl源码分析之top pod

 欢迎关注我的公众号:

 目前刚开始写一个月,一共写了18篇原创文章,文章目录如下:

istio多集群探秘,部署了50次多集群后我得出的结论

istio多集群链路追踪,附实操视频

istio防故障利器,你知道几个,istio新手不要读,太难!

istio业务权限控制,原来可以这么玩

istio实现非侵入压缩,微服务之间如何实现压缩

不懂envoyfilter也敢说精通istio系列-http-rbac-不要只会用AuthorizationPolicy配置权限

不懂envoyfilter也敢说精通istio系列-02-http-corsFilter-不要只会vs

不懂envoyfilter也敢说精通istio系列-03-http-csrf filter-再也不用再代码里写csrf逻辑了

不懂envoyfilter也敢说精通istio系列http-jwt_authn-不要只会RequestAuthorization

不懂envoyfilter也敢说精通istio系列-05-fault-filter-故障注入不止是vs

不懂envoyfilter也敢说精通istio系列-06-http-match-配置路由不只是vs

不懂envoyfilter也敢说精通istio系列-07-负载均衡配置不止是dr

不懂envoyfilter也敢说精通istio系列-08-连接池和断路器

不懂envoyfilter也敢说精通istio系列-09-http-route filter

不懂envoyfilter也敢说精通istio系列-network filter-redis proxy

不懂envoyfilter也敢说精通istio系列-network filter-HttpConnectionManager

不懂envoyfilter也敢说精通istio系列-ratelimit-istio ratelimit完全手册

 

加qq群,请联系:


————————————————

type TopPodOptions struct {//top pod结构体
	ResourceName    string
	Namespace       string
	Selector        string
	SortBy          string
	AllNamespaces   bool
	PrintContainers bool
	NoHeaders       bool
	PodClient       corev1client.PodsGetter
	HeapsterOptions HeapsterTopOptions
	Client          *metricsutil.HeapsterMetricsClient
	Printer         *metricsutil.TopCmdPrinter
	DiscoveryClient discovery.DiscoveryInterface
	MetricsClient   metricsclientset.Interface

	genericclioptions.IOStreams
}
//创建top pod命令
func NewCmdTopPod(f cmdutil.Factory, o *TopPodOptions, streams genericclioptions.IOStreams) *cobra.Command {
	if o == nil {
		o = &TopPodOptions{//初始化结构体
			IOStreams: streams,
		}
	}

	cmd := &cobra.Command{//创建cobra命令
		Use:                   "pod [NAME | -l label]",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Display Resource (CPU/Memory/Storage) usage of pods"),
		Long:                  topPodLong,
		Example:               topPodExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(f, cmd, args))//准备
			cmdutil.CheckErr(o.Validate())//校验
			cmdutil.CheckErr(o.RunTopPod())//运行
		},
		Aliases: []string{"pods", "po"},//别名
	}
	cmd.Flags().StringVarP(&o.Selector, "selector", "l", o.Selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")//selector选项
	cmd.Flags().StringVar(&o.SortBy, "sort-by", o.Selector, "If non-empty, sort pods list using specified field. The field can be either 'cpu' or 'memory'.")//sort-by选项
	cmd.Flags().BoolVar(&o.PrintContainers, "containers", o.PrintContainers, "If present, print usage of containers within a pod.")//containers选项
	cmd.Flags().BoolVarP(&o.AllNamespaces, "all-namespaces", "A", o.AllNamespaces, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.")//所有名称空间选项
	cmd.Flags().BoolVar(&o.NoHeaders, "no-headers", o.NoHeaders, "If present, print output without headers.")//no-headers选项
	o.HeapsterOptions.Bind(cmd.Flags())//绑定heapster选项
	return cmd
}
//准备函数
func (o *TopPodOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
	var err error
	if len(args) == 1 {//如果参数是1个,则把参数赋值给资源
		o.ResourceName = args[0]
	} else if len(args) > 1 {//参数大于1个报错
		return cmdutil.UsageErrorf(cmd, "%s", cmd.Use)
	}

	o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()//设置namespace
	if err != nil {
		return err
	}
	clientset, err := f.KubernetesClientSet()//获取clientset
	if err != nil {
		return err
	}

	o.DiscoveryClient = clientset.DiscoveryClient//从clientset获取discoveryClient
	config, err := f.ToRESTConfig()//获取restconfig
	if err != nil {
		return err
	}
	o.MetricsClient, err = metricsclientset.NewForConfig(config)//通过restConfig获取MetrixClient
	if err != nil {
		return err
	}

	o.PodClient = clientset.CoreV1()//通过clientset获取PodClient
	o.Client = metricsutil.NewHeapsterMetricsClient(clientset.CoreV1(), o.HeapsterOptions.Namespace, o.HeapsterOptions.Scheme, o.HeapsterOptions.Service, o.HeapsterOptions.Port)//设置heapersterclient

	o.Printer = metricsutil.NewTopCmdPrinter(o.Out)//设置打印对象
	return nil
}


//校验
func (o *TopPodOptions) Validate() error {
	if len(o.SortBy) > 0 {//如果sort-by有值,则值必须为memory或cpu
		if o.SortBy != sortByCPU && o.SortBy != sortByMemory {
			return errors.New("--sort-by accepts only cpu or memory")
		}
	}
	if len(o.ResourceName) > 0 && len(o.Selector) > 0 {//资源名称和selector不能同时指定
		return errors.New("only one of NAME or --selector can be provided")
	}
	return nil
}
//运行
func (o TopPodOptions) RunTopPod() error {
	var err error
	selector := labels.Everything()//设置标签选择器为所有
	if len(o.Selector) > 0 {//如果--selector不为空,设置标签选择器为解析后的值
		selector, err = labels.Parse(o.Selector)
		if err != nil {
			return err
		}
	}

	apiGroups, err := o.DiscoveryClient.ServerGroups()//从discoveryClient获取apiGroup
	if err != nil {
		return err
	}

	metricsAPIAvailable := SupportedMetricsAPIVersionAvailable(apiGroups)//判断metrics是否支持apiGroup

	metrics := &metricsapi.PodMetricsList{}//创建PodMetricsList对象
	if metricsAPIAvailable {//如果metrics支持apiGroup
		metrics, err = getMetricsFromMetricsAPI(o.MetricsClient, o.Namespace, o.ResourceName, o.AllNamespaces, selector)//获取metrics
		if err != nil {
			return err
		}
	} else {
		metrics, err = o.Client.GetPodMetrics(o.Namespace, o.ResourceName, o.AllNamespaces, selector)//通过client获取metrics
		if err != nil {
			return err
		}
	}

	// TODO: Refactor this once Heapster becomes the API server.
	// First we check why no metrics have been received.
	if len(metrics.Items) == 0 {//如果metrics为空
		// If the API server query is successful but all the pods are newly created,
		// the metrics are probably not ready yet, so we return the error here in the first place.
		e := verifyEmptyMetrics(o, selector)//验证空metrics
		if e != nil {
			return e
		}
	}
	if err != nil {
		return err
	}

	return o.Printer.PrintPodMetrics(metrics.Items, o.PrintContainers, o.AllNamespaces, o.NoHeaders, o.SortBy)//打印metrics
}
//通过metrics api获取metrics
func getMetricsFromMetricsAPI(metricsClient metricsclientset.Interface, namespace, resourceName string, allNamespaces bool, selector labels.Selector) (*metricsapi.PodMetricsList, error) {
	var err error
	ns := metav1.NamespaceAll//名称空间为所有
	if !allNamespaces {//如果没有指定all-namespaces,名称空间为特定值
		ns = namespace
	}
	versionedMetrics := &metricsv1beta1api.PodMetricsList{}//构造PodMetricsList对象
	if resourceName != "" {//如果资源名称不为空
		m, err := metricsClient.MetricsV1beta1().PodMetricses(ns).Get(resourceName, metav1.GetOptions{})//获取指定资源名称的metrics
		if err != nil {
			return nil, err
		}
		versionedMetrics.Items = []metricsv1beta1api.PodMetrics{*m}//包装
	} else {
		versionedMetrics, err = metricsClient.MetricsV1beta1().PodMetricses(ns).List(metav1.ListOptions{LabelSelector: selector.String()})//通过labelselector获取metrics
		if err != nil {
			return nil, err
		}
	}
	metrics := &metricsapi.PodMetricsList{}//构造podMetricsList对象
	err = metricsv1beta1api.Convert_v1beta1_PodMetricsList_To_metrics_PodMetricsList(versionedMetrics, metrics, nil)//把metrics转为PodMetricsList
	if err != nil {
		return nil, err
	}
	return metrics, nil//返回结果
}
//验证空metrics
func verifyEmptyMetrics(o TopPodOptions, selector labels.Selector) error {
	if len(o.ResourceName) > 0 {//如果资源名称不控
		pod, err := o.PodClient.Pods(o.Namespace).Get(o.ResourceName, metav1.GetOptions{})//获取pod
		if err != nil {
			return err
		}
		if err := checkPodAge(pod); err != nil {//检查年龄
			return err
		}
	} else {
		pods, err := o.PodClient.Pods(o.Namespace).List(metav1.ListOptions{//获取符合selector的所有pod
			LabelSelector: selector.String(),
		})
		if err != nil {
			return err
		}
		if len(pods.Items) == 0 {
			return nil
		}
		for _, pod := range pods.Items {//遍历pods检查年龄
			if err := checkPodAge(&pod); err != nil {
				return err
			}
		}
	}
	return errors.New("metrics not available yet")
}

func checkPodAge(pod *v1.Pod) error {
	age := time.Since(pod.CreationTimestamp.Time)//获取pod从创建到现在的时间
	if age > metricsCreationDelay {//如果pod存在时间大于特定时间
		message := fmt.Sprintf("Metrics not available for pod %s/%s, age: %s", pod.Namespace, pod.Name, age.String())
		klog.Warningf(message)//输出klog警告
		return errors.New(message)//返回错误
	} else {
		klog.V(2).Infof("Metrics not yet available for pod %s/%s, age: %s", pod.Namespace, pod.Name, age.String())//输出info
		return nil//返回nil
	}
}
// 打印pod metrics
func (printer *TopCmdPrinter) PrintPodMetrics(metrics []metricsapi.PodMetrics, printContainers bool, withNamespace bool, noHeaders bool, sortBy string) error {
	if len(metrics) == 0 {//如果metrics为空返回
		return nil
	}
	w := printers.GetNewTabWriter(printer.out)//把out包装为tabWriter
	defer w.Flush()//defer flush
	if !noHeaders {//如果没有指定noHeaders
		if withNamespace {//如果withnamespace
			printValue(w, NamespaceColumn)//打印namespace列
		}
		if printContainers {//如果打印容器为真
			printValue(w, PodColumn)//打印pod列
		}
		printColumnNames(w, PodColumns)//打印其他列
	}

	p, err := NewPodMetricsSorter(metrics, printContainers, withNamespace, sortBy)//排序器
	if err != nil {
		return err
	}
	sort.Sort(p)//执行排序

	for _, m := range metrics {// 遍历metrics
		err := printSinglePodMetrics(w, &m, printContainers, withNamespace)//打印单行
		if err != nil {
			return err
		}
	}
	return nil
}

你可能感兴趣的:(云原生)