歡迎訪問我的GitHub
https://github.com/zq2599/blog_demos
內容:所有原創文章分類彙總及配套原始碼,涉及Java、Docker、Kubernetes、DevOPS等;
系列文章連結
- kubebuilder實戰之一:準備工作
- kubebuilder實戰之二:初次體驗kubebuilder
- kubebuilder實戰之三:基礎知識速覽
- kubebuilder實戰之四:operator需求說明和設計
- kubebuilder實戰之五:operator編碼
- kubebuilder實戰之六:構建部署執行
- kubebuilder實戰之七:webhook
- kubebuilder實戰之八:知識點小記
本篇概覽
- 作為《kubebuilder實戰》系列的第四篇,經歷了前面的充分準備,從本篇開始,我們們來開發一個有實際作用的operator,該operator名為elasticweb,既彈性web服務;
- 這將是一次完整的operator開發實戰,設計、編碼、部署等環節都會參與到,與《kubebuilder實戰之二:初次體驗kubebuilder》的不同之處在於,elasticweb從CRD設計再到controller功能都有明確的業務含義,能執行業務邏輯,而《kubebuilder實戰之二》僅僅是一次開發流程體驗;
- 為了做好這個operator,本篇不急於編碼,而是認真的做好設計工作,我們們的operator有什麼功能,解決了什麼問題,有哪些核心內容,都將在本篇整理清楚,有了這樣的準備,才能在下一章寫出符合要求的程式碼;
- 接下來我們們先聊一些背景知識,以便更好的進入正題;
需求背景
- QPS:Queries-per-second,既每秒查詢率,就是說伺服器在一秒的時間內處理了多少個請求;
- 背景:做過網站開發的同學對橫向擴容應該都瞭解,簡單的說,假設一個tomcat的QPS上限為500,如果外部訪問的QPS達到了600,為了保障整個網站服務質量,必須再啟動一個同樣的tomcat來共同分攤請求,如下圖所示(簡單起見,假設我們們的後臺服務是無狀態的,也就是說不依賴宿主機的IP、本地磁碟之類):
- 以上是橫向擴容常規做法,在kubernetes環境,如果外部請求超過了單個pod的處理極限,我們可以增加pod數量來達到橫向擴容的目的,如下圖:
- 以上就是背景資訊,接下來我們們聊聊elasticweb這個operator的具體功能;
需求說明
- 為了說清楚需求,這裡虛構一個場景:小欣是個java開發者,就是下圖這個妹子:
- 現在小欣要將springboot應用部署到kubernetes上,她的現狀和麵臨的問題如下:
- springboot應用已做成docker映象;
- 通過壓測得出單個pod的QPS為500;
- 估算得出上線後的總QPS會在800左右;
- 隨著運營策略變化,QPS還會有調整;
- 總的來說,小欣手裡只有三個資料:docker映象、單個pod的QPS、總QPS,她對kubernetes不瞭解,需要有個方案來幫她將服務部署好,並且在執行期間能支撐外部的高併發訪問;
以上就是小欣的需求了,我們們來小結一下:
- 我們們為小欣開發一個operator(名為elasticweb),對小欣來說,她只要將手裡的三個引數(docker映象、單個pod的QPS、總QPS)告訴elasticweb就完事兒了;
- elasticweb在kubernetes建立pod,至於pod數量當然是自動算出來的,要確保能滿足QPS要求,以前面的情況為例,需要兩個pod才能滿足800的QPS;
- 單個pod的QPS和總QPS都隨時可能變化,一旦有變,elasticweb也要自動調整pod數量,以確保服務質量;
- 為了確保服務可以被外部呼叫,我們們再順便幫小欣建立好service(她對kubernetes瞭解不多,這事兒我們們就順手做了吧);
自保宣告
-
看過上述需求後,聰明的您一定會對我投來鄙視的眼光,其實kubernetes早就有現成的QPS調節方案了,例如修改deployment的副本數、單個pod縱向擴容、autoscale等都可以,本次使用operator來實現僅僅是為了展示operator的開發過程,並不是說自定義operator是唯一的解決方案;
-
所以,如果您覺得我這種用operator實現擴容的方式很low,請不要把我罵得太慘,我這也只是為了展示operator開發過程而已,況且我們這個operator也不是一無是處,用了這個operator,您就不用關注pod數量了,只要聚焦單例項QPS和總QPS即可,這兩個引數更貼近業務;
-
為了不把事情弄複雜,假設每個pod所需的CPU和記憶體是固定的,直接在operator程式碼中寫死,其實您也可以自己改程式碼,改成可以在外部配置,就像映象名稱引數那樣;
-
把需求都交代清楚了,接下來進入設計環節,先把CRD設計出來,這可是核心的資料結構;
CRD設計之Spec部分
Spec是用來儲存使用者的期望值的,也就是小欣手裡的三個引數(docker映象、單個pod的QPS、總QPS),再加上埠號:
- image:業務服務對應的映象
- port:service佔用的宿主機埠,外部請求通過此埠訪問pod的服務
- singlePodQPS:單個pod的QPS上限
- totalQPS:當前整個業務的總QPS
- 對小欣來說,輸入這四個引數就完事兒了;
CRD設計之Status部分
- Status用來儲存實際值,這裡設計成只有一個欄位realQPS,表示當前整個operator實際能支援的QPS,這樣無論何時,只要小欣用kubectl describe命令就能知道當前系統實際上能支援多少QPS;
CRD原始碼
- 把資料結構說明白的最好方法就是看程式碼:
package v1
import (
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"strconv"
)
// 期望狀態
type ElasticWebSpec struct {
// 業務服務對應的映象,包括名稱:tag
Image string `json:"image"`
// service佔用的宿主機埠,外部請求通過此埠訪問pod的服務
Port *int32 `json:"port"`
// 單個pod的QPS上限
SinglePodQPS *int32 `json:"singlePodQPS"`
// 當前整個業務的總QPS
TotalQPS *int32 `json:"totalQPS"`
}
// 實際狀態,該資料結構中的值都是業務程式碼計算出來的
type ElasticWebStatus struct {
// 當前kubernetes中實際支援的總QPS
RealQPS *int32 `json:"realQPS"`
}
// +kubebuilder:object:root=true
// ElasticWeb is the Schema for the elasticwebs API
type ElasticWeb struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec ElasticWebSpec `json:"spec,omitempty"`
Status ElasticWebStatus `json:"status,omitempty"`
}
func (in *ElasticWeb) String() string {
var realQPS string
if nil == in.Status.RealQPS {
realQPS = "nil"
} else {
realQPS = strconv.Itoa(int(*(in.Status.RealQPS)))
}
return fmt.Sprintf("Image [%s], Port [%d], SinglePodQPS [%d], TotalQPS [%d], RealQPS [%s]",
in.Spec.Image,
*(in.Spec.Port),
*(in.Spec.SinglePodQPS),
*(in.Spec.TotalQPS),
realQPS)
}
// +kubebuilder:object:root=true
// ElasticWebList contains a list of ElasticWeb
type ElasticWebList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []ElasticWeb `json:"items"`
}
func init() {
SchemeBuilder.Register(&ElasticWeb{}, &ElasticWebList{})
}
業務邏輯設計
-
CRD的完成代表核心資料結構已經確定,接下來是業務邏輯的設計,主要是理清楚controller的Reconcile方法裡面做些啥,其實核心邏輯還是非常簡單的:算出需要多少個pod,然後通過更新deployment讓pod數量達到要求,在此核心的基礎上再把建立deployment和service、更新status這些瑣碎的事情做好,就完事兒了;
-
這裡將整個業務邏輯的流程圖給出來如下所示,用於指導開發:
- 至此,我們們完成了整個elasticweb的需求和設計,聰明的您肯定已經胸有成竹,而且迫不及待的想啟動開發了,好的,下一篇我們們正式開始編碼!
參考資料
- 您可能會奇怪,小欣對kubernetes不瞭解,怎麼會知道docker映象的製作,還有單個pod的QPS她是怎麼測的呢?
- 其實她是程式設計師欣宸的粉絲,已經閱讀過以下部落格:
- 《SpringBoot-2.3映象方案為什麼要做多個layer》
- 《體驗SpringBoot(2.3)應用製作Docker映象(官方方案)》
- 《詳解SpringBoot(2.3)應用製作Docker映象(官方方案)》
- 《Kubernetes下web服務的效能測試三部曲之一:準備工作》
- 《Kubernetes下web服務的效能測試三部曲之二:縱向擴容》
- 《Kubernetes下web服務的效能測試三部曲之三:橫向擴容》
你不孤單,欣宸原創一路相伴
歡迎關注公眾號:程式設計師欣宸
微信搜尋「程式設計師欣宸」,我是欣宸,期待與您一同暢遊Java世界...
https://github.com/zq2599/blog_demos