Kubernetes API的使用方式
Kubernetes API屬於聲明式API編程, 它和常用的命令式編程有一些區別。 通俗的說,命令式編程是第一人稱,我要做什么,我要怎么做。 操作系統最喜歡這種編程范式了, 操作系統幾乎不用"思考", 只要一對一的將代碼翻譯成指令就可以了。 而聲明式編程則類似於"第二人稱", 也就是你要做什么。 有點"產品經理"和"開發“之間的關系, "產品經理"只負責提需求,而"開發"怎么實現他不並關心。
用戶相對Kubernetes就是"產品經理"的角色, 用戶只需要給Kubernetes提需求就可以了,比如說你(Kubernetes)給我(用戶)創建一個運行Mysql服務的Demployment,這個Deployment運行的Pod鏡像是xxxx,運行參數是xxxxx,掛載的數據卷是xxxxx。。。。。 等等。 開發(Kubernetes)接受到這個需求后,看看需求是否合理(驗證Deployment里面的參數是否正確),然后就開始創建了。 等待創建成功后,就告訴"產品經理"(用戶)Deployment創建成功。
在創建過程中,用戶並沒有(也不需要)關心服務是如何創建的。 這種操作方式就是聲明式API。
對於Kubernetes來說,聲明式API最大的難點就在於如何提一個正確的需求了。 所以下面來看看如何給Kubernetes提需求。
API的載體 -- Yaml
用戶可以通過kubectl
與Kubernetes交互,使用kubectl
會通過讀取指定的資源定義文件來要求kubernetes創建各種資源,這里的資源文件指的就是"需求文檔",在里面規定了各種資源的"大小","規格"。 為了用戶可以方便理解里面的內容(實際使用過程中,感覺使用yaml其實並不方便。尤其是當數據層次多的時候,經常出現空白符不匹配導致解析失敗的問題),資源文件使用了yaml
格式(yaml
對用戶友好,kubectl
提交需求時,會將yaml轉換成json格式,所以Kubernetes其實最終讀取的是json格式的需求文檔).
我經常在編輯完之后,通過 https://codebeautify.org/yaml-validator 來驗證格式是否正確。
編輯Yaml過程中,有如下幾個注意事項:
- 通過空格控制縮進,不支持Tab
- 如果參數是以空格開始,則需要單引號將其包含起來, 如果參數中包括單引號,則需要進行轉義操作
- 冒號后一定要有空格
- 使用一個短橫+一個空格表示列表,同樣的縮進層級表示屬於同一個列表
- 空值使用null或者~表示。
API文檔總覽
Kubernetes的API文檔在 https://kubernetes.io/docs/reference/ 點擊版本號,就可以看到相對應的API文檔說明。
Kubernetes API大致分為以下幾類(個人起的名稱,未必准確):
- 計算類
- 負載類
- 配置類
- 管理類
計算類對應是Workload
,主要是Pod,Job,Deployment,ReplicaSet之類涉及到CPU計算的各種資源。 負載類指的是LB類資源,配置類指的是ConfigMap
之類涉及到外部資源的數據資源, 而管理類指的是對集群的管理,例如創建命名空間,節點隔離等
對Kubernetes的資源操作,絕大多數就是對上面四類資源的操作。
一個標准的Kubernetes 資源文件,其結構大致是下面的樣子:
apiVersion:
kind:
metadata:
spec:
status:
apiVersion
表示API版本,服務端會通過讀取這個版本號,來進行內容驗證。 這個版本號可以通過API文檔獲取,例如要編寫一個Deployment資源,首先查看API文檔(https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#daemonset-v1-apps)如下:
版本號由Group/Version
這樣的格式組成,因此Deployment的apiVersion
就是apps/v1
。 需要注意下面一行小字: "Other API versions of this object exist: v1beta2 v1beta1 v1beta1",因此apps/v1beta2
, apps/v1beta1
這樣的版本號也是合法的。 具體使用哪個版本號,最終要取決於集群支持哪個版本號。
kind
表示操作的是什么資源, 向上面要操作Deployment,kind就是Deployment。 如果要創建Pod,則Kind就是Pod。
metadata
則是此資源的一些元數據, 如何設置后面會聊到
spec
是具體如何創建這個資源,同樣放到后面再聊
status
是此資源狀態數據,用戶不需要設置,即便設置,集群也會過濾掉
總結一下:
用戶通過apiversion
+kind
告之集群,准備按照哪個API版本所規定的協議創建何種資源。 集群確認支持指定版本和資源后,就會讀取后面的資源詳細參數。 但需要注意,未必所有資源都有這幾項,例如Configmap
就沒有Spec,但卻增加了data. 后面會聊到如何通過API文檔來組織資源文件
創建資源
來看metadata
。每種資源有不同的metadata
規范, 大部分場景中可以通用的,也就是說雖然資源不同,但metadata格式相同,只是里面的參數不同。 當需要查看具體metadata
時,直接點擊metadata
下面的ObjectMeta
,如下圖:
會跳到ObjectMeata
定義頁面中:
這里仍然假設需要創建一個Deployment,apiVersion
和kind
此時都已經確定了(如果仍然不明白,建議再看一下上面一節)。 然后開始寫metedata
. 通過ObjectMeta
可以看到里面有很多屬性,例如annotations
表示一些注釋信息,類型是obejct
,通過后面的鏈接: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ 可以得知是一個key=value
格式的map。 如果要添加注釋信息,可以按照如下方式編寫:
apiVersion: apps/v1beta2
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
在創建任何資源時,name和namesapce都是需要指定的(namespace如果不指定,默認是default,但指定namespace是一個好習慣)。查看name和namespace的定義:
都是字符串格式,因此在上面基礎之上在添加name和namespace:
apiVersion: apps/v1beta2
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
name: envoy-01
namespace: tio
在某些場景中(其實是大多數場景),需要通過label來篩選對應的workload,所以有必要給我的Deployment添加特定的Label, 查看一下Label的定義:
查看后面的鏈接 (https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/) 可以看出也是一個key=value
格式的map,和annotations
一樣,所以添加label如下:
apiVersion: apps/v1beta2
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
labels:
k8s-app: envoy-01
name: envoy-01
namespace: tio
metadata
的定義就先看到這里,下面來看spec
應該如何定義。
同樣,直接點擊deployment
spec下面的類型定義,
每個資源的spec都不同,下面是DeploymentSpec的定義:
每個屬性都有解釋,這里就不逐一翻譯了, 我們假設這個Deployment預期兩個Pod,因此replicas=2,通過selector來匹配ReplicaSet,設定strategy為滾動更新。 在上面資源文件的基礎之上,我們繼續定義spec,如下:
apiVersion: apps/v1beta2
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
labels:
k8s-app: envoy-01
name: envoy-01
namespace: tio
spec:
replicas: 1
selector:
matchLabels:
k8s-app: envoy-01
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
selector
可以參考(https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#labelselector-v1-meta)規定的規范, strategy
可以參看(https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#deploymentstrategy-v1-apps)。
這些定義完成后,就剩下Template
了,這個用來定義應該如何來創建Pod(或者說表示用戶想要一個什么樣的Pod)。
點擊下面的Pod數據定義:
可以看到Pod Template有兩個屬性:
因此資源文件大致應該是如下的樣子:
apiVersion: apps/v1beta2
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
labels:
k8s-app: envoy-01
name: envoy-01
namespace: tio
spec:
replicas: 1
selector:
matchLabels:
k8s-app: envoy-01
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
spec:
metadata
和spec
. 其中metadata
和上面我們所設置的metadata
一樣,這里就不贅述了。spec
通過下面的定義可以得知是podspec
。
點擊podspec
后可以看到和經常設置的docker container參數有一些類似了:
我們繼續在上面資源文件基礎上補充podspec
的內容
apiVersion: apps/v1beta2
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
labels:
k8s-app: envoy-01
name: envoy-01
namespace: tio
spec:
replicas: 1
selector:
matchLabels:
k8s-app: envoy-01
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
k8s-app: envoy-01
spec:
containers:
- args:
- -c
- /etc/envoy/envoy.yaml
- --service-node
- sn1
- --service-cluster
- sc1
command:
- envoy
image: envoyproxy/envoy
imagePullPolicy: IfNotPresent
name: envoy
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
securityContext:
privileged: false
procMount: Default
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /etc/envoy
name: conf
至此,一個最簡單的Deployment
資源文件就寫好了。 剩下的就是通過kubectl
提交這個需求給Kubernetes集群,然后就可以等待Kubernetes慢慢創建資源了。