Microservice & Kubernetes

31 May 2022

Microservice

一個複雜的系統會有很多的功能(例如網站會有商品查詢、付款、購物車、儲值等等功能),如果採用monolith的方法,所有程式碼、feature寫在同個program裡會導致一些問題:

  1. 所有service要用同種程式語言寫(當然有辦法可以解決,但產生問題很難debug, dependency也很高)
  2. code dependency極高,如果彼此要共用某些config或者util function,一改動很容易影響到其他service的運行,或者不同service需要使用不同版本的套件,那也會很麻煩
  3. scalability低,所有service都寫在同個program, 程式會變超級大, CI/CD會變得超級麻煩,更新一個feature要導致整份code重新測試編譯(debatable, 本來大更新就應該要有整體的integration test跟全部重編檢測,但或許可能一些測試上不用整套系統重編,但monolith的狀況就是要全部重編重測)
  4. 一個service的crash可能帶動其他service出問題或crash

Microservice就是根據business feature把service拆成不同的code、程式,彼此是要能夠獨立運作跟自己成一個service的,microservice間在透過API calls, message broker或者k8s的系統進行溝通,這樣的好處

Microservice缺點

  1. 因為把整個大程式變成跟多isolated,independent的程式,因此比起大程式執行,可能microservice後會有一些溝通上的bug, 例如某個service沒開啟結果導致另一個service的unexpected error,或者一些溝通延遲導致的問題。
  2. service變多,需要做的整合,monitor的東西也變多,確保並偵測每個microservice獨立運作正常並且能夠整合,但這件事就會變得很複雜,要依賴其他工具來達成

Monorepo & Multirepo

Microservice的repo可以有兩種呈現方式

Monorepo就是所有code,各個service的程式碼都放在同個repo裡,使用資料夾來區分。這樣的好處就是更方便管理開發,要reuse code也想當方便(但也很容易導致tightly coupled),缺點是codebase就會變超大,clone之類的就會非常痛苦,而且CI/CD pipeline就不好寫,如果都在同個repo,做某個service的修改時要跑CI/CD就要用各種條件式來判斷要怎麼跑,然後一樣的問題,一個錯誤的改動會導致整個service crash。

Multirepo就是每個service都是自己的repo,然後這些repo統合成一個project,這樣好處就是各個service可以跑自己的CI/CD, 缺點就是code要reuse就不太容易,update也會相較之下便困難,因為如果動到複數個services那就要到各個repo去做對應的修改,code search, debug, share file難度也比較高。

k8s

用來管理多個container的工具,在microservice多的狀況下 會需要有工具來監測控管各個microservice。

k8s可以確保microservice

  1. High availability(low downtime)
  2. scalability(high performance)
  3. Recovery(backup and restore)

Architecture

一個Master Node掌控所有的microservice, 然後會有數個worker node, worker node裡面會至少有三個process, container runtime, kublets, 跟kube proxy(forward request給指定的pods),各個worker node就是負責跑microservice, 一個worker node可以跑一個或多個container。

Master node裡有一個API server(包成container,是k8s cluster的entry,接受user的指令,包含API calls, CLI, UI的request), 一個control manager統整所有worker node的status,scheduler根據workloads跟狀況決定哪個worker nodes的哪個container要執行,在pod掛掉重啟時,也是由scheduler決定要在哪個worker node重啟pod,etcd存當下的各個container的status,k8s會對每個container不斷做snapshot結果存在etcd。 由此可知Master node極其重要,一但掛了整個k8s就沒人管理監控備份service,所以在production環境,會有複數個Master node。

pod: 使用者在k8s環境下跑起microservice的單位,一個container wrapper,通常一個pod代表一個microservice,一個worker node裡可以有多個pod,一個pod可以有多個container(但通常是一個,畢竟microservice就是一次做一件事)。pod負責manage container,所以開發者只要負責pod的部分,當 pod裡的container掛掉時,pod會自動restart container。當pod掛掉時,k8s會自動在產生一個pod, 然後新的pod就會有新的ip address。

Service是內建的永久的ip address可以attach到pod, 當pod掛掉重啟時,他的ip address可能會不同,但可以有相同的service, 所以只要specify service,就算pod重啟換了ip address,其他pod還是能透過這個service name來跟這個新建立的pod溝通,而不會因為重啟換了一個ip address找不到這個pod. 另外service也是一個load balancer, 因為可以有多個node跑同一個container的pod然後這些pods都指向這個service(基本上就是一個microservice跑好幾份,然後serice可以再做load balance的部分)

Ingress: 基本上是處理external service的部分,例如node裡有數個pod他是external service要有對外連線的部分,那Ingress就會是這個node裡負責forward request的物件,把外在的request forward到指定的pod來做request處理。

Configmap: k8s中,configure application的文件,原因是如果只是對application的名字、設定做更改就要每次重新build image重新跑起pod, container太不值得,所以對於單純這種名字url之類的設定改動,可以直接改configmap就把改變apply到應用程式中,就不用rebuild然後run container

secret: Config map雖然存config,但是是以明文方式儲存,非常不安全,secret則是base64的encode的config

virtual network是k8s建立的網路介面讓Master node跟worker node溝通, Master node通常資源消耗比較小,worker node資源分配會比較多(畢竟是要跑真的service workload)。Virtual network會給每個pod一個ip address,然後master node, pod就是利用這些virtual ip address溝通。但ip address本身很常換(例如pod掛掉後就要重啟就會有新的ip address),因此比起使用ip address溝通,k8s會使用sevice name來跟pod溝通

volume: 跟docker差不多的概念,就是attach一個永久的storage給container/pod,這樣pod對於資料的修改也會直接修改在hard disk中,當pod掛掉時資料就還會存在,也能把volume共享給其他pod。不同處是volume可以是local hard disk儲存也可以是remote storage service(畢竟k8s是一個distributed system)

deployment: pod的config, 決定每個pod要有幾個replicas

statefulset: 對於有些pod其實不能有replicas, 例如database因為資料要有consistency, 兩個db雖然能load balance但會導致資料同步出問題,statefulset的config就是針對這種有state的pod的config,所以要stateful pod replicas就要用statefuleset(但覺得麻煩也可以把db建於k8s之外自己做處理)

minikube & kubctl

一個open-source program用來做local testing/setup用,例如在production環境要架設好整套k8s系統會花一些時間(因為有複數個master nodes, worker nodes,要安裝一堆東西),如果只是要單純測試跑起簡易版的話就可以用minikube,minikube可以在一個node(local machine)上做完整套系統的測試,minikube會建立一個VM,VM內會跑master process跟worker process來做測試

kubectl是用來跟k8s溝通的工具,包括建立pods,service或刪除pods, kubectl會跟master process上的api server做互動。kubectl因為是跟api server做互動,所以他可以跟minikube的模擬環境互動外,也能夠跟真的production的cloud cluster互動