2019年1月31日星期四

了解及編寫 Kubernetes 的 yaml

上一回【申請 Google Cloud Platform ( GCP ) 及示範 Kubernetes Engine


Docker 有 yaml,K8s 也有 yaml,兩者都是 yaml,為甚麼完全不同呢?這個就不深究了,但兩者的 yaml 不能共用,已經確認過,所以有必要了解 K8s 是怎樣用 yaml 檔,Docker 那邊忘掉吧。

Kubernetes Object 及 Kubernetes API 不需要太深入研究,稍微知道是甚麼就夠,實戰才是本文重點。

為求方便,這篇用 Google Cloud Shell ( GCS ),不用 Google Cloud SDK 版本,因為 kubectl 之前給 Docker for CE 佔用了,把設定改回來很麻煩,之後的文章,應該會改回用本機 Shell。

Google Cloud 快速入門
https://cloud.google.com/kubernetes-engine/docs/quickstart#choosing_a_shell

yaml 語法
https://javatoybox.blogspot.com/2019/01/kubernetes-yaml.html#try-docker-compose


———————————簡易的分隔線————————————

Kubernetes Object︰



結構圖所示,kubectl 跟 API Server 溝通,怎溝通呢?kubectl 建立 API request ( JSON ) 與 API API Server 溝通,然後生成【Kubernetes Object】。

那麼……用甚麼轉成 JSON 格式呢?那就是 yaml,yaml 可以轉換成 JSON,但 API Server 也是有要求的,在 request 中,一定要包含 apiVersion、kind 及 metadata 三種資料。

上圖嚴格來說並不正確,因為使用 Google Cloud Shell,等於透過 browser 把 command 送過去 Google 那邊的 kubectl 執行,不過算了吧,要做的事情還是一樣 ( kubectl --> API Server --> Kubernetes Object )。

Describing a Kubernetes Object
https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/#describing-a-kubernetes-object

What is the difference between YAML and JSON? When to prefer one over the other
https://stackoverflow.com/questions/1726802/what-is-the-difference-between-yaml-and-json-when-to-prefer-one-over-the-other

———————————簡易的分隔線————————————

Kubernetes API︰



現在應該知道,為甚麼每個 K8s 的 yaml 都會有 apiVersion 及 kind 作為開頭,但他們的關係是甚麼?

在 Cloud Shell 輸入 command︰

  • kubectl version

會有 major 及 minor 等資訊,這代表現在 kubectl client 及 server 版本,這決定 yaml 可以用甚麼 apiVersion,例如以下官方例子,有註解說如何修改 apiVersion 參數,對應不同版本的 kubectl。

https://kubernetes.io/docs/tasks/run-application/run-stateless-application-deployment/#creating-and-exploring-an-nginx-deployment

Kube <major>.<minor>.<patch>
https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/design/versioning.md

Kubernetes API reference
https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.13/#pod-v1-core

———————————簡易的分隔線————————————

Container Registry︰


除了 apiVersion、kind 及 metadata 三種資料,而最重要的 image 從何而來?公開 image,從 Docker hub 來,而 private registry,需另外設定,這裡不會詳述,本人鼓勵 Open Source,怎會教人把東西收起來,要學就看官網。

Use Cases
https://kubernetes.io/docs/concepts/containers/images/#use-cases

Quickstart for Container Registry
https://cloud.google.com/container-registry/docs/quickstart

Private registry
https://kubernetes.io/docs/concepts/containers/images/#configuring-nodes-to-authenticate-to-a-private-registry

———————————簡易的分隔線————————————

YAML︰


稍微了解過 Kubernetes Object、Kubernetes API 及 Container Registry,現在到編寫 yaml。


Pod︰


從最基本玩起,首先來個 derby 試一試。


第一行【---】是 Document header,第二到第四行是必要項目。

  • apiVersion︰在 Kubernetes API 一節介紹過。
  • kind︰對應 apiVersion,定義這個 yaml 檔建立甚麼 Object,例如 Pod、Deployment、Ingress 等等。
  • metadata︰給這個 Object 附加資訊。


spec︰specification 簡寫,詳細定義要這 Object 做甚麼。


image︰如果沒特別設定,預設在 Docker Hub 下載 image,可以去 Docker Hub 看看有沒有公開 dockerfile ,有公開的話,最好看一看內容,例如入面有沒有設定  volume,有沒有 CMD 等等。跟據上面  yaml 第九行,在瀏覽器上開啟 https://hub.docker.com/r/integrityknight/derby 應該會去到 Repo 主頁,查一下有沒有重要資訊。

lifecycle︰其實只要第六到第九行就可以,這個定義建立 container 前後,要做甚麼動作,以 database 為例,關閉前應該要 disconnect,這樣才不會有之前的 lock 問題,不過今次沒用 Persistent volumes,重新建立 Pod 時就會還原,所以沒所謂吧?

YAML 1.1 Reference card
https://yaml.org/refcard.html

Pod Templates
https://kubernetes.io/docs/concepts/workloads/pods/pod-overview/#pod-templates

Deployments︰


現在改造 Pod 成 Deployment,用 Deployment 有甚麼好處?

Replication︰


假如有個 Pod 突然死了,會有其他 Pod 會承接,做到無間斷服務,算做 fault tolerance 的一環。

Rolling Update / Rolling Back︰


承上,不需要關掉伺服器做升級或更新服務 ( Zero downtime ),例如有三個相同的 Pod,A Pod 是舊服務,B 及 C Pod 是升級後服務,只要更新完之後,把 A Pod 弄死, B、C Pod 會自動承接要求,繼續提供服務。

Deployment
https://kubernetes.io/docs/concepts/workloads/controllers/deployment/

———————————簡易的分隔線————————————

改造 Pod 成 Deployment︰



紅框是修改後結果,要把 kind 改成 Deployment,先要改 apiVersion 成 apps/v1,而 labels 給這個 deployment 一個名稱。


replicas︰定義用兩個 Pod 做 Replication。
selector︰重點來了,入面有一個叫 matchLabels 項目,這個設定一定要跟 template 內 labels 一致才會生效!
template︰把之前 Pod 的 spec 都搬進去,再加點 metadata。記謹!yaml 必須層次分明及只能用空白鍵,不能用 Tab,所以抄的時候不要忘記對齊位置。

———————————簡易的分隔線————————————

上傳 yaml 到 GCP︰



開啟 GCS 上傳 yaml 檔案。


檔案在 userhome,打 ls -a 可看到。

———————————簡易的分隔線————————————

使用 YAML 建立 Pod / Deployment︰


之前講解過 yaml 內寫了甚麼,是時候驗證一下是否正確,首先用 pod-demo.yaml 做示範。


上傳完檔案後,使用 yaml 在 GCS 建立 Pods,command 如下︰
  • kubectl create -f pod-demo.yaml
看看 pod 是否成功建立︰
  • kubectl get pod k8s-derby-demo
進入 pod 內操作。
  • kubectl exec -it k8s-derby-demo /bin/sh

——————————— ( 補充 start ) ————————————

操作 Derby ︰



以前文章有介紹過 Derby,可看參考 連結 回顧。

以 Derby 內建 ij 測試︰
  • java org.apache.derby.tools.ij
  • connect 'jdbc:derby://localhost:1527/FirstDB';
  • SELECT id, actor, product FROM acg_character.profile;
  • disconnect;
  • exit;
——————————— ( 補充 end ) ————————————

測試 Deployment ︰



Pod 有的東西,deployment 也有,主要測試 Replication 及 Rolling Update / Rolling Back 是否如之前所說那麼神奇。首先,以上傳的 yaml 做 deployment,謹記加 --record,這個會記錄到 rollout history 中,對 Roll back 有幫助,追溯之前做過甚麼︰
  • kubectl create -f deployment-demo.yaml --record
然後看 Pods 是否成功建立︰
  • kubectl get pods

Replication︰


假設,在 Database 加一筆資料後,兩邊 Pod 應該會同步更新。故意弄死一隻 Pod,看看會否同步。


在其中一隻 pod 加一筆資料︰

  • kubectl exec -it k8s-deployderby-demo-6bc844ccbb-gwvhf /bin/sh
  • java org.apache.derby.tools.ij
  • connect 'jdbc:derby://localhost:1527/FirstDB';
  • SELECT id, actor, product FROM acg_character.profile;
  • INSERT INTO acg_character.profile (actor, product) VALUES ('Leon', 'resident evil');
  • SELECT id, actor, product FROM acg_character.profile;



弄死剛剛那隻 pod

  • kubectl delete pods k8s-deployderby-demo-6bc844ccbb-gwvhf

進入另一隻 pod 查看結果

  • kubectl exec -it k8s-deployderby-demo-6bc844ccbb-bszvm /bin/sh
  • java org.apache.derby.tools.ij
  • connect 'jdbc:derby://localhost:1527/FirstDB';
  • SELECT id, actor, product FROM acg_character.profile;

對不起,沒有更新,這個假設是錯誤,需要把資料及資料庫程式分開, Pod 只提供服務所以只裝資料庫程式,資料要放 Persistent Volumes,通過 Pod 讀寫資料。


再看一次現在 pods,發現會自動再生一個 pod 補上空缺。

  • kubectl get pods

——————————— ( 補充 start ) ————————————

Deployment 及 StatefulSets


簡單點說,Deployment 用來處理 stateless 應用,StatefulSets 用來處理 Database 讀寫。例如開放給公眾查詢資料,只用到讀取,可以用 Deployment 做,而公司職員需要輸入資料,用到寫入,這時候該用 StatefulSets 建立 Pod。

StatefulSets in GKE
https://cloud.google.com/kubernetes-engine/docs/concepts/statefulset

——————————— ( 補充 end ) ————————————

Rolling Update / Rolling Back︰


說起 Update 及 Roll back,其實在做甚麼?只是把 image 更新,要 update image 內容的話,需要重新寫過 dockerfile,上傳到 Docker Hub。

Rolling Update︰



command 詳細不說,請對比 yaml 檔。
  • kubectl set image deployment.v1.apps/k8s-deployderby-demo k8s-deployderby-demo-container=integrityknight/derby:v10.14.2.0 --record

Rollout history︰


如上圖,有 revision 號碼,這個數字可以用在 Rolling back 上,順帶一提,預設記錄數是十個。
  • kubectl rollout history deployment.apps/k8s-deployderby-demo

Rolling Back︰



不多說,看圖。
  • kubectl rollout undo deployment.apps/k8s-deployderby-demo --to-revision=1

Updating a Deployment
https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#updating-a-deployment

Rolling Back a Deployment
https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#rolling-back-a-deployment

———————————簡易的分隔線————————————

總結︰


再來個 Persistent Volumes 完成 k8s 系例文章。

下一回【Volumes、Persistent Volumes 及 Persistent Volumes Claims

沒有留言:

發佈留言

設有留言驗證及審查,檢閱後,才會顯示留言。
本人惰性很高,留言或許會石沉大海。