k8s學習(一)——kubectl與api-server之間的交互核心過程


k8s的架構是用戶使用kubectl工具對虛擬機資源進行各種各樣的控制和定制。

而kubectl本身並不包含對其核心資源的訪問與控制。而是通過http通信與api-server進行交互實現資源的管理。

而api-server的核心其實就是etcd數據庫,它將各種資源的管理通過對etcd中的數據進行更改實現。這篇文章簡要分析一下kubectl對

api-server發起訪問的過程。

以kubectl create 指令為例,其指令的相關代碼在kubernetes/pkg/kubectl/cmd/create.go這個文件中。

一,參數的構造

稍加分析不難看出,其創建資源的核心函數是func RunCreate()。

          r := builder.
		Schema(schema).
		ContinueOnError().
		NamespaceParam(cmdNamespace).DefaultNamespace().
		FilenameParam(enforceNamespace, &options.FilenameOptions).
		SelectorParam(options.Selector).
		Flatten().
		Do()

 這段代碼調用了builder的一串函數,最后生成一個Result類型的變量r。(Result 定義在 kubernetes/pkg/kubectl/resource/result.go)

這里builder的作用是將之前解析得到的各種參數進行各種分析后填充到builder中,最后再生成一個Result類型的變量r。

此時r中最關鍵的數據是visitor,這個visitor中包含了多個資源,也就是說一個visitor包含了一個對象(此處存疑)。

接着以一個函數func為參數調用r的Visit函數。經過分析我們可以知道這是一個調用鏈函數,其中繼續對參數進行各種分析,處理。

r.Visit(func(info *resource.Info, err error) error {
.....
})

大致的調用順序為

Result.Visit()
ContinueOnError.Visit()
Decorated.Visit()
FlattenList.Visit()
EagerVisitorList.Visit()
FileVisitor.Visit()
StreamVisitor.Visit()
在StreamVisitor之前,都是對數據的各種處理,並不會調用func函數,在StreamVisitor.Visit()中一個關鍵的處理是生成一個臨時變量Info。

info, err := v.InfoForData(ext.Raw, v.Source)

這里的ext.Raw和v.Source都是之前對用戶的輸入進行解析的結果。

ext.Raw是byte[]類型,v.Source是String類型,打印出來:

ext.Raw={
"apiVersion":"v1",
"kind":"Pod",
"metadata":
    {"name":"with-node-affinity-2"},
"spec":
{"affinity":
    {"nodeAffinity":{"preferredDuringSchedulingIgnoredDuringExecution":[{"preference":{"matchExpressions":[{"key":"another-node-label-key","operator":"In","values":["another-node-label-value"]}]},
"weight":1}],
"requiredDuringSchedulingIgnoredDuringExecution":{"nodeSelectorTerms":[{"matchExpressions":[{"key":"kubernetes.io/e2e-az-name","operator":"In","values":["e2e-az1","e2e-az2"]}]}]}}},
"containers":[{"image":"gcr.io/google_containers/pause:2.0","name":"with-node-affinity"}]}},




v.Source=/home/wlh/mywork/yaml_file/pod-with-node-affinity.yaml

可以看到其中存儲了生成的資源的各種特性,有了這個info之后執行func(info)。

二,訪問api-server

得到了info這個數據結構后,調用func()函數對api-server發起訪問請求。

if !dryRun {
			if err := createAndRefresh(info); err != nil {
				return cmdutil.AddSourceToErr("creating", info.Source, err)
			}
		}

這個dryRun標志位的意思是,只打印出將要創建的資源的各種特性,而不會真正去創建他。

而createAndRefresh函數中的核心調用是

obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)

 這里創建了一個Helper類型的對象,仔細分析后不難發現Info.Client中定義了訪問動作,而info.Mapping中定義了這些動作所要訪問的資源。

此時Helper中已經包含了發起一個對api-server請求的所有資源,接着調用Create函數,它創建一個具體去執行這些請求的Request對象。(定義在kubernetes/vendor/k8s.io/client-go/rest/request.go中)

Requeste發起對api-server的請求,並且將訪問存儲在ResutInfo中,與此同時返回一個Runtime.Object對象。

這樣一次完整的訪問api-server的流程就完成了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM