Kubernetes kubectl中Pod創(chuàng)建流程源碼解析
確立目標(biāo)
- 從
創(chuàng)建pod的全流程入手,了解各組件的工作內(nèi)容,組件主要包括以下
kubectl
kube-apiserver
kube-scheduler
kube-controller
kubelet
- 理解各個(gè)組件之間的相互協(xié)作,目前是
kubectl
先寫一個(gè)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就是對(duì)應(yīng)上面
metadata.name - READY - 就緒的個(gè)數(shù)
- STATUS - 當(dāng)前的狀態(tài),RUNNING表示運(yùn)行中
- RESTARTS - 重啟的次數(shù)
- AGE - 多久之前創(chuàng)建的(運(yùn)行的時(shí)間)
kubectl create 的調(diào)用邏輯
我們的目標(biāo)是查看kubectl create -f nginx_pod.yaml 這個(gè)命令是怎么運(yùn)行的
Main
在cmd/kubectl中
func main() {
// 如果不調(diào)用rand.Seed,每次重新運(yùn)行這個(gè)main函數(shù),rand下的函數(shù)返回值始終一致
// Seed即隨機(jī)的種子,每次用時(shí)間戳作為種子,就能保證隨機(jī)性
rand.Seed(time.Now().UnixNano())
// 創(chuàng)建了kubectl命令的默認(rèn)參數(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()
// 運(yùn)行command
if err := command.Execute(); err != nil {
os.Exit(1)
}
}
Match
// k8s的命令行工具采用了 cobra 庫,具有命令提示等強(qiáng)大功能,比go語言自帶的flag強(qiáng)大很多,可參考 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,采用標(biāo)準(zhǔn)輸入、輸出、錯(cuò)誤輸出
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
代碼較長(zhǎng),選擇關(guān)鍵性的內(nèi)容進(jìn)行講解
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,
// 初始化后,在運(yùn)行指令前的鉤子
PersistentPreRunE: func(*cobra.Command, []string) error {
rest.SetDefaultWarningHandler(warningHandler)
// 這里是做pprof性能分析,跳轉(zhuǎn)到對(duì)應(yīng)代碼可以看到,我們可以用參數(shù) --profile xxx 來采集性能指標(biāo),默認(rèn)保存在當(dāng)前目錄下的profile.pprof中
return initProfiling()
},
// 運(yùn)行指令后的鉤子
PersistentPostRunE: func(*cobra.Command, []string) error {
// 保存pprof性能分析指標(biāo)
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自動(dòng)補(bǔ)齊功能,可通過 kubectl completion bash 命令查看
// 具體安裝可參考 https://kubernetes.io/docs/tasks/tools/install-kubectl/#enabling-shell-autocompletion
BashCompletionFunction: bashCompletionFunc,
}
// 實(shí)例化Factory接口,工廠模式
f := cmdutil.NewFactory(matchVersionKubeConfigFlags)
// 省略實(shí)例化的過程代碼
// kubectl定義了7類命令,結(jié)合Message和各個(gè)子命令的package名來看
groups := templates.CommandGroups{
{
// 1. 初級(jí)命令,包括 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. 中級(jí)命令,包括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. 高級(jí)命令,包括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...)
// 代碼補(bǔ)全相關(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)選項(xiàng)
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,
// 驗(yàn)證參數(shù)并運(yùn)行
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))
// 核心的運(yùn)行代碼邏輯是在這里的RunCreate
cmdutil.CheckErr(o.RunCreate(f, cmd))
},
}
o.RecordFlags.AddFlags(cmd)
usage := "to use to create the resource"
// 加入文件名選項(xiàng)的flag -f,保存到o.FilenameOptions.Filenames中,對(duì)應(yīng)上面
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對(duì)象
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
}
// 實(shí)例化Builder,這塊的邏輯比較復(fù)雜,我們先關(guān)注文件部分 這些大部分是給builder設(shè)置參數(shù),在Do的時(shí)候執(zhí)行邏輯,返回我們想要的Result
r := f.NewBuilder().
Unstructured().
Schema(schema).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
// 讀取文件信息,發(fā)現(xiàn)除了支持簡(jiǎn)單的本地文件,也支持標(biāo)準(zhǔ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
- 我們從一個(gè)創(chuàng)建pod的過程開始,在
cmd/kubectl中找到kubectl的啟動(dòng)過程,kubernetes的命令行工具了利用spf13/cobra庫,傳入并解析參數(shù),去匹配子命令,配置kubectl的默認(rèn)參數(shù)。 - 在
NewKubectlCommand中進(jìn)行初始化,有初始化前后的鉤子和七類命令,還實(shí)現(xiàn)了Factory,在命令中進(jìn)入Create,進(jìn)行驗(yàn)證參數(shù)并運(yùn)行,把文件名配置到CreateOptions中,進(jìn)入RunCreate,其中傳入的Factory,封裝了與kube-apiserver交互的客戶端。 - 根據(jù)配置實(shí)例化
Builder,該函數(shù)調(diào)用了NewBuilder、Schema等一系列函數(shù),這段代碼所做的事情是將命令行接收到的參數(shù)轉(zhuǎn)化為一個(gè)資源的列。它使用了Builder模式的變種,使用獨(dú)立的函數(shù)做各自的數(shù)據(jù)初始化工作。函數(shù)Schema、ContinueOnError、NamespaceParam、DefaultNamespace、FilenameParam、SelectorParam和Flatten都引入了一個(gè)指向Builder結(jié)構(gòu)的指針,執(zhí)行一些對(duì)它的修改,并且將這個(gè)結(jié)構(gòu)體返回給調(diào)用鏈中的下一個(gè)方法來執(zhí)行這些修改。 - FilenameParam里面就進(jìn)行了解析文件,除了支持簡(jiǎn)單的本地文件,也支持標(biāo)準(zhǔn)輸入和http/https協(xié)議訪問的文件,保存為
Visitor,再調(diào)用Visit返回結(jié)果,下一節(jié)將介紹Visitor訪問者模式是和發(fā)請(qǐng)求創(chuàng)建pod的細(xì)節(jié)是怎么實(shí)現(xiàn)的。
以上就是Kubernetes kubectl中Pod創(chuàng)建流程源碼解析的詳細(xì)內(nèi)容,更多關(guān)于Kubernetes kubectl Pod創(chuàng)建的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
KubeSphere接入外部Elasticsearch實(shí)戰(zhàn)示例
這篇文章主要為大家介紹了KubeSphere接入外部Elasticsearch實(shí)戰(zhàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
Docker與K8s關(guān)系介紹不會(huì)Docker也可以使用K8s
想學(xué)K8s,必須得先學(xué)會(huì)Docker嗎?這是很多網(wǎng)友在開始有想法想要學(xué)?K8s的時(shí)候都會(huì)冒出來的想法,要回答這個(gè)問題,我們需要先搞清楚?Docker?和?K8s?他們的角色是什么,相互之間是什么關(guān)系2022-06-06
kubernetes數(shù)據(jù)持久化PV?PVC深入分析詳解
這篇文章主要為大家介紹了kubernetes數(shù)據(jù)持久化PV?PVC分析詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
了解Kubernetes中的Service和Endpoint
這篇文章介紹了Kubernetes中的Service和Endpoint,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04
Kubernetes關(guān)鍵組件與結(jié)構(gòu)組成介紹
這篇文章介紹了Kubernetes的關(guān)鍵組件與結(jié)構(gòu)組成,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-03-03
CentOS 出現(xiàn)no space left on device錯(cuò)誤解決辦法
這篇文章主要介紹了CentOS 出現(xiàn)no space left on device錯(cuò)誤解決辦法的相關(guān)資料,需要的朋友可以參考下2017-04-04

