• k8s学习(一)——kubectl与api-server之间的交互核心过程


    k8s的架构是用户使用kubectl工具对虚拟机资源进行各种各样的控制和定制。

    而kubectl本身并不包含对其核心资源的访问与控制。而是通过http通信与api-server进行交互实现资源的管理。

    而api-server的核心其实就是etcd数据库,它将各种资源的管理通过对etcd中的数据进行更改实现。这篇文章简要分析一下kubectl对

    api-server发起访问的过程。

    以kubectl create 指令为例,其指令的相关代码在kubernetes/pkg/kubectl/cmd/create.go这个文件中。

    一,参数的构造

    稍加分析不难看出,其创建资源的核心函数是func RunCreate()。

              r := builder.
    		Schema(schema).
    		ContinueOnError().
    		NamespaceParam(cmdNamespace).DefaultNamespace().
    		FilenameParam(enforceNamespace, &options.FilenameOptions).
    		SelectorParam(options.Selector).
    		Flatten().
    		Do()
    

     这段代码调用了builder的一串函数,最后生成一个Result类型的变量r。(Result 定义在 kubernetes/pkg/kubectl/resource/result.go)

    这里builder的作用是将之前解析得到的各种参数进行各种分析后填充到builder中,最后再生成一个Result类型的变量r。

    此时r中最关键的数据是visitor,这个visitor中包含了多个资源,也就是说一个visitor包含了一个对象(此处存疑)。

    接着以一个函数func为参数调用r的Visit函数。经过分析我们可以知道这是一个调用链函数,其中继续对参数进行各种分析,处理。

    r.Visit(func(info *resource.Info, err error) error {
    .....
    })

    大致的调用顺序为

    Result.Visit()
    ContinueOnError.Visit()
    Decorated.Visit()
    FlattenList.Visit()
    EagerVisitorList.Visit()
    FileVisitor.Visit()
    StreamVisitor.Visit()
    在StreamVisitor之前,都是对数据的各种处理,并不会调用func函数,在StreamVisitor.Visit()中一个关键的处理是生成一个临时变量Info。

    info, err := v.InfoForData(ext.Raw, v.Source)

    这里的ext.Raw和v.Source都是之前对用户的输入进行解析的结果。

    ext.Raw是byte[]类型,v.Source是String类型,打印出来:

    ext.Raw={
    "apiVersion":"v1",
    "kind":"Pod",
    "metadata":
        {"name":"with-node-affinity-2"},
    "spec":
    {"affinity":
        {"nodeAffinity":{"preferredDuringSchedulingIgnoredDuringExecution":[{"preference":{"matchExpressions":[{"key":"another-node-label-key","operator":"In","values":["another-node-label-value"]}]},
    "weight":1}],
    "requiredDuringSchedulingIgnoredDuringExecution":{"nodeSelectorTerms":[{"matchExpressions":[{"key":"kubernetes.io/e2e-az-name","operator":"In","values":["e2e-az1","e2e-az2"]}]}]}}},
    "containers":[{"image":"gcr.io/google_containers/pause:2.0","name":"with-node-affinity"}]}},
    
    
    
    
    v.Source=/home/wlh/mywork/yaml_file/pod-with-node-affinity.yaml

    可以看到其中存储了生成的资源的各种特性,有了这个info之后执行func(info)。

    二,访问api-server

    得到了info这个数据结构后,调用func()函数对api-server发起访问请求。

    if !dryRun {
    			if err := createAndRefresh(info); err != nil {
    				return cmdutil.AddSourceToErr("creating", info.Source, err)
    			}
    		}
    

    这个dryRun标志位的意思是,只打印出将要创建的资源的各种特性,而不会真正去创建他。

    而createAndRefresh函数中的核心调用是

    obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
    

     这里创建了一个Helper类型的对象,仔细分析后不难发现Info.Client中定义了访问动作,而info.Mapping中定义了这些动作所要访问的资源。

    此时Helper中已经包含了发起一个对api-server请求的所有资源,接着调用Create函数,它创建一个具体去执行这些请求的Request对象。(定义在kubernetes/vendor/k8s.io/client-go/rest/request.go中)

    Requeste发起对api-server的请求,并且将访问存储在ResutInfo中,与此同时返回一个Runtime.Object对象。

    这样一次完整的访问api-server的流程就完成了。

  • 相关阅读:
    【转载】这才是真正的表扩展方案
    【转载】啥,又要为表增加一列属性?
    【转载】这才是真正的分布式锁
    mysql备份表sql
    selenium定位当前处于那个iframe(frame)中
    MQ手动推送消息
    报表导出时间格式数据多‘0‘
    python里的原始字符串
    qq邮箱设置授权码方法(jenkins)
    Apache与Tomcat有什么关系和区别(转)
  • 原文地址:https://www.cnblogs.com/elnino/p/7206712.html
Copyright © 2020-2023  润新知