網站首頁 編程語言 正文
確立目標
- 從
創建pod
的全流程入手,了解各組件的工作內容,組件主要包括以下
kubectl
kube-apiserver
kube-scheduler
kube-controller
kubelet
- 理解各個組件之間的相互協作,目前是
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
提示創建成功
查詢Pod
kubectl get pods NAME READY STATUS RESTARTS AGE nginx-pod 1/1 Running 0 4m22s
打印出狀態:
- NAME - nginx-pod就是對應上面?
metadata.name
- READY - 就緒的個數
- STATUS - 當前的狀態,RUNNING表示運行中
- RESTARTS - 重啟的次數
- AGE - 多久之前創建的(運行的時間)
kubectl create 的調用邏輯
我們的目標是查看kubectl create -f nginx_pod.yaml
?這個命令是怎么運行的
Main
在cmd/kubectl中
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 // 創建主命令 告訴你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性能分析,跳轉到對應代碼可以看到,我們可以用參數 --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,這塊的邏輯比較復雜,我們先關注文件部分 這些大部分是給builder設置參數,在Do的時候執行邏輯,返回我們想要的Result 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 { // 我們看到的pod創建成功就是在這里打印的 打印結果 xxxx created return o.PrintObj(info.Object) }) return nil }
站在前人的肩膀上,向前輩致敬,Respect!
Summary
- 我們從一個創建pod的過程開始,在
cmd/kubectl
中找到kubectl的啟動過程,kubernetes的命令行工具了利用spf13/cobra
庫,傳入并解析參數,去匹配子命令,配置kubectl的默認參數。 - 在
NewKubectlCommand
中進行初始化,有初始化前后的鉤子和七類命令,還實現了Factory
,在命令中進入Create,進行驗證參數并運行,把文件名配置到CreateOptions中,進入RunCreate
,其中傳入的Factory,封裝了與kube-apiserver交互的客戶端。 - 根據配置實例化
Builder
,該函數調用了NewBuilder、Schema等一系列函數,這段代碼所做的事情是將命令行接收到的參數轉化為一個資源的列。它使用了Builder模式的變種,使用獨立的函數做各自的數據初始化工作。函數Schema、ContinueOnError、NamespaceParam、DefaultNamespace、FilenameParam、SelectorParam和Flatten都引入了一個指向Builder結構的指針,執行一些對它的修改,并且將這個結構體返回給調用鏈中的下一個方法來執行這些修改。 - FilenameParam里面就進行了解析文件,除了支持簡單的本地文件,也支持標準輸入和http/https協議訪問的文件,保存為
Visitor
,再調用Visit
返回結果,下一節將介紹Visitor訪問者模式是和發請求創建pod的細節是怎么實現的。
原文鏈接:https://juejin.cn/post/7153196942469251108/
相關推薦
- 2023-01-03 Kotlin文件讀寫與SharedPreferences存儲功能實現方法_Android
- 2023-02-10 Python常見錯誤:IndexError:?list?index?out?of?range解決_p
- 2022-12-05 Python?如何截取字符函數_python
- 2023-06-16 GO語言中通道和sync包的使用教程分享_Golang
- 2022-02-28 Module not found: Error: Can't resolve 'sass-loade
- 2022-07-29 Linux中文件的基本屬性介紹_linux shell
- 2022-07-24 docker容器使用GPU方法實現_docker
- 2022-10-23 C/C++指針介紹與使用詳解_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支