Kubernetes kubectl中Pod創(chuàng)建流程源碼解析
確立目標
- 從
創(chuàng)建pod的全流程入手,了解各組件的工作內(nèi)容,組件主要包括以下
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 的調(diào)用邏輯
我們的目標是查看kubectl create -f nginx_pod.yaml 這個命令是怎么運行的
Main
在cmd/kubectl中
func main() {
// 如果不調(diào)用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:]
// 調(diào)用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
代碼較長,選擇關(guān)鍵性的內(nèi)容進行講解
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性能分析,跳轉(zhuǎn)到對應代碼可以看到,我們可以用參數(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類命令,結(jié)合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. 故障排查和調(diào)試,包括 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. 設(shè)置命令,包括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相關(guān)的子命令
alpha := cmdpkg.NewCmdAlpha(f, ioStreams)
if !alpha.HasSubCommands() {
filters = append(filters, alpha.Name())
}
templates.ActsAsRootCommand(cmds, filters, groups...)
// 代碼補全相關(guān)
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子命令的相關(guān)選項
o := NewCreateOptions(ioStreams)
// create子命令的相關(guān)說明
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,這塊的邏輯比較復雜,我們先關(guān)注文件部分 這些大部分是給builder設(shè)置參數(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
// 調(diào)用visit函數(shù),創(chuàng)建資源
err = r.Visit(func(info *resource.Info, err error) error {
// 我們看到的pod創(chuàng)建成功就是在這里打印的 打印結(jié)果 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ù)調(diào)用了NewBuilder、Schema等一系列函數(shù),這段代碼所做的事情是將命令行接收到的參數(shù)轉(zhuǎn)化為一個資源的列。它使用了Builder模式的變種,使用獨立的函數(shù)做各自的數(shù)據(jù)初始化工作。函數(shù)Schema、ContinueOnError、NamespaceParam、DefaultNamespace、FilenameParam、SelectorParam和Flatten都引入了一個指向Builder結(jié)構(gòu)的指針,執(zhí)行一些對它的修改,并且將這個結(jié)構(gòu)體返回給調(diào)用鏈中的下一個方法來執(zhí)行這些修改。 - FilenameParam里面就進行了解析文件,除了支持簡單的本地文件,也支持標準輸入和http/https協(xié)議訪問的文件,保存為
Visitor,再調(diào)用Visit返回結(jié)果,下一節(jié)將介紹Visitor訪問者模式是和發(fā)請求創(chuàng)建pod的細節(jié)是怎么實現(xiàn)的。
以上就是Kubernetes kubectl中Pod創(chuàng)建流程源碼解析的詳細內(nèi)容,更多關(guān)于Kubernetes kubectl Pod創(chuàng)建的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
KubeSphere接入外部Elasticsearch實戰(zhàn)示例
這篇文章主要為大家介紹了KubeSphere接入外部Elasticsearch實戰(zhàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-12-12
Docker與K8s關(guān)系介紹不會Docker也可以使用K8s
想學K8s,必須得先學會Docker嗎?這是很多網(wǎng)友在開始有想法想要學?K8s的時候都會冒出來的想法,要回答這個問題,我們需要先搞清楚?Docker?和?K8s?他們的角色是什么,相互之間是什么關(guān)系2022-06-06
kubernetes數(shù)據(jù)持久化PV?PVC深入分析詳解
這篇文章主要為大家介紹了kubernetes數(shù)據(jù)持久化PV?PVC分析詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11
了解Kubernetes中的Service和Endpoint
這篇文章介紹了Kubernetes中的Service和Endpoint,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-04-04
Kubernetes關(guān)鍵組件與結(jié)構(gòu)組成介紹
這篇文章介紹了Kubernetes的關(guān)鍵組件與結(jié)構(gòu)組成,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-03-03
CentOS 出現(xiàn)no space left on device錯誤解決辦法
這篇文章主要介紹了CentOS 出現(xiàn)no space left on device錯誤解決辦法的相關(guān)資料,需要的朋友可以參考下2017-04-04

