<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          初識 Kubernetes API 的組織結(jié)構(gòu)

          共 12070字,需瀏覽 25分鐘

           ·

          2021-03-03 10:35


          前言

          話說自己入坑云原生也有好幾年了,但是對 kubernetes 基礎(chǔ)認(rèn)識卻不夠深,導(dǎo)致寫代碼的時候經(jīng)常需要打開 godoc 或者 kubernetes 源碼查看某個接口或者方法的定義。這種快餐式的消費代碼方式可以解決常見的問題,但有時候卻會被一個簡單的問題困擾很久。究其原因,還是沒有對 kubernetes 有比較系統(tǒng)的學(xué)習(xí),特別對于 kubernetes API 的設(shè)計與原理沒有較為深入的認(rèn)識,這也是我們平時擴展 kubernetes 功能繞不開的話題。與此同時,這也是很難講清楚的一個話題,是因為 kubernetes 經(jīng)過多個版本的迭代功能已經(jīng)趨于成熟與復(fù)雜,這一點也可以從 Github 平臺 kubernetes 組織下的多個倉庫也可以看得出來,相信很多人和我一樣,看到 kubernetes、client-go、api、apimachinery 等倉庫就不知道如何下手。事實上,從 API 入手是比較簡單的做法,特別是我們對于 kubernetes 核心組件的功能有了一定的了解之后。

          接下來的幾篇筆記,我將由淺入深地學(xué)習(xí) kubernetes API 的設(shè)計以及背后的原理。我的計劃是這樣的:

          1. 初識 kubernetes API 的組織結(jié)構(gòu)
          2. 深入 kubernetes API 的源碼實現(xiàn)
          3. 擴展 kubernetes API 的典型方式

          廢話不多說,我們先來認(rèn)識一下 kubernetes API 的基礎(chǔ)結(jié)構(gòu)以及背后的設(shè)計原理。

          API-Server

          我們知道 kubernetes 控制層面的核心組件包括 API-Server、 Controller Manager、Scheduler,其中 API-Server 對內(nèi)與分布式存儲系統(tǒng) etcd 交互實現(xiàn) kubernetes 資源(例如 pod、namespace、configMap、service 等)的持久化,對外提供通過 RESTFul 的形式提供 kubernetes API[1] 的訪問接口,除此之外,它還負(fù)責(zé) API 請求的認(rèn)證(authN)[2]、授權(quán)(authZ)[3]以及驗證[4]。剛提到的“對外”是相對的概念,因為除了像 kubectl 之類的命令行工具之外,kubernetes 的其他組件也會通過各種客戶端庫來訪問 kubernetes API,關(guān)于官方提供的各種客戶端庫請查看 client-libraries 列表[5],其中最典型的是 Go 語言的客戶端庫 client-go[6]

          API-Server 是 kubernetes 控制層面中唯一一個與 etcd 交互的組件,kubernetes 的其他組件都要通過 API-Server 來更新集群的狀態(tài),所以說 API-Server 是無狀態(tài)的;當(dāng)然也可以創(chuàng)建多個 API-Server 的實例來實現(xiàn)容災(zāi)。API-Server 通過配合 controller 模式來實現(xiàn)聲明式的 API 管理 kubernetes 資源。

          既然我們知道了 API-Server 的主要職責(zé)是提供 kubernetes 資源的 RESTFul API,那么客戶端怎么去請求 kubernetes 資源, API-Server 怎么去組織這些 kubernetes 資源呢?

          GVK vs GVR

          Kubernetes API 通過 HTTP 協(xié)議以 RESTful 的形式提供,API 資源的序列化方式主要是以 JSON 格式進行,但為了內(nèi)部通信也支持 Protocol Buffer 格式。為了方便擴展與演進,kubernetes API 支持分組與多版本,這體現(xiàn)在不同的 API 訪問路徑上。有了分組與多版本支持,即使要在新版本中去掉 API 資源的特定字段或者重構(gòu) API 資源的展現(xiàn)形式,也可以保證版本之間的兼容性。

          API-group

          將整個 kubernetes API 資源分成各個組,可以帶來很多好處:

          • 各組可以單獨打開或者關(guān)閉[7]
          • 各組可以有獨立的版本,在不影響其他組的情況下單獨向前衍化
          • 同一個資源可以同時存在于多個不同組中,這樣就可以同時支持某個特定資源穩(wěn)定版本與實驗版本

          關(guān)于 kubernetes API 資源的分組信息可以在序列化的資源定義中有所體現(xiàn),例如:

          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: example-deploy
          spec:
          ...

          其中 apiVersion 字段中 apps 即為 Deployment 資源的分組,實際上,Deployment 不止出現(xiàn)在 apps 分組里,也出現(xiàn)在 extensions 分組中,不同的分組可以實驗不同的特性;另外,kubernetes 中的核心資源如 pod、namespace、configmap、node、service 等存在于 core 分組中,但是由于歷史的原因,core 不出現(xiàn)在 apiVersion 字段中,例如以下定義一個 pod 資源的序列化對象:

          apiVersion: v1
          kind: Pod
          metadata:
            name: example-pod
            labels:
              app: exp
          ...

          API 分組也體現(xiàn)在訪問資源的 RESTful API 路徑上,core 組中的資源訪問路徑一般為 /api/$VERSION,其他命名組的資源訪問路徑則是 /apis/$GROUP_NAME/$VERSION,此外還有一些系統(tǒng)級別的資源,如集群指標(biāo)信息 /metrics,以上這些就基本構(gòu)成了 kubernetes API 的樹結(jié)構(gòu):

          API-version

          為了支持獨立的演進,kubernetes API 也支持不同的版本,不同的版本代表不同的成熟度。注意,這里說的是 API 而非資源支持多版本。因為多版本支持是針對 API 級別,而不是特定的資源或者資源的字段。一般來說,我們根據(jù) API 分組、資源類型、namespace 以及 name 來區(qū)分不同的資源對象,對于同一個資源對象的不同版本,API-Server 負(fù)責(zé)不同版本之間的無損切換,這點對于客戶端來說是完全透明的。事實上,不同版本的同類型的資源在持久化層的數(shù)據(jù)可能是相同的。例如,對于同一種資源類型支持 v1v1beta1 兩個 API 版本,以 v1beta1 版本創(chuàng)建該資源的對象,后續(xù)可以以v1 或者 v1beta1 來更新或者刪除該資源對象。

          API 多版本支持一般通過將資源分組置于不同的版本中來實現(xiàn),例如,batch 同時存在 v2alph1v1 版本。一般來說,新的資源分組先出現(xiàn) v1alpha1 版本,隨著穩(wěn)定性的提高被推進到 v1beta1 ,最后從 v1 版本畢業(yè)。

          隨著新的用戶場景出現(xiàn),kubernetes API 需要不斷變化,可能是新增一個字段,也可能是刪除舊的字段,甚至是改變資源的展現(xiàn)形式。為了保證兼容性,kubernetes 制定了一系列的策略[8]??偟膩碚f,對于已經(jīng) GA 的 API,API,kubernetes 嚴(yán)格維護其兼容性,終端用戶可以放心食用,beta 版本的 API 則盡量維護,保證不打破版本跨版本之間的交互,而對于 alpha 版本的 API 則很難保證兼容性,不太推薦生產(chǎn)環(huán)境使用。

          GVK 與 GVR 映射

          在 kubernetes API 宇宙中,我們經(jīng)常使用屬于 GVK 或者 GVR 來區(qū)分特定的 kubernetes 資源。其中 GVK 是 Group Version Kind 的簡稱,而 GVR 則是 Group Version Resource 的簡稱。

          通過上面對于 kubernetes API 分組和多版本的介紹中我們已經(jīng)了解了 Group 與 Version,那么 Kind 與 Resource 又分別是指什么呢?

          Kind 是 API “頂級”資源對象的類型,每個資源對象都需要 Kind 來區(qū)分它自身代表的資源類型,例如,對于一個 pod 的例子:

          apiVersion: v1
          kind: Pod
          metadata:
            name: example-pod
            labels:
              app: exp
          ...

          其中 kind 字段即代表該資源對象的類型。一般來說,在 kubernetes API 中有三種不同的 Kind:

          1. 單個資源對象的類型,最典型的就是剛才例子中提到的 Pod
          2. 資源對象的列表類型,例如 PodList 以及 NodeList 等
          3. 特殊類型以及非持久化操作的類型,很多這種類型的資源是 subresource, 例如用于綁定資源的 /binding、更新資源狀態(tài)的 /status 以及讀寫資源實例數(shù)量的 /scale

          需要注意的是,同 Kind 不止可以出現(xiàn)在同一分組的不同版本中,如 apps/v1beta1apps/v1,它還可能出現(xiàn)在不同的分組中,例如 Deployment 開始以 alpha 的特性出現(xiàn)在 extensions 分組,GA 之后被推進到 apps 組,所以為了嚴(yán)格區(qū)分不同的 Kind,需要組合 API Group、API Version 與 Kind 成為 GVK。

          Resource 則是通過 HTTP 協(xié)議以 JSON 格式發(fā)送或者讀取的資源展現(xiàn)形式,可以以單個資源對象展現(xiàn),例如 .../namespaces/default,也可以以列表的形式展現(xiàn),例如 .../jobs。要正確的請求資源對象,API-Server 必須知道 apiVersion 與請求的資源,這樣 API-Server 才能正確地解碼請求信息,這些信息正是處于請求的資源路徑中。一般來說,把 API Group、API Version 以及 Resource 組合成為 GVR 可以區(qū)分特定的資源請求路徑,例如 /apis/batch/v1/jobs 就是請求所有的 jobs 信息。

          GVR 常用于組合成 RESTful API 請求路徑。例如,針對應(yīng)用程序 v1 部署的 RESTful API 請求如下所示:

          GET /apis/apps/v1/namespaces/{namespace}/deployments/{name}

          通過獲取資源的 JSON 或 YAML 格式的序列化對象,進而從資源的類型信息中可以獲得該資源的 GVK;相反,通過 GVK 信息則可以獲取要讀取的資源對象的 GVR,進而構(gòu)建 RESTful API 請求獲取對應(yīng)的資源。這種 GVK 與 GVR 的映射叫做 RESTMapper。Kubernetes 定義了 RESTMapper 接口[9]并帶默認(rèn)帶有實現(xiàn) DefaultRESTMapper[10]。

          關(guān)于 kubernetes API 的詳細(xì)規(guī)范請參考 API Conventions[11]

          如何儲存

          經(jīng)過上一章節(jié)的研究,我們已經(jīng)知道了 kubernetes API 的組織結(jié)構(gòu)以及背后的設(shè)計原理,那么,Kubernetes API 的資源對象最終是怎么提供可靠存儲的。之前也提到了 API-Server 是無狀態(tài)的,它需要與分布式存儲系統(tǒng) etcd[12] 交互來實現(xiàn)資源對象的持久化操作。從概念上講,etcd 支持的數(shù)據(jù)模型是鍵值(key-value)存儲。在 etcd2 中,各個 key 是以層次結(jié)構(gòu)存在,而在 etcd3 中這個就變成了平級模型,但為了保證兼容性也保持了層次結(jié)構(gòu)的方式。

          在 Kubernetes 中 etcd 是如何使用的呢?實際上,前面也提到了,etcd 被部署為獨立的部分,甚至多個 etcd 可以組成集群,API-Server 負(fù)責(zé)與 etcd 交互來完成資源對象的持久化。從 1.5.x 之后,Kubernetes 開始全面使用 etcd3。可以在 API-Server 的相關(guān)啟動項參數(shù)中配置使用 etcd 的方式:

          $ kube-apiserver -h
          ...
          Etcd flags:

                --etcd-cafile string
                          SSL Certificate Authority file used to secure etcd communication.
                --etcd-certfile string
                          SSL certification file used to secure etcd communication.
                ...
                --etcd-keyfile string
                          SSL key file used to secure etcd communication.
                --etcd-prefix string
                          The prefix to prepend to all resource paths in etcd. (default "/registry")
                ...
                --storage-backend string
                          The storage backend for persistence. Options: 'etcd3' (default).
                --storage-media-type string
                          The media type to use to store objects in storage. Some resources or storage backends may only support a specific media type and will ignore this setting. (default
                          "application/vnd.kubernetes.protobuf")
          ...

          Kubernetes 資源對象是以 JSON 或 Protocol Buffers 格式存儲在 etcd 中,這可以通過配置 kube-apiserver 的啟動參數(shù) --storage-media-type 來決定想要序列化數(shù)據(jù)存入 etcd 的格式,默認(rèn)情況下為 application/vnd.kubernetes.protobuf 格式;另外也可以通過配置 --storage-versions 啟動參數(shù)來配置每個 API 分組的資源對象的持久化存儲的默認(rèn)版本號。

          下面通過一個簡單的例子來看,創(chuàng)建一個 pod,然后使用 etcdctl 工具來查看存儲在 etcd 中數(shù)據(jù):

          $ cat << EOF | kubectl create -f -
          apiVersion: v1
          kind: Pod
          metadata:
            name: webserver
          spec:
            containers:
            - name: nginx
              image: nginx
              ports:
              - containerPort: 80
          EOF
          pod/webserver created
          $ etcdctl --endpoints=$ETCD_URL \
            --cert /etc/kubernetes/pki/etcd/server.crt \
            --key /etc/kubernetes/pki/etcd/server.key \
            --cacert /etc/kubernetes/pki/etcd/ca.crt \
            get /registry/pods/default/webserver --prefix -w simple
          /registry/pods/default/webserver
          ...
          10.244.0.5"

          使用各種客戶端工具創(chuàng)建資源對象到然后存儲到 etcd 的流程大致如下圖所示:

          1. 客戶端工具(例如 kubectl)提供一個期望狀態(tài)的資源對象的序列化表示,該例子使用 YAML 格式提供
          2. kubectl 將 YAML 轉(zhuǎn)換為 JSON 格式,并發(fā)送給 API-Server
          3. 對應(yīng)同類型對象的不同版本,API-Server 執(zhí)行無損轉(zhuǎn)換。對于老版本中不存在的字段則存儲在 annotations 中
          4. API-Server 將接收到的對象轉(zhuǎn)換為規(guī)范存儲版本,這個版本由 API-Server 啟動參數(shù)指定,一般是最新的穩(wěn)定版本
          5. 最后將資源對象通過 JSON 或 protobuf 方式解析并通過一個特定的 key 存入 etcd 當(dāng)中

          上面提到的無損轉(zhuǎn)換是如何進行的?下面使用 Kubernetes 資源對象對象 Horizontal Pod Autoscaling (HPA) 來舉例說明:

          $ kubectl proxy --port=8080 &
          $ cat << EOF | kubectl apply -f -
          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: webserver
          spec:
            selector:
              matchLabels:
                app: webserver
            template:
              metadata:
                labels:
                  app: webserver
              spec:
                containers:
                  - name: nginx
                    image: nginx
                    ports:
                      - containerPort: 80
          EOF
          $ kubectl autoscale deployment webserver --min=2 --max=5 --cpu-percent=80
          $ curl http://127.0.0.1:8001/apis/autoscaling/v2beta1/namespaces/default/horizontalpodautoscalers/webserver > hpa-v2beta1.json
          $ curl http://127.0.0.1:8001/apis/autoscaling/v2beta2/namespaces/default/horizontalpodautoscalers/webserver > hpa-v2beta2.json
          $ diff hpa-v2beta1.json hpa-v2beta2.json
          3c3
          <   "apiVersion""autoscaling/v2beta1",
          ---
          >   "apiVersion""autoscaling/v2beta2",
          42c42,45
          <           "targetAverageUtilization": 80
          ---
          >           "target": {
          >             "type""Utilization",
          >             "averageUtilization": 80
          >           }

          通過上面命令的輸出能夠看出,即使 HorizontalPodAutoscale 的版本從 v2beta1 變?yōu)榱?v2beta2,API-Server 也能夠在不同的版本之前無損轉(zhuǎn)換,不論在 etcd 中實際存的是哪個版本。實際上,API-Server 將所有已知的 Kubernetes 資源類型保存在名為 Scheme 的注冊表(registry)中。在此注冊表中,定義了每種 Kubernetes 資源的類型、分組、版本以及如何轉(zhuǎn)換它們,如何創(chuàng)建新對象,以及如何將對象編碼和解碼為 JSON 或 protobuf 格式的序列化形式。

          參考資料

          [1]

          kubernetes API: https://kubernetes.io/docs/concepts/overview/kubernetes-api/

          [2]

          認(rèn)證(authN): https://kubernetes.io/docs/reference/access-authn-authz/authentication/

          [3]

          授權(quán)(authZ): https://kubernetes.io/docs/reference/access-authn-authz/authorization/

          [4]

          驗證: https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/

          [5]

          client-libraries 列表: https://kubernetes.io/docs/reference/using-api/client-libraries/

          [6]

          client-go: https://github.com/kubernetes/client-go/

          [7]

          打開或者關(guān)閉: https://kubernetes.io/docs/reference/using-api/#enabling-or-disabling

          [8]

          策略: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api_changes.md

          [9]

          RESTMapper 接口: https://github.com/kubernetes/apimachinery/blob/master/pkg/api/meta/interfaces.go

          [10]

          DefaultRESTMapper: https://github.com/kubernetes/apimachinery/blob/master/pkg/api/meta/restmapper.go

          [11]

          API Conventions: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md

          [12]

          etcd: https://etcd.io/


          原文鏈接:https://morven.life/posts/the_k8s_api-1/



          你可能還喜歡

          點擊下方圖片即可閱讀

          Wireguard 全互聯(lián)模式(full mesh)權(quán)威指南

          云原生是一種信仰 ??


          關(guān)注公眾號

          后臺回復(fù)?k8s?獲取史上最方便快捷的 Kubernetes 高可用部署工具,只需一條命令,連 ssh 都不需要!



          點擊 "閱讀原文" 獲取更好的閱讀體驗!


          發(fā)現(xiàn)朋友圈變“安靜”了嗎?

          瀏覽 65
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  肏逼视频在线免费观看 | 日韩男女操逼 | 影音先锋琪琪色 | 国产免费一级A片 | 成人黄网站在线观看 |