当前位置 博文首页 > mark's technic world:kubectl源码分析之top node
发布一个k8s部署视频:https://edu.csdn.net/course/detail/26967
课程内容:各种k8s部署方式。包括minikube部署,kubeadm部署,kubeasz部署,rancher部署,k3s部署。包括开发测试环境部署k8s,和生产环境部署k8s。
腾讯课堂连接地址https://ke.qq.com/course/478827?taid=4373109931462251&tuin=ba64518
第二个视频发布??https://edu.csdn.net/course/detail/27109
腾讯课堂连接地址https://ke.qq.com/course/484107?tuin=ba64518
介绍主要的k8s资源的使用配置和命令。包括configmap,pod,service,replicaset,namespace,deployment,daemonset,ingress,pv,pvc,sc,role,rolebinding,clusterrole,clusterrolebinding,secret,serviceaccount,statefulset,job,cronjob,podDisruptionbudget,podSecurityPolicy,networkPolicy,resourceQuota,limitrange,endpoint,event,conponentstatus,node,apiservice,controllerRevision等。
第三个视频发布:https://edu.csdn.net/course/detail/27574
详细介绍helm命令,学习helm chart语法,编写helm chart。深入分析各项目源码,学习编写helm插件
第四个课程发布:https://edu.csdn.net/course/detail/28488
本课程将详细介绍k8s所有命令,以及命令的go源码分析,学习知其然,知其所以然
?
加qq群,请联系:
————————————————
//创建top命令
func NewCmdTop(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
cmd := &cobra.Command{//创建cobra命令
Use: "top",
Short: i18n.T("Display Resource (CPU/Memory/Storage) usage."),
Long: topLong,
Run: cmdutil.DefaultSubCommandRun(streams.ErrOut),
}
// create subcommands
cmd.AddCommand(NewCmdTopNode(f, nil, streams))//添加node子命令
cmd.AddCommand(NewCmdTopPod(f, nil, streams))//添加pod子命令
return cmd
}
type TopNodeOptions struct {//top node结构体
ResourceName string
Selector string
SortBy string
NoHeaders bool
NodeClient corev1client.CoreV1Interface
HeapsterOptions HeapsterTopOptions
Client *metricsutil.HeapsterMetricsClient
Printer *metricsutil.TopCmdPrinter
DiscoveryClient discovery.DiscoveryInterface
MetricsClient metricsclientset.Interface
genericclioptions.IOStreams
}
type HeapsterTopOptions struct {//Heapster结构体
Namespace string
Service string
Scheme string
Port string
}
func (o *HeapsterTopOptions) Bind(flags *pflag.FlagSet) {//设置heapster选项
if len(o.Namespace) == 0 {
o.Namespace = metricsutil.DefaultHeapsterNamespace
}
if len(o.Service) == 0 {
o.Service = metricsutil.DefaultHeapsterService
}
if len(o.Scheme) == 0 {
o.Scheme = metricsutil.DefaultHeapsterScheme
}
if len(o.Port) == 0 {
o.Port = metricsutil.DefaultHeapsterPort
}
flags.StringVar(&o.Namespace, "heapster-namespace", o.Namespace, "Namespace Heapster service is located in")
flags.StringVar(&o.Service, "heapster-service", o.Service, "Name of Heapster service")
flags.StringVar(&o.Scheme, "heapster-scheme", o.Scheme, "Scheme (http or https) to connect to Heapster as")
flags.StringVar(&o.Port, "heapster-port", o.Port, "Port name in service to use")
}
//创建top node命令
func NewCmdTopNode(f cmdutil.Factory, o *TopNodeOptions, streams genericclioptions.IOStreams) *cobra.Command {
if o == nil {
o = &TopNodeOptions{//初始化结构体
IOStreams: streams,
}
}
cmd := &cobra.Command{//创建cobra命令
Use: "node [NAME | -l label]",
DisableFlagsInUseLine: true,
Short: i18n.T("Display Resource (CPU/Memory/Storage) usage of nodes"),
Long: topNodeLong,
Example: topNodeExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))//准备
cmdutil.CheckErr(o.Validate())//校验
cmdutil.CheckErr(o.RunTopNode())//运行
},
Aliases: []string{"nodes", "no"},// 别名
}
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 nodes list using specified field. The field can be either 'cpu' or 'memory'.")//sort-by选项
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 *TopNodeOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
if len(args) == 1 {
o.ResourceName = args[0]//设置resource
} else if len(args) > 1 {
return cmdutil.UsageErrorf(cmd, "%s", cmd.Use)
}
clientset, err := f.KubernetesClientSet()//获取clientset
if err != nil {
return err
}
o.DiscoveryClient = clientset.DiscoveryClient//设置discoveryclient
config, err := f.ToRESTConfig()//获取rest config
if err != nil {
return err
}
o.MetricsClient, err = metricsclientset.NewForConfig(config)//设置MetricsClient
if err != nil {
return err
}
o.NodeClient = clientset.CoreV1()//设置NodeClient
o.Client = metricsutil.NewHeapsterMetricsClient(clientset.CoreV1(), o.HeapsterOptions.Namespace, o.HeapsterOptions.Scheme, o.HeapsterOptions.Service, o.HeapsterOptions.Port)//设置Heapster client
o.Printer = metricsutil.NewTopCmdPrinter(o.Out)//设置printer
return nil
}
//校验函数
func (o *TopNodeOptions) Validate() error {
if len(o.SortBy) > 0 {//排序
if o.SortBy != sortByCPU && o.SortBy != sortByMemory {//只能是cpu或momery
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 TopNodeOptions) RunTopNode() error {
var err error
selector := labels.Everything()//设置selector
if len(o.Selector) > 0 {//如果--selector有值
selector, err = labels.Parse(o.Selector)//设置selector
if err != nil {
return err
}
}
apiGroups, err := o.DiscoveryClient.ServerGroups()//获取apigroup
if err != nil {
return err
}
metricsAPIAvailable := SupportedMetricsAPIVersionAvailable(apiGroups)//判断Metrics是否支持这个apiGroup
metrics := &metricsapi.NodeMetricsList{}
if metricsAPIAvailable {//如果Metrics支持这个apiGroup
metrics, err = getNodeMetricsFromMetricsAPI(o.MetricsClient, o.ResourceName, selector)//获取metrics
if err != nil {
return err
}
} else {//如果不支持
metrics, err = o.Client.GetNodeMetrics(o.ResourceName, selector.String())//通过client获取metrics
if err != nil {
return err
}
}
if len(metrics.Items) == 0 {//如果没有metrics
return errors.New("metrics not available yet")
}
var nodes []v1.Node
if len(o.ResourceName) > 0 {//如果资源有值
node, err := o.NodeClient.Nodes().Get(o.ResourceName, metav1.GetOptions{})//获取资源名称对应节点
if err != nil {
return err
}
nodes = append(nodes, *node)//append节点
} else {//如果selector有值
nodeList, err := o.NodeClient.Nodes().List(metav1.ListOptions{//获取selector对应节点
LabelSelector: selector.String(),
})
if err != nil {
return err
}
nodes = append(nodes, nodeList.Items...)//append节点
}
allocatable := make(map[string]v1.ResourceList)//可分配资源map
for _, n := range nodes {//遍历节点,设置可分配资源
allocatable[n.Name] = n.Status.Allocatable
}
return o.Printer.PrintNodeMetrics(metrics.Items, allocatable, o.NoHeaders, o.SortBy)//打印结果
}
func getNodeMetricsFromMetricsAPI(metricsClient metricsclientset.Interface, resourceName string, selector labels.Selector) (*metricsapi.NodeMetricsList, error) {//获取metrics
var err error
versionedMetrics := &metricsV1beta1api.NodeMetricsList{}//构造metricsList对象
mc := metricsClient.MetricsV1beta1()//获取client
nm := mc.NodeMetricses()//获取node metrics client
if resourceName != "" {//如果资源名称不为空
m, err := nm.Get(resourceName, metav1.GetOptions{})//获取metrics
if err != nil {
return nil, err
}
versionedMetrics.Items = []metricsV1beta1api.NodeMetrics{*m}//包装metricsList
} else {//如果selector有值
versionedMetrics, err = nm.List(metav1.ListOptions{LabelSelector: selector.String()})//通过selector获取metrics
if err != nil {
return nil, err
}
}
metrics := &metricsapi.NodeMetricsList{}
err = metricsV1beta1api.Convert_v1beta1_NodeMetricsList_To_metrics_NodeMetricsList(versionedMetrics, metrics, nil)//把metrics转成NodeMetricsList
if err != nil {
return nil, err
}
return metrics, nil//返回NodeMetricsList
}
//打印node metrics
func (printer *TopCmdPrinter) PrintNodeMetrics(metrics []metricsapi.NodeMetrics, availableResources map[string]v1.ResourceList, noHeaders bool, sortBy string) error {
if len(metrics) == 0 {//metrics为空返回
return nil
}
w := printers.GetNewTabWriter(printer.out)//包装tab Writer
defer w.Flush()//defer刷新
n, err := NewNodeMetricsSorter(metrics, sortBy)//metrics排序
if err != nil {
return err
}
sort.Sort(n)//执行排序
if !noHeaders {//如果不是noHeaders,打印headers
printColumnNames(w, NodeColumns)
}
var usage v1.ResourceList
for _, m := range metrics {//遍历metrics
err := scheme.Scheme.Convert(&m.Usage, &usage, nil)//转换usage
if err != nil {
return err
}
printMetricsLine(w, &ResourceMetricsInfo{//打印一行metrics info
Name: m.Name,
Metrics: usage,
Available: availableResources[m.Name],
})
delete(availableResources, m.Name)//删除availableResources 中已经打印的
}
// print lines for nodes of which the metrics is unreachable.
for nodeName := range availableResources {//遍历availableResources,打印没有metrics的node
printMissingMetricsNodeLine(w, nodeName)
}
return nil
}
//判断metrics是否支持apiGroup
func SupportedMetricsAPIVersionAvailable(discoveredAPIGroups *metav1.APIGroupList) bool {
for _, discoveredAPIGroup := range discoveredAPIGroups.Groups {
if discoveredAPIGroup.Name != metricsapi.GroupName {//如果groupname不同则跳过
continue
}
for _, version := range discoveredAPIGroup.Versions {
for _, supportedVersion := range supportedMetricsAPIVersions {
if version.Version == supportedVersion {//如果version为supportedVersion 则返回true
return true
}
}
}
}
return false//返回false
}
?
?
?
?
?
?
?
?
?
?
cs