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就是對應(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
代碼較長,選擇關(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)到對應(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自動補(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. 初級命令,包括 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...)
// 代碼補(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中,對應(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對象
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)除了支持簡單的本地文件,也支持標(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的啟動過程,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í)行一些對它的修改,并且將這個(gè)結(jié)構(gòu)體返回給調(diào)用鏈中的下一個(gè)方法來執(zhí)行這些修改。 - FilenameParam里面就進(jìn)行了解析文件,除了支持簡單的本地文件,也支持標(biāo)準(zhǔn)輸入和http/https協(xié)議訪問的文件,保存為
Visitor,再調(diào)用Visit返回結(jié)果,下一節(jié)將介紹Visitor訪問者模式是和發(fā)請求創(chuàng)建pod的細(xì)節(jié)是怎么實(shí)現(xiàn)的。
以上就是Kubernetes kubectl中Pod創(chuàng)建流程源碼解析的詳細(xì)內(nèi)容,更多關(guān)于Kubernetes kubectl Pod創(chuà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)系介紹不會Docker也可以使用K8s
想學(xué)K8s,必須得先學(xué)會Docker嗎?這是很多網(wǎng)友在開始有想法想要學(xué)?K8s的時(shí)候都會冒出來的想法,要回答這個(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,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04
Kubernetes關(guān)鍵組件與結(jié)構(gòu)組成介紹
這篇文章介紹了Kubernetes的關(guān)鍵組件與結(jié)構(gòu)組成,對大家的學(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

