Microservice & Kubernetes
31 May 2022
Microservice
一個複雜的系統會有很多的功能(例如網站會有商品查詢、付款、購物車、儲值等等功能),如果採用monolith的方法,所有程式碼、feature寫在同個program裡會導致一些問題:
- 所有service要用同種程式語言寫(當然有辦法可以解決,但產生問題很難debug, dependency也很高)
- code dependency極高,如果彼此要共用某些config或者util function,一改動很容易影響到其他service的運行,或者不同service需要使用不同版本的套件,那也會很麻煩
- scalability低,所有service都寫在同個program, 程式會變超級大, CI/CD會變得超級麻煩,更新一個feature要導致整份code重新測試編譯(debatable, 本來大更新就應該要有整體的integration test跟全部重編檢測,但或許可能一些測試上不用整套系統重編,但monolith的狀況就是要全部重編重測)
- 一個service的crash可能帶動其他service出問題或crash
Microservice就是根據business feature把service拆成不同的code、程式,彼此是要能夠獨立運作跟自己成一個service的,microservice間在透過API calls, message broker或者k8s的系統進行溝通,這樣的好處
Microservice缺點
- 因為把整個大程式變成跟多isolated,independent的程式,因此比起大程式執行,可能microservice後會有一些溝通上的bug, 例如某個service沒開啟結果導致另一個service的unexpected error,或者一些溝通延遲導致的問題。
- 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
- High availability(low downtime)
- scalability(high performance)
- 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互動