K8s-kubectl(执行流程)
K8s-kubectl(执行流程)
基于1.25
什么是kubectl
kubectl是kube-apiserver的客户端,通过向kube-apiserver发送HTTP请求,实现对K8s集群的控制
初始化命令对象
kubectl使用NewCmdXX 进行初始化,主要有俩类对象:
- cobra.Command:提供命令对象
- XXXoptions:Options命令参数对象
补全命令参数
支持补全成命令执行的相关工具类,形成完整的Options,主要工具包含三种
- Genericclioptions.Recorder:用于记录资源对象发生变化的原因,对于由kubectl触发的变更,genericclioptions.Recoder会将完整的命令记录到资源对象的kubernetes.io/change-cause注解中
- resource.QueryParamVerifier:用于检查资源对象是否支持DryRun和资源对象娇艳
- options.ToPrinter/options.PrintObj:打印相关函数,用于获取命令执行结果之后,执行结果打印到终端
校验命令参数
- 依赖参数校验。比如,在使用kubectl apply 使用了
--force-conflicts指定出现冲突的时候,合并更新,同时必须使用--service-side指定服务端应用 - 兼容参数校验。比如,在使用kubectl create的时候,使用了
raw指定服务端的URL地址,就会执行使用Client把请求发送给服务端,不在支持使用–output定制结果输出
执行命令输出结果
校验命令参数之后,回进入到命令执行阶段。
其中在里面饮入了Builder和多层嵌套的Vistor模式,实现了不修改结果的情况下在现有的结果上添加新操作
定制资源构造器
resource.Builder 使用了Builder模式
-
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// Factory provides abstractions that allow the Kubectl command to be extended across multiple types
// of resources and different API sets.
// The rings are here for a reason. In order for composers to be able to provide alternative factory implementations
// they need to provide low level pieces of *certain* functions so that when the factory calls back into itself
// it uses the custom version of the function. Rather than try to enumerate everything that someone would want to override
// we split the factory into rings, where each ring can depend on methods in an earlier ring, but cannot depend
// upon peer methods in its own ring.
// TODO: make the functions interfaces
// TODO: pass the various interfaces on the factory directly into the command constructors (so the
// commands are decoupled from the factory).
type Factory interface {
genericclioptions.RESTClientGetter
// DynamicClient returns a dynamic client ready for use
// 实现看三种Client的交互模式
DynamicClient() (dynamic.Interface, error)
// KubernetesClientSet gives you back an external clientset
KubernetesClientSet() (*kubernetes.Clientset, error)
// Returns a RESTClient for accessing Kubernetes resources or an error.
RESTClient() (*restclient.RESTClient, error)
// NewBuilder returns an object that assists in loading objects from both disk and the server
// and which implements the common patterns for CLI interactions with generic resources.
// 实现Builder的对象实例化
NewBuilder() *resource.Builder
// Returns a RESTClient for working with the specified RESTMapping or an error. This is intended
// for working with arbitrary resources and is not guaranteed to point to a Kubernetes APIServer.
ClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error)
// Returns a RESTClient for working with Unstructured objects.
UnstructuredClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error)
// Returns a schema that can validate objects stored on disk.
// 提供了获取校验器对象的方法
Validator(validationDirective string) (validation.Schema, error)
// Used for retrieving openapi v2 resources.
openapi.OpenAPIResourcesGetter
// OpenAPIV3Schema returns a client for fetching parsed schemas for
// any group version
OpenAPIV3Client() (openapiclient.Client, error)
}
组装Vistor多层嵌套
-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17r := f.NewBuilder().
// 在发送请求到kube-apiserver到时候,使用Unstructured 非结构化数据
Unstructured().
// 配置对请求参数对象进行校验的校验器
Schema(schema).
// 知识在处理过程中出现错误不要立即结束流程,尽可能执行后面的流程
ContinueOnError().
// 指定暂存对象的命名空间,没有指定使用默认命名空间
NamespaceParam(cmdNamespace).DefaultNamespace().
// 配置输入参数重涉及到网络或者本地文件/目录
FilenameParam(enforceNamespace, &o.FilenameOptions).
// 指示在请求资源时使用标签选择器
LabelSelectorParam(o.Selector).
// 指示在处理请求数据遇到的嵌套列表数据展开并且拉平胃大列表
Flatten().
// 构造
Do()
Vistor接口的相关定义:
-
1
2
3
4// Visitor lets clients walk a list of resources.
type Visitor interface {
Visit(VisitorFunc) error
} -
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// Info contains temporary info to execute a REST call, or show the results
// of an already completed REST call.
type Info struct {
// Client will only be present if this builder was not local
Client RESTClient
// Mapping will only be present if this builder was not local
Mapping *meta.RESTMapping
// Namespace will be set if the object is namespaced and has a specified value.
Namespace string
Name string
// Optional, Source is the filename or URL to template file (.json or .yaml),
// or stdin to use to handle the resource
Source string
// Optional, this is the most recent value returned by the server if available. It will
// typically be in unstructured or internal forms, depending on how the Builder was
// defined. If retrieved from the server, the Builder expects the mapping client to
// decide the final form. Use the AsVersioned, AsUnstructured, and AsInternal helpers
// to alter the object versions.
// If Subresource is specified, this will be the object for the subresource.
Object runtime.Object
// Optional, this is the most recent resource version the server knows about for
// this type of resource. It may not match the resource version of the object,
// but if set it should be equal to or newer than the resource version of the
// object (however the server defines resource version).
ResourceVersion string
// Optional, if specified, the object is the most recent value of the subresource
// returned by the server if available.
Subresource string
}
// Visit implements Visitor
func (i *Info) Visit(fn VisitorFunc) error {
return fn(i, nil)
}
常见的Visitor实例用用途
| Visitor | 用途 |
|---|---|
| DecoratedVistitor | 提供多种装饰器函数,通过遍历自身的装饰器func 对Info和error处理,如果任何一个装饰函数报错立即返回 |
| ContinueOnErrorVisitor | 在执行多层Visitor匿名函数,如果发生错误不会马上退出,把错误收集到error数组中,返回 |
| FlattenListVistor | 将列表类型的通用资源展开为一个个独立的资源对象,并且试用其装饰的Vistor对象依次访问展开之后的资源对象 |
| EagerVistor | Vistor集合类型,依次执行集合中的每个Vistor,同意收集错误为一个error信息返回 |
| FileVistor | 通过本地方式指定资源对象声明文件,会访问对象描述文件,并且通过StreamVistor将转换为Info |
| StreamVistitor | 从io.Reader获取数据流,转换为JSON,通过schema检查,最后转为info对象 |
执行命令获取结果
-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25err = r.Visit(func(info *resource.Info, err error) error {
if err != nil {
return err
}
if err := util.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info.Object, scheme.DefaultJSONEncoder()); err != nil {
return cmdutil.AddSourceToErr("creating", info.Source, err)
}
if err := o.Recorder.Record(info.Object); err != nil {
klog.V(4).Infof("error recording current command: %v", err)
}
if o.DryRunStrategy != cmdutil.DryRunClient {
if o.DryRunStrategy == cmdutil.DryRunServer {
if err := o.DryRunVerifier.HasSupport(info.Mapping.GroupVersionKind); err != nil {
return cmdutil.AddSourceToErr("creating", info.Source, err)
}
}
obj, err := resource.
NewHelper(info.Client, info.Mapping).
DryRun(o.DryRunStrategy == cmdutil.DryRunServer).
WithFieldManager(o.fieldManager).
WithFieldValidation(o.ValidationDirective).
Create(info.Namespace, true, info.Object)
}
打印执行结果
kubectl使用PrintObj func和ToPrinter func打印上一步获取的执行结果
-
1
2
3
4
5
6
7
8
9
10
11
12
13// ResourcePrinterFunc is a function that can print objects
type ResourcePrinterFunc func(runtime.Object, io.Writer) error
// PrintObj implements ResourcePrinter
func (fn ResourcePrinterFunc) PrintObj(obj runtime.Object, w io.Writer) error {
return fn(obj, w)
}
// ResourcePrinter is an interface that knows how to print runtime objects.
type ResourcePrinter interface {
// PrintObj receives a runtime object, formats it and prints it to a writer.
PrintObj(runtime.Object, io.Writer) error
}
在补全命令阶段(Complete),根据传入打印参数的构造ResourcePrinter对象赋值为PrintObj,实现了(YAML、JSON)等打印命令执行结果
-
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
55
56
// Complete adapts from the command line args and factory to the data required.
func (o *AnnotateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
var err error
o.RecordFlags.Complete(cmd)
o.Recorder, err = o.RecordFlags.ToRecorder()
if err != nil {
return err
}
o.outputFormat = cmdutil.GetFlagString(cmd, "output")
o.dryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd)
if err != nil {
return err
}
dynamicClient, err := f.DynamicClient()
if err != nil {
return err
}
o.dryRunVerifier = resource.NewQueryParamVerifier(dynamicClient, f.OpenAPIGetter(), resource.QueryParamDryRun)
cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.dryRunStrategy)
printer, err := o.PrintFlags.ToPrinter()
if err != nil {
return err
}
o.PrintObj = func(obj runtime.Object, out io.Writer) error {
return printer.PrintObj(obj, out)
}
if o.list && len(o.outputFormat) > 0 {
return fmt.Errorf("--list and --output may not be specified together")
}
o.namespace, o.enforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
if err != nil {
return err
}
o.builder = f.NewBuilder()
o.unstructuredClientForMapping = f.UnstructuredClientForMapping
// retrieves resource and annotation args from args
// also checks args to verify that all resources are specified before annotations
resources, annotationArgs, err := cmdutil.GetResourcesAndPairs(args, "annotation")
if err != nil {
return err
}
o.resources = resources
o.newAnnotations, o.removeAnnotations, err = parseAnnotations(annotationArgs)
if err != nil {
return err
}
return nil
}
| ResourcePrinter | 说明 |
|---|---|
| YAMLPrinter | 以YAML打印结果 |
| JSONPrinter | 以JSON打印结果 |
| HuamanReadablePrinter | 为指定输出格式默认使用Printer格式打印器,以可读性是打印执行结果,结果为表格 |
| GoTempldatePrinter | 按用户提供的GoTemplate执行打印结果 |
| TablePrinter | 转换为表格打印 |
| CustomColumnsPrinter | 按指定列名打印结果 |
| SortingPrinter | 按指定字段排序打印结果 |
| JSONPathPrinter | 按照用户提供的JSONpath打印结果 |
| NamePrinter | 为打印资源专门实现的Prnter,以rescue/name打印资源名称 |
| EventPrinter | 专门打印Event资源的Printer |
| OmitManageredFieldsPrinter | 在打印资源忽略managerField字段 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Joohwan!
评论


