Skip to content

Kubernetes API 基礎

原文: https://iximiuz.com/en/posts/kubernetes-api-structure-and-terminology/

這是關於如何從代碼中使用 Kubernetes API 的系列文章中的第一篇。 Kubernetes API 比一堆 HTTP 端點組合在一起要先進一點。因此,在嘗試從代碼中訪問它之前,了解 Kubernetes API 結構並熟悉術語至關重要。否則,嘗試將非常痛苦——官方的 Go 客戶端帶有太多的花里胡哨,試圖將你的頭腦圍繞在客戶端和 API 概念上,可能很快就會讓你不知所措。

Kubernetes API 非常龐大——它有數百個端點。幸運的是,它非常一致,因此只需了解有限數量的想法,然後將這些知識外推到 API 的其餘部分。在這篇文章中,我將嘗試觸及我發現的最基本的概念。我傾向於簡單和易消化,而不是學術上的正確性和材料的完整性。和往常一樣,我只是分享我對事物的理解和思考這個話題的方式——所以,它不是 API 手冊,而是個人學習經驗的記錄。

Resources and Verbs

由於它是一個 RESTful 領域,我們將根據resource(鬆散地,某種結構的對象)和verb(對這些對象的操作)進行操作。

在討論resources時,將 a resource as a certain kind of objectsa resource as a particular instance of some kind 區分開來是很重要的。因此,Kubernetes API 端點被正式命名為資源類型 (resource types),以避免與資源實例 (resource instances) 產生歧義。然而,對一般應用程式的開發者來,端點(endpoint)通常被稱為資源(resource),因此這個詞的實際含義得從上下文中來得出。

出於可擴展性的原因,resource types 被組織成 API groups,並且這些 API 群組彼此獨立地進行版本控制:

$ kubectl api-resources

NAME                              SHORTNAMES   APIVERSION                             NAMESPACED   KIND
bindings                                       v1                                     true         Binding
componentstatuses                 cs           v1                                     false        ComponentStatus
configmaps                        cm           v1                                     true         ConfigMap
endpoints                         ep           v1                                     true         Endpoints
events                            ev           v1                                     true         Event
limitranges                       limits       v1                                     true         LimitRange
namespaces                        ns           v1                                     false        Namespace
nodes                             no           v1                                     false        Node
persistentvolumeclaims            pvc          v1                                     true         PersistentVolumeClaim
persistentvolumes                 pv           v1                                     false        PersistentVolume
pods                              po           v1                                     true         Pod
podtemplates                                   v1                                     true         PodTemplate
replicationcontrollers            rc           v1                                     true         ReplicationController
resourcequotas                    quota        v1                                     true         ResourceQuota
secrets                                        v1                                     true         Secret
serviceaccounts                   sa           v1                                     true         ServiceAccount
services                          svc          v1                                     true         Service
mutatingwebhookconfigurations                  admissionregistration.k8s.io/v1        false        MutatingWebhookConfiguration
validatingwebhookconfigurations                admissionregistration.k8s.io/v1        false        ValidatingWebhookConfiguration
customresourcedefinitions         crd,crds     apiextensions.k8s.io/v1                false        CustomResourceDefinition
apiservices                                    apiregistration.k8s.io/v1              false        APIService
controllerrevisions                            apps/v1                                true         ControllerRevision
daemonsets                        ds           apps/v1                                true         DaemonSet
deployments                       deploy       apps/v1                                true         Deployment
replicasets                       rs           apps/v1                                true         ReplicaSet
statefulsets                      sts          apps/v1                                true         StatefulSet
tokenreviews                                   authentication.k8s.io/v1               false        TokenReview
localsubjectaccessreviews                      authorization.k8s.io/v1                true         LocalSubjectAccessReview
selfsubjectaccessreviews                       authorization.k8s.io/v1                false        SelfSubjectAccessReview
selfsubjectrulesreviews                        authorization.k8s.io/v1                false        SelfSubjectRulesReview
subjectaccessreviews                           authorization.k8s.io/v1                false        SubjectAccessReview
horizontalpodautoscalers          hpa          autoscaling/v2                         true         HorizontalPodAutoscaler
cronjobs                          cj           batch/v1                               true         CronJob
jobs                                           batch/v1                               true         Job
certificatesigningrequests        csr          certificates.k8s.io/v1                 false        CertificateSigningRequest
leases                                         coordination.k8s.io/v1                 true         Lease
endpointslices                                 discovery.k8s.io/v1                    true         EndpointSlice
events                            ev           events.k8s.io/v1                       true         Event
flowschemas                                    flowcontrol.apiserver.k8s.io/v1beta2   false        FlowSchema
prioritylevelconfigurations                    flowcontrol.apiserver.k8s.io/v1beta2   false        PriorityLevelConfiguration
ingressclasses                                 networking.k8s.io/v1                   false        IngressClass
ingresses                         ing          networking.k8s.io/v1                   true         Ingress
networkpolicies                   netpol       networking.k8s.io/v1                   true         NetworkPolicy
runtimeclasses                                 node.k8s.io/v1                         false        RuntimeClass
poddisruptionbudgets              pdb          policy/v1                              true         PodDisruptionBudget
podsecuritypolicies               psp          policy/v1beta1                         false        PodSecurityPolicy
clusterrolebindings                            rbac.authorization.k8s.io/v1           false        ClusterRoleBinding
clusterroles                                   rbac.authorization.k8s.io/v1           false        ClusterRole
rolebindings                                   rbac.authorization.k8s.io/v1           true         RoleBinding
roles                                          rbac.authorization.k8s.io/v1           true         Role
priorityclasses                   pc           scheduling.k8s.io/v1                   false        PriorityClass
csidrivers                                     storage.k8s.io/v1                      false        CSIDriver
csinodes                                       storage.k8s.io/v1                      false        CSINode
csistoragecapacities                           storage.k8s.io/v1beta1                 true         CSIStorageCapacity
storageclasses                    sc           storage.k8s.io/v1                      false        StorageClass
volumeattachments                              storage.k8s.io/v1                      false        VolumeAttachment

如果你好奇 kubectl api-resources 命令是如何構建這樣一個支持的資源列表的,這裡有一個很好的技巧,它顯示了任何 kubectl 命令進行了哪些 API 調用:

$ kubectl api-resources -v 6  # -v 6 means "extra verbose logging"

...
I0108 ... GET https://192.168.58.2:8443/api?timeout=32s 200 OK in 10 milliseconds
I0108 ... GET https://192.168.58.2:8443/apis?timeout=32s 200 OK in 1 milliseconds
I0108 ... GET https://192.168.58.2:8443/apis/apiregistration.k8s.io/v1?timeout=32s 200 OK in 7 milliseconds
I0108 ... GET https://192.168.58.2:8443/api/v1?timeout=32s 200 OK in 13 milliseconds
I0108 ... GET https://192.168.58.2:8443/apis/authentication.k8s.io/v1?timeout=32s 200 OK in 13 milliseconds
I0108 ... GET https://192.168.58.2:8443/apis/events.k8s.io/v1?timeout=32s 200 OK in 15 milliseconds
I0108 ... GET https://192.168.58.2:8443/apis/apps/v1?timeout=32s 200 OK in 14 milliseconds
I0108 ... GET https://192.168.58.2:8443/apis/autoscaling/v2beta1?timeout=32s 200 OK in 16 milliseconds
I0108 ... GET https://192.168.58.2:8443/apis/policy/v1beta1?timeout=32s 200 OK in 14 milliseconds
I0108 ... GET https://192.168.58.2:8443/apis/scheduling.k8s.io/v1?timeout=32s 200 OK in 14 milliseconds
I0108 ... GET https://192.168.58.2:8443/apis/batch/v1?timeout=32s 200 OK in 13 milliseconds
I0108 ... GET https://192.168.58.2:8443/apis/batch/v1beta1?timeout=32s 200 OK in 43 milliseconds
...

其實 ubernetes 的 API 都具備了相當豐富的 meta data 來陳述這個 Kubernetes API 基本資料。顯然,您可以通過讀取(或創建)其他資源來列出現有的(甚至註冊新的資源類型)!例如,上面的列表是通過調用特殊的 /api/apis/<group-name> 資源獲得的。

Info

/api 端點已經是最初 Kubernetes 定義與使用的,僅用於核心資源(pod、secrets、configmaps 等)。一個更現代和通用的 /apis/<group-name> 端點用於其餘資源,包括用戶定義的自定義資源。

您可以使用 curl 等標準 HTTP 客戶端輕鬆調用上述資源(即 API 端點)並檢查返回的資源(即 JSON 對象):

# Make Kubernetes API available on localhost:8080
# to bypass the auth step in subsequent queries:
$ kubectl proxy --port=8080 &

# List all known API paths
$ curl http://localhost:8080/
# List known versions of the `core` group
$ curl http://localhost:8080/api
# List known resources of the `core/v1` group
$ curl http://localhost:8080/api/v1
# Get a particular Pod resource
$ curl http://localhost:8080/api/v1/namespaces/default/pods/sleep-7c7db887d8-dkkcg

# List known groups (all but `core`)
$ curl http://localhost:8080/apis
# List known versions of the `apps` group 
$ curl http://localhost:8080/apis/apps
# List known resources of the `apps/v1` group
$ curl http://localhost:8080/apis/apps/v1
# Get a particular Deployment resource
$ curl http://localhost:8080/apis/apps/v1/namespaces/default/deployments/sleep

Info

有一種更簡單的方法來檢查 Kubernetes API:kubectl get --raw /SOME/API/PATH。然而,上面的練習是為了表明 Kubernetes API 並不神奇。擁有一個通用型的 HTTP 客戶端或工具就足以開始使用它了。

說到 verbs (即對資源的操作),所有標準的 CRUD 操作及其傳統映射到 HTTP 方法都在那裡。此外,還支持資源的patching(選擇性字段修改)和 watching(流式集合的讀取)。在 Kubernetes 官方開發指南中定義了詳細的說明: sig-architecture/api-conventions.md

## Verbs on Resources

API resources should use the traditional REST pattern:

GET /<resourceNamePlural> - Retrieve a list of type <resourceName>, e.g. GET /pods returns a list of Pods.
POST /<resourceNamePlural> - Create a new resource from the JSON object provided by the client.
GET /<resourceNamePlural>/<name> - Retrieves a single resource with the given name, e.g. GET /pods/first returns a Pod named 'first'. Should be constant time, and the resource should be bounded in size.
DELETE /<resourceNamePlural>/<name> - Delete the single resource with the given name. DeleteOptions may specify gracePeriodSeconds, the optional duration in seconds before the object should be deleted. Individual kinds may declare fields which provide a default grace period, and different kinds may have differing kind-wide default grace periods. A user provided grace period overrides a default grace period, including the zero grace period ("now").
DELETE /<resourceNamePlural> - Deletes a list of type <resourceName>, e.g. DELETE /pods a list of Pods.
PUT /<resourceNamePlural>/<name> - Update or create the resource with the given name with the JSON object provided by the client.
PATCH /<resourceNamePlural>/<name> - Selectively modify the specified fields of the resource. See more information below.
GET /<resourceNamePlural>?watch=true - Receive a stream of JSON objects corresponding to changes made to any resource of the given kind over time.

## PATCH operations

The API supports three different PATCH operations, determined by their corresponding Content-Type header:

JSON Patch, Content-Type: application/json-patch+json
As defined in RFC6902, a JSON Patch is a sequence of operations that are executed on the resource, e.g. {"op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ]}. For more details on how to use JSON Patch, see the RFC.
Merge Patch, Content-Type: application/merge-patch+json
As defined in RFC7386, a Merge Patch is essentially a partial representation of the resource. The submitted JSON is "merged" with the current resource to create a new one, then the new one is saved. For more details on how to use Merge Patch, see the RFC.
Strategic Merge Patch, Content-Type: application/strategic-merge-patch+json
Strategic Merge Patch is a custom implementation of Merge Patch. For a detailed explanation of how it works and why it needed to be introduced, see here.

Kinds aka Object Schemas

kind(類型) 這個詞會時不時地出現在這里和那裡。例如,在 kubectl api-resources 輸出中,您可以看到 persistentvolumes 資源具有相應的 PersistentVolume 類型。

很長一段時間以來,我與 Kubernetes 的交互僅限於使用 kubectl apply 盲目地為其提供清單。這讓我覺得 kind 總是包含一個資源的 CamelCase 名稱,比如 PodServiceDeployment 等。

$ cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment
spec:
  replicas: 1
  selector:
    ...
EOF

但實際上,就算不是資源的 Kubernetes 數據結構也可以有Kind的宣告:

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata

甚至 Kubernetes 對象(即持久實體)的資源也有Kind

$ kubectl get --raw /api | jq
{
  "kind": "APIVersions",
  "versions": [
    "v1"
  ],
  "serverAddressByClientCIDRs": [
    {
      "clientCIDR": "0.0.0.0/0",
      "serverAddress": "192.168.49.2:8443"
    }
  ]
}

那麼,什麼是kind

Info

"All resource types have a concrete representation which is called a kind" - Kubernetes API reference. 嗯,這個解釋不是特別有用! 🤔

事實證明,在 Kubernetes 中,一種Kindobject schema。就像您通常使用 JSON schema 那樣。換句話說,Kind是指特定的數據結構,即 attributes 和 properties 的某種組合。

根據 sig-architecture/api-conventions.mdKind 分為三類:

  • Objects (Pod, Service, etc) - persistent entities in the system.
  • Lists - (PodList, APIResourceList, etc) - collections of resources of one or more kinds.
  • Simple - specific actions on objects (status, scale, etc.) or non-persistent auxiliary entities (ListOptions, Policy, etc).

Kubernetes 中使用的大多數物件(object),包括 API 返回的所有 JSON 物件,都有 kind 字段。它允許客戶端和服務器在通過網絡發送它們或將它們存儲在磁盤上之前正確地序列化和反序列化這些物件。

Kubernetes Objects

就像 resource 一樣,Kubernetes 用語中的 object一詞是也是搞的大家暈頭轉向的。從廣義上講,Objects 可以指任何數據結構——資源類型的實例(如 APIGroup)、配置(如審計策略)或持久實體(如 Pod)。但是,在本節中,我將在狹義的、明確定義的意義上討論 object。所以,我將使用大寫的詞 Object 來代替。

大多數 Kubernetes API 資源代表 Object。與僅要求 kind 字段的其他形式的資源不同,Objects 必須定義更多字段:

  • kind - a string that identifies the schema this object should have
  • apiVersion - a string that identifies the version of the schema the object should have
  • metadata.namespace - a string with the namespace (defaults to "default")
  • metadata.name - a string that uniquely identifies this object within the current namespace
  • metadata.uid - a unique in time and space value used to distinguish between objects with the same name that have been deleted and recreated.

此外,metadata 也可能包括標籤和註釋字段,以及一些版本控制和時間戳信息。

示例 - Pod 對象(截斷輸出):

$ kubectl get --raw /api/v1/namespaces/default/pods/sleep-7c7db887d8-dkkcg | jq
{
    "apiVersion": "v1",
    "kind": "Pod",
    "metadata": {
        "namespace": "default",
        "name": "sleep-7c7db887d8-dkkcg",        
        "uid": "32bf410a-0009-484e-adac-21179ec28f0f",
        "labels": {
            "app": "sleep",
            "pod-template-hash": "7c7db887d8"
        },        
        "creationTimestamp": "2022-01-08T18:10:04Z",
        "resourceVersion": "465766"        
    },
    "spec": { ... },
    "status": { ... }
}

如上例所示,Kubernetes 對象通常具有 spec(期望狀態)和 status(實際狀態)字段。但情況並非總是如此。將上面的輸出與下面的 ConfigMap 對象進行比較:

$ kubectl get --raw /api/v1/namespaces/default/configmaps/informer-dynamic-simple-wzgmx | jq
{
    "apiVersion": "v1",
    "kind": "ConfigMap",
    "data": {
        "foo": "bar"
    },    
    "metadata": {
        "namespace": "default",
        "name": "informer-dynamic-simple-wzgmx",
        "uid": "74471398-0244-4686-b490-7007f6246a63",
        "creationTimestamp": "2022-01-06T21:45:04Z",
        "generateName": "informer-dynamic-simple-",
        "resourceVersion": "418185"        
    }
}

從代碼中處理 Kubernetes API 涉及到大量的 Object 操作,因此必須對常見的對象結構有紮實的理解。 kubectl explain 命令可以幫助您。它最酷的部分是它不僅可以在資源上調用,還可以在嵌套字段上調用:

$ kubectl explain deployment.spec.template
KIND:     Deployment
VERSION:  apps/v1

RESOURCE: template <Object>

DESCRIPTION:
     Template describes the pods that will be created.

     PodTemplateSpec describes the data a pod should have when created from a
     template

FIELDS:
   metadata <Object>
     Standard object's metadata. More info:
     https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata

   spec <Object>
     Specification of the desired behavior of the pod. More info:
     https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status

Summarizing

Kubernetes 用語中的 resource 可以指資源類型和資源實例。資源類型被組織成 API groups,並且 API groups是版本化的。每個資源表示都遵循由其種類定義的特定模式。雖然每個資源都遵循由其種類定義的具體結構,但並非每個資源都代表一個 Kubernetes 對象。對像是表示意圖記錄的持久實體。不同種類的對象具有不同的結構,但所有對像都帶有共同的元數據屬性,例如命名空間、名稱、uid 或 creationTimestamp。

What's next?

對 Kubernetes API 的理論部分有更好的了解嗎? 太好了! 接下來我們將用一個簡單的 HTTP 客戶端調用它(事實證明這不是一件容易的事,有很多坑要跳)。

當理論和實踐相提並論時,我建議看一下 k8s.io/apik8s.io/apimachinery 模塊 - 這是官方 Go 客戶端的兩個主要依賴項。 k8s.io/api為 Kubernetes 對象定義的 Go 結構,而 k8s.io/apimachinery帶來了較低級別的構建塊和常見的 API 功能,如序列化、類型轉換或錯誤處理。這是我對這兩個模塊的圖解概述

Talk is cheap, show me the code? 大家可看我在 GitHub 上收集的 Kubernetes client-go 示例😉

Resources