聚焦目标
理解kubectl是怎么向kube-apiserver发送请求的
目录
- 向kube-apiserver发送请求
- RESTful客户端是怎么创建的
- Object是怎么生成的
- 发送post请求
- kubectl第一阶段源码阅读总结
send request
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
| obj, err := resource. NewHelper(info.Client, info.Mapping). DryRun(o.DryRunStrategy == cmdutil.DryRunServer). WithFieldManager(o.fieldManager). Create(info.Namespace, true, info.Object)
m.createResource(m.RESTClient, m.Resource, namespace, obj, options)
func (m *Helper) createResource(c RESTClient, resource, namespace string, obj runtime.Object, options *metav1.CreateOptions) (runtime.Object, error) { return c.Post(). NamespaceIfScoped(namespace, m.NamespaceScoped). Resource(resource). VersionedParams(options, metav1.ParameterCodec). Body(obj). Do(context.TODO()). Get() }
|
RESTful Client
我们先来看看,与kube-apiserver交互的Client是怎么创建的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| r.Visit(func(info *resource.Info, err error) error{})
r := f.NewBuilder(). Unstructured(). Schema(schema). ContinueOnError(). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(enforceNamespace, &o.FilenameOptions). LabelSelectorParam(o.Selector). Flatten(). Do()
func (b *Builder) getClient(gv schema.GroupVersion) (RESTClient, error)
NewClientWithOptions(client, b.requestTransforms...)
|
Object
Object
这个对象是怎么获取到的呢?因为我们的数据源是来自文件的,那么我们最直观的想法就是FileVisitor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| func (v *FileVisitor) Visit(fn VisitorFunc) error { return v.StreamVisitor.Visit(fn) }
func (v *StreamVisitor) Visit(fn VisitorFunc) error { d := yaml.NewYAMLOrJSONDecoder(v.Reader, 4096) for { info, err := v.infoForData(ext.Raw, v.Source) } }
func (m *mapper) infoForData(data []byte, source string) (*Info, error){ obj, gvk, err := m.decoder.Decode(data, nil, nil) }
|
这时,我们想回头去看,这个mapper是在什么时候被定义的?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| func (b *Builder) Unstructured() *Builder { b.mapper = &mapper{ localFn: b.isLocal, restMapperFn: b.restMapperFn, clientFn: b.getClient, decoder: &metadataValidatingDecoder{unstructured.UnstructuredJSONScheme}, } return b }
func (s unstructuredJSONScheme) decode(data []byte) (runtime.Object, error) { }
|
Post
了解了REST Client
和Object
的大致产生逻辑后,我们再回过头来看发送的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| c.Post(). NamespaceIfScoped(namespace, m.NamespaceScoped). Resource(resource). VersionedParams(options, metav1.ParameterCodec). Body(obj). Do(context.TODO()). Get()
err := r.request(ctx, func(req *http.Request, resp *http.Response) { result = r.transformResponse(resp, req) })
switch t := out.(type) { case *metav1.Status: if t.Status != metav1.StatusSuccess { return nil, errors.FromObject(t) } }
|
Summary
到这里我们对kubectl的功能有了初步的了解,希望大家对以下的关键内容有所掌握:
- 命令行采用了
cobra
库,主要支持7个大类的命令;
- 掌握Visitor设计模式,这个是kubectl实现各类资源对象的解析和校验的核心;
- 初步了解
RESTClient
和Object
这两个对象,它们是贯穿kubernetes的核心概念;
- 调用逻辑
- cobra匹配子命令
- 用Visitor模式构建Builder
- 用RESTClient将Object发送到kube-apiserver
Github: https://github.com/Junedayday/code_reading
Blog: http://junes.tech/
Bilibili:https://space.bilibili.com/293775192
公众号:golangcoding