Kubernetes kubectl中Pod創(chuàng)建流程源碼解析
確立目標
- 從
創(chuàng)建pod
的全流程入手,了解各組件的工作內容,組件主要包括以下
kubectl
kube-apiserver
kube-scheduler
kube-controller
kubelet
- 理解各個組件之間的相互協(xié)作,目前是
kubectl
先寫一個Pod的Yaml
apiVersion: v1 kind: Pod metadata: name: nginx-pod spec: containers: - name: nginx image: nginx:1.8
部署Pod
kubectl create -f nginx_pod.yaml pod/nginx-pod created
提示創(chuàng)建成功
查詢Pod
kubectl get pods NAME READY STATUS RESTARTS AGE nginx-pod 1/1 Running 0 4m22s
打印出狀態(tài):
- NAME - nginx-pod就是對應上面
metadata.name
- READY - 就緒的個數(shù)
- STATUS - 當前的狀態(tài),RUNNING表示運行中
- RESTARTS - 重啟的次數(shù)
- AGE - 多久之前創(chuàng)建的(運行的時間)
kubectl create 的調用邏輯
我們的目標是查看kubectl create -f nginx_pod.yaml
這個命令是怎么運行的
Main
在cmd/kubectl中
func main() { // 如果不調用rand.Seed,每次重新運行這個main函數(shù),rand下的函數(shù)返回值始終一致 // Seed即隨機的種子,每次用時間戳作為種子,就能保證隨機性 rand.Seed(time.Now().UnixNano()) // 創(chuàng)建了kubectl命令的默認參數(shù) 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 { // 這里為傳入的參數(shù),即 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 // 創(chuàng)建主命令 告訴你kubectl該怎么用 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性能分析,跳轉到對應代碼可以看到,我們可以用參數(shù) --profile xxx 來采集性能指標,默認保存在當前目錄下的profile.pprof中 return initProfiling() }, // 運行指令后的鉤子 PersistentPostRunE: func(*cobra.Command, []string) error { // 保存pprof性能分析指標 if err := flushProfiling(); err != nil { return err } // 打印warning條數(shù) 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, // 驗證參數(shù)并運行 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,這塊的邏輯比較復雜,我們先關注文件部分 這些大部分是給builder設置參數(shù),在Do的時候執(zhí)行邏輯,返回我們想要的Result r := f.NewBuilder(). Unstructured(). Schema(schema). ContinueOnError(). NamespaceParam(cmdNamespace).DefaultNamespace(). // 讀取文件信息,發(fā)現(xiàn)除了支持簡單的本地文件,也支持標準輸入和http/https協(xié)議訪問的文件,保存為Visitor FilenameParam(enforceNamespace, &o.FilenameOptions). LabelSelectorParam(o.Selector). Flatten(). Do() err = r.Err() if err != nil { return err } count := 0 // 調用visit函數(shù),創(chuàng)建資源 err = r.Visit(func(info *resource.Info, err error) error { // 我們看到的pod創(chuàng)建成功就是在這里打印的 打印結果 xxxx created return o.PrintObj(info.Object) }) return nil }
站在前人的肩膀上,向前輩致敬,Respect!
Summary
- 我們從一個創(chuàng)建pod的過程開始,在
cmd/kubectl
中找到kubectl的啟動過程,kubernetes的命令行工具了利用spf13/cobra
庫,傳入并解析參數(shù),去匹配子命令,配置kubectl的默認參數(shù)。 - 在
NewKubectlCommand
中進行初始化,有初始化前后的鉤子和七類命令,還實現(xiàn)了Factory
,在命令中進入Create,進行驗證參數(shù)并運行,把文件名配置到CreateOptions中,進入RunCreate
,其中傳入的Factory,封裝了與kube-apiserver交互的客戶端。 - 根據(jù)配置實例化
Builder
,該函數(shù)調用了NewBuilder、Schema等一系列函數(shù),這段代碼所做的事情是將命令行接收到的參數(shù)轉化為一個資源的列。它使用了Builder模式的變種,使用獨立的函數(shù)做各自的數(shù)據(jù)初始化工作。函數(shù)Schema、ContinueOnError、NamespaceParam、DefaultNamespace、FilenameParam、SelectorParam和Flatten都引入了一個指向Builder結構的指針,執(zhí)行一些對它的修改,并且將這個結構體返回給調用鏈中的下一個方法來執(zhí)行這些修改。 - FilenameParam里面就進行了解析文件,除了支持簡單的本地文件,也支持標準輸入和http/https協(xié)議訪問的文件,保存為
Visitor
,再調用Visit
返回結果,下一節(jié)將介紹Visitor訪問者模式是和發(fā)請求創(chuàng)建pod的細節(jié)是怎么實現(xiàn)的。
以上就是Kubernetes kubectl中Pod創(chuàng)建流程源碼解析的詳細內容,更多關于Kubernetes kubectl Pod創(chuàng)建的資料請關注腳本之家其它相關文章!
相關文章
kubernetes中的namespace、node、pod介紹
這篇文章介紹了kubernetes中的namespace、node、pod,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-03-03Kubernetes scheduler啟動監(jiān)控資源變化解析
這篇文章主要為大家介紹了Kubernetes scheduler啟動監(jiān)控資源變化解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11Dashboard管理Kubernetes集群與API訪問配置
這篇文章介紹了Dashboard管理Kubernetes集群與API訪問配置的方法,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-04-04Kubernetes ApiServer三大server權限與數(shù)據(jù)存儲解析
這篇文章主要為大家介紹了Kubernetes ApiServer三大server權限與數(shù)據(jù)存儲解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11CentOS 出現(xiàn)no space left on device錯誤解決辦法
這篇文章主要介紹了CentOS 出現(xiàn)no space left on device錯誤解決辦法的相關資料,需要的朋友可以參考下2017-04-04Kubernetes kubectl中Pod創(chuàng)建流程源碼解析
這篇文章主要為大家介紹了Kubernetes kubectl中Pod創(chuàng)建流程源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11KubeSphere接入外部Elasticsearch實戰(zhàn)示例
這篇文章主要為大家介紹了KubeSphere接入外部Elasticsearch實戰(zhàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-12-12