【K8s源码品读】002:Phase 1 - kubectl - create的调用逻辑

简介: 我们的目标是查看`kubectl create -f nginx_pod.yaml` 这个命令是怎么运行的。

聚焦目标

我们的目标是查看kubectl create -f nginx_pod.yaml 这个命令是怎么运行的。

目录

  1. main函数入口

  2. 传入参数与子命令的匹配

  3. kubectl命令的初始化

  4. 查看create子命令

  5. runCreate的创建逻辑

main

func main() {
   
     // 如果不调用rand.Seed,每次重新运行这个main函数,rand下的函数返回值始终一致
    // Seed即随机的种子,每次用时间戳作为种子,就能保证随机性
    rand.Seed(time.Now().UnixNano())

  // 创建了kubectl命令的默认参数
    command := cmd.NewDefaultKubectlCommand()

    // TODO: once we switch everything over to Cobra commands, we can go back to calling
    // cliflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
    // normalize func and add the go flag set by hand.
    pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
    pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
    // cliflag.InitFlags()

  // 日志的初始化与退出
    logs.InitLogs()
    defer logs.FlushLogs()

  // 运行command
    if err := command.Execute(); err != nil {
   
        os.Exit(1)
    }
}

match

// k8s的命令行工具采用了 cobra 库,具有命令提示等强大功能,比go语言自带的flag强大很多,可参考 github.com/spf13/cobra
func NewDefaultKubectlCommand() *cobra.Command {
   
    return NewDefaultKubectlCommandWithArgs(NewDefaultPluginHandler(plugin.ValidPluginFilenamePrefixes), os.Args, os.Stdin, os.Stdout, os.Stderr)
}

func NewDefaultKubectlCommandWithArgs(pluginHandler PluginHandler, args []string, in io.Reader, out, errout io.Writer) *cobra.Command {
   
  // 初始化NewKubectlCommand,采用标准输入、输出、错误输出
    cmd := NewKubectlCommand(in, out, errout)

    if pluginHandler == nil {
   
        return cmd
    }

    if len(args) > 1 {
   
    // 这里为传入的参数,即 create -f nginx_pod.yaml 部分
        cmdPathPieces := args[1:]

        // 调用cobra的Find去匹配args
        if _, _, err := cmd.Find(cmdPathPieces); err != nil {
   
            if err := HandlePluginCommand(pluginHandler, cmdPathPieces); err != nil {
   
                fmt.Fprintf(errout, "%v\n", err)
                os.Exit(1)
            }
        }
    }

    return cmd
}

command

代码较长,我选择关键性的内容进行讲解

func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
   
    warningHandler := rest.NewWarningWriter(err, rest.WarningWriterOptions{
   Deduplicate: true, Color: term.AllowsColorOutput(err)})
    warningsAsErrors := false

    // 创建主命令
    cmds := &cobra.Command{
   
        Use:   "kubectl",
        Short: i18n.T("kubectl controls the Kubernetes cluster manager"),
        Long: templates.LongDesc(`
      kubectl controls the Kubernetes cluster manager.

      Find more information at:
            https://kubernetes.io/docs/reference/kubectl/overview/`),
        Run: runHelp,
        // 初始化后,在运行指令前的钩子
        PersistentPreRunE: func(*cobra.Command, []string) error {
   
            rest.SetDefaultWarningHandler(warningHandler)
      // 这里是做pprof性能分析,跳转到对应代码可以看到,我们可以用参数 --profile xxx 来采集性能指标,默认保存在当前目录下的profile.pprof中
            return initProfiling()
        },
    // 运行指令后的钩子
        PersistentPostRunE: func(*cobra.Command, []string) error {
   
      // 保存pprof性能分析指标
            if err := flushProfiling(); err != nil {
   
                return err
            }
      // 打印warning条数
            if warningsAsErrors {
   
                count := warningHandler.WarningCount()
                switch count {
   
                case 0:
                    // no warnings
                case 1:
                    return fmt.Errorf("%d warning received", count)
                default:
                    return fmt.Errorf("%d warnings received", count)
                }
            }
            return nil
        },
    // bash自动补齐功能,可通过 kubectl completion bash 命令查看
    // 具体安装可参考 https://kubernetes.io/docs/tasks/tools/install-kubectl/#enabling-shell-autocompletion
        BashCompletionFunction: bashCompletionFunc,
    }

  // 实例化Factory接口,工厂模式
    f := cmdutil.NewFactory(matchVersionKubeConfigFlags)

    // 省略实例化的过程代码

  // kubectl定义了7类命令,结合Message和各个子命令的package名来看
    groups := templates.CommandGroups{
   
        {
   
      // 1. 初级命令,包括 create/expose/run/set
            Message: "Basic Commands (Beginner):",
            Commands: []*cobra.Command{
   
                create.NewCmdCreate(f, ioStreams),
                expose.NewCmdExposeService(f, ioStreams),
                run.NewCmdRun(f, ioStreams),
                set.NewCmdSet(f, ioStreams),
            },
        },
        {
   
      // 2. 中级命令,包括explain/get/edit/delete
            Message: "Basic Commands (Intermediate):",
            Commands: []*cobra.Command{
   
                explain.NewCmdExplain("kubectl", f, ioStreams),
                get.NewCmdGet("kubectl", f, ioStreams),
                edit.NewCmdEdit(f, ioStreams),
                delete.NewCmdDelete(f, ioStreams),
            },
        },
        {
   
      // 3. 部署命令,包括 rollout/scale/autoscale
            Message: "Deploy Commands:",
            Commands: []*cobra.Command{
   
                rollout.NewCmdRollout(f, ioStreams),
                scale.NewCmdScale(f, ioStreams),
                autoscale.NewCmdAutoscale(f, ioStreams),
            },
        },
        {
   
      // 4. 集群管理命令,包括 cerfificate/cluster-info/top/cordon/drain/taint
            Message: "Cluster Management Commands:",
            Commands: []*cobra.Command{
   
                certificates.NewCmdCertificate(f, ioStreams),
                clusterinfo.NewCmdClusterInfo(f, ioStreams),
                top.NewCmdTop(f, ioStreams),
                drain.NewCmdCordon(f, ioStreams),
                drain.NewCmdUncordon(f, ioStreams),
                drain.NewCmdDrain(f, ioStreams),
                taint.NewCmdTaint(f, ioStreams),
            },
        },
        {
   
      // 5. 故障排查和调试,包括 describe/logs/attach/exec/port-forward/proxy/cp/auth
            Message: "Troubleshooting and Debugging Commands:",
            Commands: []*cobra.Command{
   
                describe.NewCmdDescribe("kubectl", f, ioStreams),
                logs.NewCmdLogs(f, ioStreams),
                attach.NewCmdAttach(f, ioStreams),
                cmdexec.NewCmdExec(f, ioStreams),
                portforward.NewCmdPortForward(f, ioStreams),
                proxy.NewCmdProxy(f, ioStreams),
                cp.NewCmdCp(f, ioStreams),
                auth.NewCmdAuth(f, ioStreams),
            },
        },
        {
   
      // 6. 高级命令,包括diff/apply/patch/replace/wait/convert/kustomize
            Message: "Advanced Commands:",
            Commands: []*cobra.Command{
   
                diff.NewCmdDiff(f, ioStreams),
                apply.NewCmdApply("kubectl", f, ioStreams),
                patch.NewCmdPatch(f, ioStreams),
                replace.NewCmdReplace(f, ioStreams),
                wait.NewCmdWait(f, ioStreams),
                convert.NewCmdConvert(f, ioStreams),
                kustomize.NewCmdKustomize(ioStreams),
            },
        },
        {
   
      // 7. 设置命令,包括label,annotate,completion
            Message: "Settings Commands:",
            Commands: []*cobra.Command{
   
                label.NewCmdLabel(f, ioStreams),
                annotate.NewCmdAnnotate("kubectl", f, ioStreams),
                completion.NewCmdCompletion(ioStreams.Out, ""),
            },
        },
    }
    groups.Add(cmds)

    filters := []string{
   "options"}

    // alpha相关的子命令
    alpha := cmdpkg.NewCmdAlpha(f, ioStreams)
    if !alpha.HasSubCommands() {
   
        filters = append(filters, alpha.Name())
    }

    templates.ActsAsRootCommand(cmds, filters, groups...)

  // 代码补全相关
    for name, completion := range bashCompletionFlags {
   
        if cmds.Flag(name) != nil {
   
            if cmds.Flag(name).Annotations == nil {
   
                cmds.Flag(name).Annotations = map[string][]string{
   }
            }
            cmds.Flag(name).Annotations[cobra.BashCompCustom] = append(
                cmds.Flag(name).Annotations[cobra.BashCompCustom],
                completion,
            )
        }
    }

  // 添加其余子命令,包括 alpha/config/plugin/version/api-versions/api-resources/options
    cmds.AddCommand(alpha)
    cmds.AddCommand(cmdconfig.NewCmdConfig(f, clientcmd.NewDefaultPathOptions(), ioStreams))
    cmds.AddCommand(plugin.NewCmdPlugin(f, ioStreams))
    cmds.AddCommand(version.NewCmdVersion(f, ioStreams))
    cmds.AddCommand(apiresources.NewCmdAPIVersions(f, ioStreams))
    cmds.AddCommand(apiresources.NewCmdAPIResources(f, ioStreams))
    cmds.AddCommand(options.NewCmdOptions(ioStreams.Out))

    return cmds
}

create

func NewCmdCreate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
   
  // create子命令的相关选项
    o := NewCreateOptions(ioStreams)

  // create子命令的相关说明
    cmd := &cobra.Command{
   
        Use:                   "create -f FILENAME",
        DisableFlagsInUseLine: true,
        Short:                 i18n.T("Create a resource from a file or from stdin."),
        Long:                  createLong,
        Example:               createExample,
    // 验证参数并运行
        Run: func(cmd *cobra.Command, args []string) {
   
            if cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames, o.FilenameOptions.Kustomize) {
   
                ioStreams.ErrOut.Write([]byte("Error: must specify one of -f and -k\n\n"))
                defaultRunFunc := cmdutil.DefaultSubCommandRun(ioStreams.ErrOut)
                defaultRunFunc(cmd, args)
                return
            }
            cmdutil.CheckErr(o.Complete(f, cmd))
            cmdutil.CheckErr(o.ValidateArgs(cmd, args))
      // 核心的运行代码逻辑是在这里的RunCreate
            cmdutil.CheckErr(o.RunCreate(f, cmd))
        },
    }

    o.RecordFlags.AddFlags(cmd)

    usage := "to use to create the resource"
  // 加入文件名选项的flag -f,保存到o.FilenameOptions.Filenames中,对应上面
    cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
    cmdutil.AddValidateFlags(cmd)
    cmd.Flags().BoolVar(&o.EditBeforeCreate, "edit", o.EditBeforeCreate, "Edit the API resource before creating")
    cmd.Flags().Bool("windows-line-endings", runtime.GOOS == "windows",
        "Only relevant if --edit=true. Defaults to the line ending native to your platform.")
    cmdutil.AddApplyAnnotationFlags(cmd)
    cmdutil.AddDryRunFlag(cmd)
    cmd.Flags().StringVarP(&o.Selector, "selector", "l", o.Selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
    cmd.Flags().StringVar(&o.Raw, "raw", o.Raw, "Raw URI to POST to the server.  Uses the transport specified by the kubeconfig file.")
    cmdutil.AddFieldManagerFlagVar(cmd, &o.fieldManager, "kubectl-create")

    o.PrintFlags.AddFlags(cmd)

    // create的子命令,指定create对象
    cmd.AddCommand(NewCmdCreateNamespace(f, ioStreams))
    cmd.AddCommand(NewCmdCreateQuota(f, ioStreams))
    cmd.AddCommand(NewCmdCreateSecret(f, ioStreams))
    cmd.AddCommand(NewCmdCreateConfigMap(f, ioStreams))
    cmd.AddCommand(NewCmdCreateServiceAccount(f, ioStreams))
    cmd.AddCommand(NewCmdCreateService(f, ioStreams))
    cmd.AddCommand(NewCmdCreateDeployment(f, ioStreams))
    cmd.AddCommand(NewCmdCreateClusterRole(f, ioStreams))
    cmd.AddCommand(NewCmdCreateClusterRoleBinding(f, ioStreams))
    cmd.AddCommand(NewCmdCreateRole(f, ioStreams))
    cmd.AddCommand(NewCmdCreateRoleBinding(f, ioStreams))
    cmd.AddCommand(NewCmdCreatePodDisruptionBudget(f, ioStreams))
    cmd.AddCommand(NewCmdCreatePriorityClass(f, ioStreams))
    cmd.AddCommand(NewCmdCreateJob(f, ioStreams))
    cmd.AddCommand(NewCmdCreateCronJob(f, ioStreams))
    return cmd
}

runCreate

func (o *CreateOptions) RunCreate(f cmdutil.Factory, cmd *cobra.Command) error {
   
    // f为传入的Factory,主要是封装了与kube-apiserver交互客户端

    schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
    if err != nil {
   
        return err
    }

    cmdNamespace, enforceNamespace, err := f.ToRawKubeConfigLoader().Namespace()
    if err != nil {
   
        return err
    }

  // 实例化Builder,这块的逻辑比较复杂,我们先关注文件部分
    r := f.NewBuilder().
        Unstructured().
        Schema(schema).
        ContinueOnError().
        NamespaceParam(cmdNamespace).DefaultNamespace().
      // 读取文件信息,发现除了支持简单的本地文件,也支持标准输入和http/https协议访问的文件,保存为Visitor
        FilenameParam(enforceNamespace, &o.FilenameOptions).
        LabelSelectorParam(o.Selector).
        Flatten().
        Do()
    err = r.Err()
    if err != nil {
   
        return err
    }

    count := 0
  // 调用visit函数,创建资源
    err = r.Visit(func(info *resource.Info, err error) error {
   
        // 打印结果 xxxx created
        return o.PrintObj(info.Object)
    })
    return nil
}
相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
目录
相关文章
|
1月前
|
运维 Kubernetes 监控
揭秘高效运维:如何用kubectl top命令实时监控K8s资源使用情况?
揭秘高效运维:如何用kubectl top命令实时监控K8s资源使用情况?
69 0
|
1月前
|
运维 Kubernetes 容器
K8S运维命令必备kubectl命令总结
K8S运维命令必备kubectl命令总结
32 3
|
1月前
|
Kubernetes 网络协议 Perl
k8s Failed to create pod sandbox: open /run/systemd/resolve/resolv.conf: no such file or directory
k8s Failed to create pod sandbox: open /run/systemd/resolve/resolv.conf: no such file or directory
39 0
|
2月前
|
Kubernetes Shell Docker
容器服务ACK常见问题之容器服务ACK kubectl命令写到shell脚本失败如何解决
容器服务ACK(阿里云容器服务 Kubernetes 版)是阿里云提供的一种托管式Kubernetes服务,帮助用户轻松使用Kubernetes进行应用部署、管理和扩展。本汇总收集了容器服务ACK使用中的常见问题及答案,包括集群管理、应用部署、服务访问、网络配置、存储使用、安全保障等方面,旨在帮助用户快速解决使用过程中遇到的难题,提升容器管理和运维效率。
|
3月前
|
Kubernetes 容器
使用kubeadm部署k8s报错:The kubelet is not running或者level=error msg="Handler for POST /v1.43/images/create returned error: Head \"https://us-west2-dock
使用kubeadm部署k8s报错:The kubelet is not running或者level=error msg="Handler for POST /v1.43/images/create returned error: Head \"https://us-west2-dock
|
3月前
|
Kubernetes 安全 API
K8S 实用工具之四 - kubectl 实用插件
K8S 实用工具之四 - kubectl 实用插件
|
4月前
|
Kubernetes Linux 网络安全
百度搜索:蓝易云【K8s在centos7安装及kubectl教程】
希望以上教程对你有所帮助!Kubernetes是一个强大的容器编排平台,能够帮助你更轻松地管理容器化应用程序。如果你有其他问题,请随时继续提问。
62 1
|
4月前
|
Kubernetes 容器
Kubernetes高可用集群二进制部署(四)部署kubectl和kube-controller-manager、kube-scheduler
Kubernetes高可用集群二进制部署(四)部署kubectl和kube-controller-manager、kube-scheduler
|
Kubernetes Shell API
kubernetes-kubectl命令说明
本文基于kubernetes 1.5.2版本编写 kubectl kubectl controls the K8S cluster manager. Find more information at https://github.
1200 0
|
Kubernetes 容器 Perl
Kubernetes-kubectl命令出现错误【The connection to the server localhost:8080 was refused - did you specif...
  今天在Kubernetes的从节点上运行命令【kubectl】出现了如下错误 [root@k8snode1 kubernetes]# kubectl get pod The connection to the server localhost:80...
35233 0