- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
kubectl 看了也有一段时间,期间写了两篇设计模式的文章,是时候对 kubectl 做个回顾了.
kubectl 是 kubernetes 的命令行工具,通过 kubectl 实现资源的增删改查。kubectl 通过 client-go 和 kube-apiserver 进行交互,其背后封装了 https ,配置文件为 kubeconfig .
kubectl 的命令行框架为 Cobra 。首先,将外部参数,配置统统赋给 KubectlOptions 对象:
// NewDefaultKubectlCommand creates the `kubectl` command with default arguments
func NewDefaultKubectlCommand() *cobra.Command {
return NewDefaultKubectlCommandWithArgs(KubectlOptions{
PluginHandler: NewDefaultPluginHandler(plugin.ValidPluginFilenamePrefixes),
Arguments: os.Args,
ConfigFlags: defaultConfigFlags,
IOStreams: genericiooptions.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr},
})
}
该对象包含四个属性:
接着通过 ConfigFlags 属性创建工厂,工厂提供了与 kube-apiserver 的交互方式,以及验证资源对象等方法:
kubeConfigFlags := o.ConfigFlags
if kubeConfigFlags == nil {
kubeConfigFlags = defaultConfigFlags
}
kubeConfigFlags.AddFlags(flags)
matchVersionKubeConfigFlags := cmdutil.NewMatchVersionFlags(kubeConfigFlags)
matchVersionKubeConfigFlags.AddFlags(flags)
f := cmdutil.NewFactory(matchVersionKubeConfigFlags)
这里以创建 get 为例 getCmd := get.NewCmdGet("kubectl", f, o.IOStreams) ,工厂 f 和 IOStreams 作为参数传给 get 包的 NewCmdGet 函数,在函数内实现 get 命令的创建.
创建 GetOptions 对象,该对象包含和 get 命令相关的输入.
func NewCmdGet(parent string, f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command {
o := NewGetOptions(parent, streams)
cmd := &cobra.Command{
...
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.Run(f, args))
},
SuggestFor: []string{"list", "ps"},
}
...
Cobra 的 Run 函数实现运行 get 命令的行为.
首先, o.Complete(f, cmd, args) 补全 GetOptions 对象的输入:
func (o *GetOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
var err error
o.Namespace, o.ExplicitNamespace, err = f.ToRawKubeConfigLoader().Namespace()
if err != nil {
return err
}
...
需要注意的是, f.ToRawKubeConfigLoader().Namespace() 调用工厂的 ToRawKubeConfigLoader() 方法解析 kubeconfig 中的配置,然后调用 Namespace() 方法将 kubeconfig 中定义的 namespace 解析出来,解析 kubeconfig 的过程是反序列化 kubeconfig 文件的过程。这一过程太长,这里就不多做介绍了.
完成了输入补全,在 o.Validate() 中对输入做验证。最后,通过 o.Run(f, args) 运行命令:
func (o *GetOptions) Run(f cmdutil.Factory, args []string) error {
...
r := f.NewBuilder().
Unstructured().
NamespaceParam(o.Namespace).DefaultNamespace().AllNamespaces(o.AllNamespaces).
FilenameParam(o.ExplicitNamespace, &o.FilenameOptions).
LabelSelectorParam(o.LabelSelector).
FieldSelectorParam(o.FieldSelector).
Subresource(o.Subresource).
RequestChunksOf(chunkSize).
ResourceTypeOrNameArgs(true, args...).
ContinueOnError().
Latest().
Flatten().
TransformRequests(o.transformRequests).
Do()
...
这里涉及到 建造者设计模式 。通过 f 创建建造者,建造者通过一系列方法补全自身属性,在 Do 方法中根据这些属性建造 resource.Result 对象:
func (b *Builder) Do() *Result {
r := b.visitorResult()
...
return r
}
Do 方法值得重点关注,其实现了 访问者设计模式 ,且是嵌套的访问者,访问的对象为 info 结构体.
首先, b.visitorResult() 方法通过 visit 多个 item 创建 resource.Result 。这里以 visit resource name 为例:
func (b *Builder) visitByName() *Result {
result := &Result{
singleItemImplied: len(b.names) == 1,
targetsSingleItems: true,
}
client, err := b.getClient(mapping.GroupVersionKind.GroupVersion())
if err != nil {
result.err = err
return result
}
...
visitors := []Visitor{}
for _, name := range b.names {
info := &Info{
Client: client,
Mapping: mapping,
Namespace: selectorNamespace,
Name: name,
Subresource: b.subresource,
}
visitors = append(visitors, info)
}
result.visitor = VisitorList(visitors)
result.sources = visitors
return result
}
visitByName() 方法内创建了一组 info 对象,其中保存了 resource 的信息。该对象保存在存储访问者 Visitor 的 visitors 列表,并赋值给 result.visitor 和 result.sources .
关于 result.visitor 要注意的一点是,其中的 VisitorList 也实现了 Visit 方法,它是横向的调用 info , info 是主体, fn 是这里的访问者:
type VisitorList []Visitor
// Visit implements Visitor
func (l VisitorList) Visit(fn VisitorFunc) error {
for i := range l {
if err := l[i].Visit(fn); err != nil {
return err
}
}
return nil
}
得到 resource.Result 之后,通过各个访问者访问 info 资源:
func (b *Builder) Do() *Result {
r := b.visitorResult()
if b.flatten {
r.visitor = NewFlattenListVisitor(r.visitor, b.objectTyper, b.mapper)
}
helpers := []VisitorFunc{}
if b.defaultNamespace {
helpers = append(helpers, SetNamespace(b.namespace))
}
if b.requireNamespace {
helpers = append(helpers, RequireNamespace(b.namespace))
}
helpers = append(helpers, FilterNamespace)
if b.requireObject {
helpers = append(helpers, RetrieveLazy)
}
if b.continueOnError {
r.visitor = ContinueOnErrorVisitor{Visitor: r.visitor}
}
r.visitor = NewDecoratedVisitor(r.visitor, helpers...)
return r
}
其中, FlattenListVisitor , ContinueOnErrorVisitor 和 DecoratedVisitor 是纵向的访问者嵌套关系, SetNamespace , RequireNamespace 和 RetrieveLazy 是横向的嵌套关系.
这里关于访问者模式和访问者嵌套的调用顺序就不过多介绍,有兴趣的话可以参考 浅析访问者模式 .
Do 方法返回 Result ,接着调用 infos, err := r.Infos() 方法实现 resource 的访问:
func (r *Result) Infos() ([]*Info, error) {
...
infos := []*Info{}
err := r.visitor.Visit(func(info *Info, err error) error {
if err != nil {
return err
}
infos = append(infos, info)
return nil
})
return infos, err
}
这里 infos 是一组 info 对象访问 kube-apiserver 获得的返回结果集合。那么,哪里有定义访问 kube-apiserver 的地方呢?
答案在 RetrieveLazy 访问者:
func RetrieveLazy(info *Info, err error) error {
if err != nil {
return err
}
if info.Object == nil {
return info.Get()
}
return nil
}
// Get retrieves the object from the Namespace and Name fields
func (i *Info) Get() (err error) {
obj, err := NewHelper(i.Client, i.Mapping).WithSubresource(i.Subresource).Get(i.Namespace, i.Name)
if err != nil {
if errors.IsNotFound(err) && len(i.Namespace) > 0 && i.Namespace != metav1.NamespaceDefault && i.Namespace != metav1.NamespaceAll {
err2 := i.Client.Get().AbsPath("api", "v1", "namespaces", i.Namespace).Do(context.TODO()).Error()
if err2 != nil && errors.IsNotFound(err2) {
return err2
}
}
return err
}
i.Object = obj
i.ResourceVersion, _ = metadataAccessor.ResourceVersion(obj)
return nil
}
func (m *Helper) Get(namespace, name string) (runtime.Object, error) {
req := m.RESTClient.Get().
NamespaceIfScoped(namespace, m.NamespaceScoped).
Resource(m.Resource).
Name(name).
SubResource(m.Subresource)
return req.Do(context.TODO()).Get()
}
RetrieveLazy 中定义如果 info.Object 没有信息,则调用 info 的 Get 方法,在 Get 方法中根据 i.Client 和 i.Mapping 创建 Helper ,通过 Helper 的 Get 方法通过 client-go 实现同 kube-apiserver 的交互,获得 info 的资源信息.
通过上例分析给出 UML 交互图如下:
最后此篇关于Kubernetes:Kubectl源码分析的文章就讲到这里了,如果你想了解更多关于Kubernetes:Kubectl源码分析的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
ACO.Visualization项目 本项目演示蚁群算法求解旅行商问题的可视化过程,包括路径上的信息素浓度、蚁群的运动过程等。项目相关的代码:https://github.com/anycad/A
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
我需要用Sql数据库制作并包含的PHP票务系统源码用户客户端和管理员。我需要个人 CMS 的这个来源。谢谢你帮助我。 最佳答案 我在不同的情况下使用了 osticket。 这里: http://ost
我的场景:我想在日志文件中写入发生异常的部分代码(例如,发生异常的行前 5 行和行后 5 行 - 或者至少是该方法的所有代码)。 我的想法是用 C# 代码反编译 pdb 文件,并从该反编译文件中找到一
RocketMQ设定了延迟级别可以让消息延迟消费,延迟消息会使用 SCHEDULE_TOPIC_XXXX 这个主题,每个延迟等级对应一个消息队列,并且与普通消息一样,会保存每个消息队列的消费进度
先附上Hystrix源码图 在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以相互调用(RPC),在Spring Cloud可以用RestTemplate+Ribbon和
此篇博客学习的api如标题,分别是: current_url 获取当前页面的url; page_source 获取当前页面的源码; title 获取当前页面的titl
? 1 2
1、前言 作为一个数据库爱好者,自己动手写过简单的sql解析器以及存储引擎,但感觉还是不够过瘾。<<事务处理-概念与技术>>诚然讲的非常透彻,但只能提纲挈领,不能让你
gory"> 目录 运行时信号量机制 semaphore 前言 作用是什么 几个主要的方法 如何实现
自己写的一个评论系统源码分享给大家,包括有表情,还有评论机制。用户名是随机的 针对某一篇文章进行评论 function subcomment() {
一、概述 StringBuilder是一个可变的字符串序列,这个类被设计去兼容StringBuffer类的API,但不保证线程安全性,是StringBuffer单线程情况下的一个替代实现。在可能的情
一、概述 System是用的非常多的一个final类。它不能被实例化。System类提供了标准的输入输出和错误输出流;访问外部定义的属性和环境变量;加载文件和库的方法;以及高效的拷贝数组中一部分元素
在JDK中,String的使用频率和被研究的程度都非常高,所以接下来我只说一些比较重要的内容。 一、String类的概述 String类的声明如下: public final class Str
一、概述 Class的实例代表着正在运行的Java应用程序的类和接口。枚举是一种类,而直接是一种接口。每一个数组也属于一个类,这个类b被反射为具有相同元素类型和维数的所有数组共享的类对象。八大基本树
一、概述 Compiler这个类被用于支持Java到本地代码编译器和相关服务。在设计上,这个类啥也不做,他充当JIT编译器实现的占位符。 放JVM虚拟机首次启动时,他确定系统属性java.comp
一、概述 StringBuffer是一个线程安全的、可变的字符序列,跟String类似,但它能被修改。StringBuffer在多线程环境下可以很安全地被使用,因为它的方法都是通过synchroni
一、概述 Enum是所有Jav中枚举类的基类。详细的介绍在Java语言规范中有说明。 值得注意的是,java.util.EnumSet和java.util.EnumMap是Enum的两个高效实现,
一、概述 此线程指的是执行程序中的线程。 Java虚拟机允许应用程序同时执行多个执行线程。 每个线程都有优先权。 具有较高优先级的线程优先于优先级较低的线程执行。 每个线程可能也可能不会被标记为守
一、抽象类Number 类继承关系 这里面的原子类、BigDecimal后面都会详细介绍。 属性和抽象方法 二、概述 所有的属性,最小-128,最大127,SIZE和BYTES代码比
我是一名优秀的程序员,十分优秀!