騰訊云:一文讀懂Kubernetes APIServer原理(下)

來(lái)源: 騰訊云原生
作者:杜楊浩
時(shí)間:2021-01-19
17550
本文繼續(xù)分享Kubernetes APIServer原理。

ZDI2ZWRlMi5qcGVn.jpg

·APIExtensionServer負(fù)責(zé)CustomResourceDefinition(CRD)apiResources以及apiVersions的注冊(cè),同時(shí)處理CRD以及相應(yīng)CustomResource(CR)的REST請(qǐng)求(如果對(duì)應(yīng)CR不能被處理的話(huà)則會(huì)返回404),也是apiserver Delegation的最后一環(huán)

·crdRegistrationController負(fù)責(zé)將CRD GroupVersions自動(dòng)注冊(cè)到APIServices中。具體邏輯為:枚舉所有CRDs,然后根據(jù)CRD定義的crd.Spec.Group以及crd.Spec.Versions字段構(gòu)建APIService,并添加到autoRegisterController.apiServicesToSync中,由autoRegisterController進(jìn)行創(chuàng)建以及維護(hù)操作。這也是為什么創(chuàng)建完CRD后會(huì)產(chǎn)生對(duì)應(yīng)的APIService對(duì)象

·APIExtensionServer包含的controller以及功能如下所示:

openapiController:將crd資源的變化同步至提供的OpenAPI文檔,可通過(guò)訪(fǎng)問(wèn)/openapi/v2進(jìn)行查看;

crdController:負(fù)責(zé)將crd信息注冊(cè)到apiVersions和apiResources中,兩者的信息可通過(guò)kubectl api-versions和kubectl api-resources查看;

kubectl api-versions命令返回所有Kubernetes集群資源的版本信息(實(shí)際發(fā)出了兩個(gè)請(qǐng)求,分別是https://127.0.0.1:6443/api以及https://127.0.0.1:6443/apis,并在最后將兩個(gè)請(qǐng)求的返回結(jié)果進(jìn)行了合并)

$ kubectl -v=8 api-versions 

I1211 11:44:50.276446   22493 loader.go:375] Config loaded from file:  /root/.kube/config

I1211 11:44:50.277005   22493 round_trippers.go:420] GET https://127.0.0.1:6443/api?timeout=32s

...

I1211 11:44:50.290265   22493 request.go:1068] Response Body: {"kind":"APIVersions","versions":["v1"],"serverAddressByClientCIDRs":[{"clientCIDR":"0.0.0.0/0","serverAddress":"x.x.x.x:6443"}]}

I1211 11:44:50.293673   22493 round_trippers.go:420] GET https://127.0.0.1:6443/apis?timeout=32s

...

I1211 11:44:50.298360   22493 request.go:1068] Response Body: {"kind":"APIGroupList","apiVersion":"v1","groups":[{"name":"apiregistration.k8s.io","versions":[{"groupVersion":"apiregistration.k8s.io/v1","version":"v1"},{"groupVersion":"apiregistration.k8s.io/v1beta1","version":"v1beta1"}],"preferredVersion":{"groupVersion":"apiregistration.k8s.io/v1","version":"v1"}},{"name":"extensions","versions":[{"groupVersion":"extensions/v1beta1","version":"v1beta1"}],"preferredVersion":{"groupVersion":"extensions/v1beta1","version":"v1beta1"}},{"name":"apps","versions":[{"groupVersion":"apps/v1","version":"v1"}],"preferredVersion":{"groupVersion":"apps/v1","version":"v1"}},{"name":"events.k8s.io","versions":[{"groupVersion":"events.k8s.io/v1beta1","version":"v1beta1"}],"preferredVersion":{"groupVersion":"events.k8s.io/v1beta1","version":"v1beta1"}},{"name":"authentication.k8s.io","versions":[{"groupVersion":"authentication.k8s.io/v1","version":"v1"},{"groupVersion":"authentication.k8s.io/v1beta1","version":"v1beta1"}],"preferredVersion":{"groupVersion":"authentication.k8s.io/v1"," [truncated 4985 chars]

apiextensions.k8s.io/v1

apiextensions.k8s.io/v1beta1

apiregistration.k8s.io/v1

apiregistration.k8s.io/v1beta1

apps/v1

authentication.k8s.io/v1beta1

...

storage.k8s.io/v1

storage.k8s.io/v1beta1

v1

kubectl api-resources命令就是先獲取所有API版本信息,然后對(duì)每一個(gè)API版本調(diào)用接口獲取該版本下的所有API資源類(lèi)型

$ kubectl -v=8 api-resources

 5077 loader.go:375] Config loaded from file:  /root/.kube/config

 I1211 15:19:47.593450   15077 round_trippers.go:420] GET https://127.0.0.1:6443/api?timeout=32s

 I1211 15:19:47.602273   15077 request.go:1068] Response Body: {"kind":"APIVersions","versions":["v1"],"serverAddressByClientCIDRs":[{"clientCIDR":"0.0.0.0/0","serverAddress":"x.x.x.x:6443"}]}

 I1211 15:19:47.606279   15077 round_trippers.go:420] GET https://127.0.0.1:6443/apis?timeout=32s

 I1211 15:19:47.610333   15077 request.go:1068] Response Body: {"kind":"APIGroupList","apiVersion":"v1","groups":[{"name":"apiregistration.k8s.io","versions":[{"groupVersion":"apiregistration.k8s.io/v1","version":"v1"},{"groupVersion":"apiregistration.k8s.io/v1beta1","version":"v1beta1"}],"preferredVersion":{"groupVersion":"apiregistration.k8s.io/v1","version":"v1"}},{"name":"extensions","versions":[{"groupVersion":"extensions/v1beta1","version":"v1beta1"}],"preferredVersion":{"groupVersion":"extensions/v1beta1","version":"v1beta1"}},{"name":"apps","versions":[{"groupVersion":"apps/v1","version":"v1"}],"preferredVersion":{"groupVersion":"apps/v1","version":"v1"}},{"name":"events.k8s.io","versions":[{"groupVersion":"events.k8s.io/v1beta1","version":"v1beta1"}],"preferredVersion":{"groupVersion":"events.k8s.io/v1beta1","version":"v1beta1"}},{"name":"authentication.k8s.io","versions":[{"groupVersion":"authentication.k8s.io/v1","version":"v1"},{"groupVersion":"authentication.k8s.io/v1beta1","version":"v1beta1"}],"preferredVersion":{"groupVersion":"authentication.k8s.io/v1"," [truncated 4985 chars]

 I1211 15:19:47.614700   15077 round_trippers.go:420] GET https://127.0.0.1:6443/apis/batch/v1?timeout=32s

 I1211 15:19:47.614804   15077 round_trippers.go:420] GET https://127.0.0.1:6443/apis/authentication.k8s.io/v1?timeout=32s

 I1211 15:19:47.615687   15077 round_trippers.go:420] GET https://127.0.0.1:6443/apis/auth.tkestack.io/v1?timeout=32s

 https://127.0.0.1:6443/apis/authentication.k8s.io/v1beta1?timeout=32s

 I1211 15:19:47.616794   15077 round_trippers.go:420] GET https://127.0.0.1:6443/apis/coordination.k8s.io/v1?timeout=32s

 I1211 15:19:47.616863   15077 round_trippers.go:420] GET https://127.0.0.1:6443/apis/apps/v1?timeout=32s

 ...

 NAME                              SHORTNAMES   APIGROUP                  NAMESPACED       KIND

 bindings                                                                                         true                       Binding

 endpoints                         ep                                                          true                      Endpoints

 events                               ev                                                          true                      Event

 limitranges                       limits                                                      true                      LimitRange

 namespaces                     ns                                                           false                     Namespace

 nodes                               no                                                           false                    Node

 ...

namingController:檢查crd obj中是否有命名沖突,可在crd.status.conditions中查看;

establishingController:檢查crd是否處于正常狀態(tài),可在crd.status.conditions中查看;

nonStructuralSchemaController:檢查crd obj結(jié)構(gòu)是否正常,可在crd.status.conditions中查看;

apiApprovalController:檢查crd是否遵循Kubernetes API聲明策略,可在crd.status.conditions中查看;

finalizingController:類(lèi)似于finalizes的功能,與CRs的刪除有關(guān);

總結(jié)CR CRUD APIServer處理邏輯如下:

// New returns a new instance of CustomResourceDefinitions from the given config.

func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget) (*CustomResourceDefinitions, error) {

  ...

    crdHandler, err := NewCustomResourceDefinitionHandler(

      versionDiscoveryHandler,

        groupDiscoveryHandler,

      s.Informers.Apiextensions().V1().CustomResourceDefinitions(),

        delegateHandler,

      c.ExtraConfig.CRDRESTOptionsGetter,

        c.GenericConfig.AdmissionControl,

      establishingController,

        c.ExtraConfig.ServiceResolver,

      c.ExtraConfig.AuthResolverWrapper,

        c.ExtraConfig.MasterCount,

        s.GenericAPIServer.Authorizer,

        c.GenericConfig.RequestTimeout,

        time.Duration(c.GenericConfig.MinRequestTimeout)*time.Second,

        apiGroupInfo.StaticOpenAPISpec,

        c.GenericConfig.MaxRequestBodyBytes,

    )

    if err != nil {

        return nil, err

    }

    s.GenericAPIServer.Handler.NonGoRestfulMux.Handle("/apis", crdHandler)

    s.GenericAPIServer.Handler.NonGoRestfulMux.HandlePrefix("/apis/", crdHandler)

    ...

    return s, nil

}

·crdHandler處理邏輯如下:

解析req(GET/apis/duyanghao.example.com/v1/namespaces/default/students),根據(jù)請(qǐng)求路徑中的group(duyanghao.example.com),version(v1),以及resource字段(students)獲取對(duì)應(yīng)CRD內(nèi)容(crd,err:=r.crdLister.Get(crdName))

通過(guò)crd.UID以及crd.Name獲取crdInfo,若不存在則創(chuàng)建對(duì)應(yīng)的crdInfo(crdInfo,err:=r.getOrCreateServingInfoFor(crd.UID,crd.Name))。crdInfo中包含了CRD定義以及該CRD對(duì)應(yīng)Custom Resource的customresource.REST storage

customresource.REST storage由CR對(duì)應(yīng)的Group(duyanghao.example.com),Version(v1),Kind(Student),Resource(students)等創(chuàng)建完成,由于CR在Kubernetes代碼中并沒(méi)有具體結(jié)構(gòu)體定義,所以這里會(huì)先初始化一個(gè)范型結(jié)構(gòu)體Unstructured(用于保存所有類(lèi)型的Custom Resource),并對(duì)該結(jié)構(gòu)體進(jìn)行SetGroupVersionKind操作(設(shè)置具體Custom Resource Type)

從customresource.REST storage獲取Unstructured結(jié)構(gòu)體后會(huì)對(duì)其進(jìn)行相應(yīng)轉(zhuǎn)換然后返回

// k8s.io/kubernetes/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go:223

func (r *crdHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {

  ctx := req.Context()

  requestInfo, ok := apirequest.RequestInfoFrom(ctx)

  ...

  crdName := requestInfo.Resource + "." + requestInfo.APIGroup

  crd, err := r.crdLister.Get(crdName)

  ...

  crdInfo, err := r.getOrCreateServingInfoFor(crd.UID, crd.Name)

  verb := strings.ToUpper(requestInfo.Verb)

  resource := requestInfo.Resource

  subresource := requestInfo.Subresource

  scope := metrics.CleanScope(requestInfo)

  ...

  switch {

  case subresource == "status" && subresources != nil && subresources.Status != nil:

      handlerFunc = r.serveStatus(w, req, requestInfo, crdInfo, terminating, supportedTypes)

  case subresource == "scale" && subresources != nil && subresources.Scale != nil:

      handlerFunc = r.serveScale(w, req, requestInfo, crdInfo, terminating, supportedTypes)

  case len(subresource) == 0:

      handlerFunc = r.serveResource(w, req, requestInfo, crdInfo, terminating, supportedTypes)

  default:

      responsewriters.ErrorNegotiated(

          apierrors.NewNotFound(schema.GroupResource{Group: requestInfo.APIGroup, Resource: requestInfo.Resource}, requestInfo.Name),

          Codecs, schema.GroupVersion{Group: requestInfo.APIGroup, Version: requestInfo.APIVersion}, w, req,

      )

  }

  if handlerFunc != nil {

      handlerFunc = metrics.InstrumentHandlerFunc(verb, requestInfo.APIGroup, requestInfo.APIVersion, resource, subresource, scope, metrics.APIServerComponent, handlerFunc)

      handler := genericfilters.WithWaitGroup(handlerFunc, longRunningFilter, crdInfo.waitGroup)

      handler.ServeHTTP(w, req)

      return

  }

}

更多代碼原理詳情,參考kubernetes-reading-notes[1]。

Conclusion

本文從源碼層面對(duì)Kubernetes apiserver進(jìn)行了一個(gè)概覽性總結(jié),包括:aggregatorServer,kubeAPIServer,apiExtensionsServer以及bootstrap-controller等。通過(guò)閱讀本文可以對(duì)apiserver內(nèi)部原理有一個(gè)大致的理解,另外也有助于后續(xù)深入研究。

參考資料

[1]kubernetes-reading-notes:https://github.com/duyanghao/kubernetes-reading-notes/tree/master/core/api-ser

立即登錄,閱讀全文
版權(quán)說(shuō)明:
本文內(nèi)容來(lái)自于騰訊云原生,本站不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。文章內(nèi)容系作者個(gè)人觀(guān)點(diǎn),不代表快出海對(duì)觀(guān)點(diǎn)贊同或支持。如有侵權(quán),請(qǐng)聯(lián)系管理員(zzx@kchuhai.com)刪除!
相關(guān)文章
騰訊云數(shù)據(jù)庫(kù)PostgreSQL全面支持PG 17
騰訊云數(shù)據(jù)庫(kù)PostgreSQL全面支持PG 17
即日起,騰訊云PostgreSQL全面支持PostgreSQL 17.0。所有用戶(hù)可使用大版本升級(jí)能力升級(jí)至最新的PostgreSQL 17.0進(jìn)行體驗(yàn),也可以在產(chǎn)品購(gòu)買(mǎi)頁(yè)直接購(gòu)買(mǎi)。
騰訊云
云服務(wù)
2024-12-152024-12-15
高可用這個(gè)問(wèn)題,加機(jī)器就能解決?
高可用這個(gè)問(wèn)題,加機(jī)器就能解決?
互聯(lián)網(wǎng)服務(wù)的可用性問(wèn)題是困擾企業(yè)IT人員的達(dá)摩克利斯之劍:防于未然,體現(xiàn)不出價(jià)值。已然發(fā)生,又面臨P0危機(jī)。就更別提穩(wěn)定性建設(shè)背后顯性的IT預(yù)算問(wèn)題與隱性的人員成本問(wèn)題。
騰訊云
云服務(wù)
2024-11-252024-11-25
TDSQL TDStore引擎版替換HBase:在歷史庫(kù)場(chǎng)景中的成本與性能優(yōu)勢(shì)
TDSQL TDStore引擎版替換HBase:在歷史庫(kù)場(chǎng)景中的成本與性能優(yōu)勢(shì)
HBase憑借其高可用性、高擴(kuò)展性和強(qiáng)一致性,以及在廉價(jià)PC服務(wù)器上的低部署成本,廣泛應(yīng)用于大規(guī)模數(shù)據(jù)分析。
騰訊云
云服務(wù)
2024-11-042024-11-04
復(fù)雜查詢(xún)性能弱,只讀分析引擎來(lái)幫忙
復(fù)雜查詢(xún)性能弱,只讀分析引擎來(lái)幫忙
隨著當(dāng)今業(yè)務(wù)的高速發(fā)展,復(fù)雜多表關(guān)聯(lián)的場(chǎng)景越來(lái)越普遍。但基于行式存儲(chǔ)的數(shù)據(jù)庫(kù)在進(jìn)行復(fù)雜查詢(xún)時(shí)性能相對(duì)較弱。
騰訊云
云服務(wù)
2024-11-022024-11-02
優(yōu)質(zhì)服務(wù)商推薦
更多
掃碼登錄
打開(kāi)掃一掃, 關(guān)注公眾號(hào)后即可登錄/注冊(cè)
加載中
二維碼已失效 請(qǐng)重試
刷新
賬號(hào)登錄/注冊(cè)
小程序
快出海小程序
公眾號(hào)
快出海公眾號(hào)
商務(wù)合作
商務(wù)合作
投稿采訪(fǎng)
投稿采訪(fǎng)
出海管家
出海管家