###### tags: `LSA` `k8s` `study group`
# Chapter 4: Introducing the Kubernetes API objects
[TOC]
## 這章節包括的範圍
- 管理 k8s cluster 和 經由 k8s api 部屬在這個 cluster 的 application
- K8s API object
- 取得/理解 k8s object's YAML or JSON manifest
- 藉由 Node Object 查看 cluster 的健康程度 status
- 藉由 Event Object 查看 cluster 的 events
## 前情提要
上一章我們使用了 3 個 object
- deployment object
- 生成 3 個 pod object
- pod object
- 代表獨立的 instance(application)
- service object
- deploy a load balencer to expose the whole the application
## What is k8s API
### k8s API architecture
- HTTP-base [RESTful(Representational **State** Transfer)](https://zh.wikipedia.org/wiki/%E8%A1%A8%E7%8E%B0%E5%B1%82%E7%8A%B6%E6%80%81%E8%BD%AC%E6%8D%A2) API
- API 的 state 代表 resources 的集合,可以根據不同的 HTTP method 對特定的 resource 進行(Create, Read, Update, Delete)
- Create: `POST`
- Read: `GET`
- Update: `PUT` / `PATCH`
- Delete: `DELETE`
:::info
k8s 的管理和部屬到 cluster 都是基於利用 RESTful API 對 Object 進行操作 or 設定

:::
### difference between resources and objects
k8s 社群常常混用 resource 和 object,在正常情形下是可以混用的,但兩者有些微的不一樣
#### 最重要的差別
- resources: **在 k8s API 中一定會有 URI 代表**
- 指的不是硬體的 resources(cpu, ram...),而是指我們 or k8s control plane 獲得 k8s 當前 cluster 狀況的入口
- 這裡會有 `apiVersion` 和 `kind` 來讓我們知道 k8s 應該去哪個 API 找這些資料
- example
- `http://localhost:8001/api/v1/namespaces/default/events`
- `kubectl get events -o yaml -v=6`
```yaml=
I0122 20:24:13.622715 1093334 loader.go:372] Config loaded from file: /home/efficacy38/.kube/config
I0122 20:24:13.623436 1093334 cert_rotation.go:137] Starting client certificate rotation controller
I0122 20:24:13.635556 1093334 round_trippers.go:553] GET https://192.168.49.2:8443/api/v1/namespaces/default/events?limit=500 200 OK in 8 milliseconds
kind: List
apiVersion: v1
items:
- action: Binding
apiVersion: v1
eventTime: "2022-01-19T07:37:35.593578Z"
firstTimestamp: null
involvedObject:
apiVersion: v1
kind: Pod
name: kiada-8744d76c8-lsczc
[...]
```
> Note that kubectl and other tools sometimes output collections of resources as **`kind: List`**. Keep in mind that **`kind: List`** is **not part of the Kubernetes API**; it is exposing an implementation detail from **client-side code in those tools**, used to handle groups of **mixed resources**.
> [k8s List and eventList, and other List](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#types-kinds)
> - `kubectl get events -o yaml -v=6`
> - `v=6`: Display requested resources.
> - `v=7`: Display HTTP request headers.
> - `v=8`: Display HTTP request contents.
> - `v=9`: Display HTTP request contents without truncation of contents.
> - [verbose level](https://kubernetes.io/docs/reference/kubectl/cheatsheet/#kubectl-output-verbosity-and-debugging)
> [name=Jerry]
- object: **不一定會有 URI 代表**
- 存儲著所有的 k8s 的 cluster 狀態的最小單位
- 不一定可以直接觀察到,部份要藉由 resources 觀察
- example
- event object 不能直接被觀察,但可以從 resources 觀察到
:::info
what is URL, URN, URI
- URL 著重強調 "如何取得" 資料的方式 可能是 network location(http, ftp...)
- `https://www.manning.com/books/Kubernetes-in-action-second-edition` 代表我可以從這個 URL "得到" content-type, encoding, `Kubernetes in Action, Second Edition` 這本書的方式...
- Uniform Resource Name(URN) 著重在一個 namespace 下的資源,不需要取得的方法
- k8s in action 2ed 的 URN 是 urn:isbn:9781617297618
- URI 是以 string 表示虛擬 or 實體的資源
- URN 和 URL 都是 URI 的 subset
- 可以說 k8s in action 2ed 這本書的 uri 是 `https://www.manning.com/books/Kubernetes-in-action-second-edition` 和 `urn:isbn:9781617297618`
[man page(uri)](https://linux.die.net/man/7/uri)
[w3c uri classification](https://www.w3.org/TR/uri-clarification/#uri-partitioning)
difference between resource and object
[specification of `resource` and `object`](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#resources)
:::
#### 例子

- 圖的 resource 顏色代表意義
- 紫色: 不包含 object
- 黃色: 新版本的 resources
- 綠色: 舊版本的 resources
- resources 的一些特性
- 一個 object 可以同時被好幾個 resources expose 出來
- 像是 query `deployments` 時 mydeploy 作為一個集合中的一個 object 回傳
- or query `deployments/mydeploy` 作為一個 object 回傳
- 一個 object 同樣可以被不同版本的 resources expose 出來
- 新版本的 v1 `/apis/apps/v1/deployments`
- 舊版本的 v1beta1 `/apis/extensions/v1beta1/deployments`
- 兩者可以回傳同樣的 object ,不代表 v1 和 v1beta 是不同的 deployment 集合而只是表達的方式不同
- 有時候一個 resources 不包含 object
- 我們可以透過 `/apis/authorization.k8s.io/v1/subjectaccessreviews` 確認 deployment or user 是否具有權限查看 subject
:::info
以上的例子說明了 **"object"** 和 **"resource"** 不同之處,**但**在這本書為了避免誤會,使用 **"object"** 代表 **"resoruces"**
:::
## Understanding the structure of an object manifest
### main parts of an object
- Type Metadata
- object type
- `kubectl api-resources`: 當前有哪些 support object
- group to which the type belongs
- API version
- ...
- Object Metadata
- object instance name
- time of creation
- identifying information
- 這個 metadata 包含的欄位和其他 object 一樣,不管其他的 object type 是什麼
- Spec
- 我們對這個 object 的期望狀態
- 這裡包含的欄位因 object 種類而異
- if pods
- specifies the pod’s containers, storage volumes...
- Status
- 現在這個 object 的實際狀況
- if pods
- the condition of the pod, the status of each of its containers, its IP address, the node it’s running on...
### Example(user operate k8s object via k8s API)

- **write spec**:
user 提供 spec part of object 更新 object 的期望狀態
- **read state**:
user 讀 state part of object 得知 object 的實際狀況
:::info
圖上是 user 寫入 spec 讀 state,但現實情況是 `PUT` 整包資料(包含上述的 4 個部份),`GET` 也會拿到整包資料
:::
### what happened after we change the spec?
>The **Kubernetes Control Plane** runs several **components** called **controllers** that **manage the objects** you create.
Each controller is usually only **responsible for one object** type.
For example, the Deployment controller manages Deployment objects.
#### Controller 同樣利用 k8s API 獲取/更新 object 狀態

1. **read spec**:
controller 會不斷的透過 k8s API 觀察 spec,幫我們向 cluster 做出變更 cluster object 狀態的操作
2. **write state**:
變更後利用 k8s API 告知我們 state
- controller 做的事情
- object 當前狀態
:::info
- 剛剛討論集中在 spec/status ,但不是所有 object 都有 spec or status,why?
- 一些 object 只是 static 的資料,甚至沒有 controller,沒必要區分期望狀態 (spec) 和當前狀態 (status)
- 等等的 Event Object 就是這種類型
- 有什麼部份是 object 一定會有的?
- Type Metadata
- Object Metadata
:::
## Node Object’s individual properties
每個 node object 可以簡單的被想成我們安裝 k8s 的 host,並且可以透過 k8s API 查看每個 Node Object

- `kubectl get nodes`: 獲取 node list by k8s API
```csv
NAME STATUS ROLES AGE VERSION
minikube Ready control-plane,master 7d10h v1.22.3
minikube-m02 Ready <none> 2m1s v1.22.3
minikube-m03 Ready <none> 108s v1.22.3
minikube-m04 Ready <none> 92s v1.22.3
minikube-m05 Ready <none> 77s v1.22.3
```
- `kubectl get node <node-name> -o yaml`: 查看 Node Object 每個欄位在 k8s 內代表的意義
- Type Metadata:
- apiVersion:
- 當前架構 ( schema ) 版本
- 可能同時被多個版本的 API expose
- `v1`
- `v1beta`
- 原先目的是為了區分不同版本的 API,但後來也用來區分 API group
- deployment's apiversion: `app/v1`
- Node's apiversion: `v1`
- 因為屬於 core API group, 省略 API group
- kind
- object 類型
- `Node`
- `Deployment`
- `Service`
- ...
- Object Metadata:
- `name` of object
- `labels` and `annotations`
- will introduce at ch9
- `resourceVersion` and `managedFields`
- will introduce at ch12
- Spec section
- 就像的設定檔,在這通常有更多可以被當作設定的欄位
- `podCIDR`: pod IP range
- `taint`
- not important at this point, will introduce at ch18
- Staus section
- 就是當前的 Node 狀態
- node's ip address
- hostname
- capacity to provide compute resources
- current conditions of the node
- container images already install at this node
- OS
- ...
- **不用翻文件查看 field 定義的好指令**
- `kubectl explain nodes`
- `kubectl explain node.spec`
- `kubectl explain pods --recursive`: check 每個欄位的 data type
- `kubectl explain pods --api-version <api-version>`: check 不同版本的定義
### example using `condition` field in Node object's `status`
- `spec` 和 `status` 會根據 object `kind`(in object's `metadata`) 不同而有不同的欄位
- 為什麼使用 object 的 condition 來介紹 `status`?
- 在大部份的 object 都可以看到的欄位
- 提供當下 object 的狀況
- 有助於 **trouble shooting**
#### condition 欄位
- condition 有幾個欄位可以注意
- status:
- 只能是 `Ture`, `False` or `Unknown`
- type: object condition 的類別
- lastTransitionTime: 上次狀態改變的時間
- lastHeartbeatTime: controller 接收到更新的時間
#### 實際例子
- `kubectl get node kind-control-plane -o yaml` or
`kubectl get nodes minikube-m02 -o yaml | yq e .status.conditions -`
```yaml=
...
status:
...
conditions:
- lastHeartbeatTime: "2020-05-17T13:03:42Z"
lastTransitionTime: "2020-05-03T15:09:17Z"
message: kubelet has sufficient memory available
reason: KubeletHasSufficientMemory
status: "False"
type: MemoryPressure
- lastHeartbeatTime: "2020-05-17T13:03:42Z"
lastTransitionTime: "2020-05-03T15:09:17Z"
message: kubelet has no disk pressure
reason: KubeletHasNoDiskPressure
status: "False"
type: DiskPressure
- lastHeartbeatTime: "2020-05-17T13:03:42Z"
lastTransitionTime: "2020-05-03T15:09:17Z"
message: kubelet has sufficient PID available
reason: KubeletHasSufficientPID
status: "False"
type: PIDPressure
- lastHeartbeatTime: "2020-05-17T13:03:42Z"
lastTransitionTime: "2020-05-03T15:10:15Z"
message: kubelet is posting ready status
reason: KubeletReady
status: "True"
type: Ready
```
:::info
- yq: yaml 格式化工具
- `kubectl get node <name> -o yaml | yq e .spec.podCIDR -`
- `-` stand for read from STDIN
- jq: json 格式化工具
- `kubectl get node <name> -o json | jq .status.conditions`
:::

- condition 的意義
- `Ready`: 最重要的, Node 是否準備好了
- `MemoryPressure`: 這個 Node 是否記憶體不足
- `DiskPressure`: 這個 Node 是否硬碟硬碟不足
- `PIDPressure`: 這個 Node 是否 PID 不足
:::info
如果發現 Node 很奇怪的時候可以來這裡檢查一下
:::
### 查看其他的欄位
- `kubectl describe <resources>`
- 比起 `kubectl get <resources>` 提供更人性化的資料
- 提供一些不在 object 內的欄位資料, `kubectl` CLI 會幫忙收集資料
- 像是 events 的部份
## Observing cluster events via Event objects
當 controllor 想要根據 object 的 spec 協調 object 的狀態時,會在更新時產生 event object 儲存到 etcd 內

### Intro of event object
- event object 有幾個類別
- Normal
- Warning
- 有其他原因阻止 controller 變更 object 的狀態
- event object 會在創建後存到 etcd
- 預設會在 1 hr 後清除( configurable )
### listing event object
- event 不包括在與它關聯的一些 resources
- event 可能會在短時間產生一堆,放在關聯的 resources 的欄位就不是很合適
- but 可以透過 `kubectl describe <resource>` 來看到和某個 resource 相關的 event
- `kubectl get ev`: 取得當前的 events
- `kubectl get ev -o wide`: 查看所有 event 的欄位
- `kubectl get ev --field-selector type=Warning`: 查看 warning 的 event
- 如果沒輸出就代表現在還沒有出現 warning 的 event
:::info
因為 controllor 在**改變 object 狀態**時會產生 event object,所以 event object 在 **setting/debug** 時是非常重要的 object ,所以在探索新的 object 時,可以先注意 events 的含意,與此同時也可以比較清楚 **K8s 在 CLI 背後幫我們做了哪些事情**
:::
### events 的各種欄位
- Name: 這 event 的名字(`minikube-m02.16cbdeda94d70a6a`),在想透過 API 抓 event object 資料時很方便
- Type: `Normal` or `Warning`
- Reason: machine-facing description
- Source: 回報 event 的角色,通常是 controller
- Object: 這 event 的對象,通常不是 controller(e.g. node/xyz)
- Sub-object: 這 event 對象的擁有者(e.g. 在哪個 pod 的 container)
- Message: human faceing description
- First seen: 第一次發生這個 event 的時間
- Last seen: 最後一次發生 event 的時間
- Count: 發生的幾次
:::info
因為 `kubectl explain events`: 在 event object 內**沒有 spec 和 status**
所以 `kubectl get events minikube-m02.16cbdeda94d70a6a -o yaml` 會顯得雜亂無章,讓人討厭處理 yaml :cry: ~
:::
## summary
- k8s 提供 RESTful API 讓我們操作 cluster, API object 對應到整個構成 cluster 的元件(application, load balancers, nodes, storage volume, ...)
- object 可以同時被好幾個 resources 釋出
- k8s API object 是 YAML or JSON manifest
- 用 `POST` method 創建 object
- 用 `GET` method retrieve object status
- object 一定有 Type 和 Object Metadata, 大多都有 `spec` 和 `status`,有些 object 因為只含 static 資料, 所以沒有 `spec` 和 `status`
- 當 controllers 管理 object 時,會釋出 k8s event object,所有的 event 都可以經過 k8s API 取得,可以得知 cluster 被做了什麼事情
- `kubectl explain` 可以提供查看欄位定義的地方
- `kubectl describe <resources>` 會提供更多的資訊,有些甚至不在這個 resouces 的 object 內
- `kubectl describe nodes <nodename>`: 會看到 events object 的資訊
- 很多 object 利用 condition 描述 object 當前情況, condition 內的 status 只能是 `True`, `False`, `Unknown` 代表 condition 狀態,`reason` 和 `message` 提供 condition 定義
- node's condition
- `MemoryPressure`
- `DiskPressure`
- `PIDPressure`