首先,關于k8s的調度機制,可以看我上一篇文章:
而這一篇文章探討的內容,就是關于k8s 調度器的不足之處的。我們知道,對于內存memory,cpu的劃分,k8s已經做得很不錯了,但如果要追求更多,更細致的劃分,就需要自己動手寫scheduler。
而scheduler調度是需要信息的。我們這一次準備搞一個能顯示我們想要的信息的daemon,給自己寫的scheduler使用。
由于k8s的底層接口全部都是go編寫的,我們也必須用go來寫這個daemon,這就不得不學習一下需要的相關的依賴
在Go 1.11之后,Go 大力推動Go Modules,關于這個的討論非常多,也非常激烈,在go項目中如何使用Go Modules也是需要了解的。
Cron
https://godoc.org/github.com/robfig/cron
import? "github.com/robfig/cron"
Cron是一個相當優秀的處理定時任務的工具,我們如果說要定時采集Pod的數據,可少不了它。
c := cron.New()
c.AddFunc("30 * * * *", func() { fmt.Println("Every hour on the half hour") })
c.AddFunc("30 3-6,20-23 * * *", func() { fmt.Println(".. in the range 3-6am, 8-11pm") })
c.AddFunc("CRON_TZ=Asia/Tokyo 30 04 * * *", func() { fmt.Println("Runs at 04:30 Tokyo time every day") })
c.AddFunc("@hourly",? ? ? func() { fmt.Println("Every hour, starting an hour from now") })
c.AddFunc("@every 1h30m", func() { fmt.Println("Every hour thirty, starting an hour thirty from now") })
c.Start()
這里的符號特別有意思:
Field name | Mandatory? | Allowed values | Allowed special characters
----------? | ---------- | --------------? | --------------------------
Minutes? ? ? | Yes? ? ? ? | 0-59? ? ? ? ? ? | * / , -
Hours? ? ? ? | Yes? ? ? ? | 0-23? ? ? ? ? ? | * / , -
Day of month | Yes? ? ? ? | 1-31? ? ? ? ? ? | * / , - ?
Month? ? ? ? | Yes? ? ? ? | 1-12 or JAN-DEC | * / , -
Day of week? | Yes? ? ? ? | 0-6 or SUN-SAT? | * / , - ?
下面是官方的解釋:
Asterisk ( * )
The asterisk indicates that the cron expression will match for all values of the
field; e.g., using an asterisk in the 5th field (month) would indicate every
month.
Slash ( / )
Slashes are used to describe increments of ranges. For example 3-59/15 in the
1st field (minutes) would indicate the 3rd minute of the hour and every 15
minutes thereafter. The form "*\/..." is equivalent to the form "first-last/...",
that is, an increment over the largest possible range of the field.? The form
"N/..." is accepted as meaning "N-MAX/...", that is, starting at N, use the
increment until the end of that specific range.? It does not wrap around.
Comma ( , )
Commas are used to separate items of a list. For example, using "MON,WED,FRI" in
the 5th field (day of week) would mean Mondays, Wednesdays and Fridays.
Hyphen ( - )
Hyphens are used to define ranges. For example, 9-17 would indicate every
hour between 9am and 5pm inclusive.
Question mark ( ? )
Question mark may be used instead of '*' for leaving either day-of-month or
day-of-week blank
也可以參考下文
http://www.lxweimin.com/p/fd3dda663953
https://www.cnblogs.com/jiangz222/p/12345566.html
Zap
https://github.com/uber-go/zap
import "go.uber.org/zap"
Zap是一個高性能日志庫,擁有非常多優秀的特性,參考
https://www.liwenzhou.com/posts/Go/zap/
Nvml
nvml是nvidia基于自家NVIDIA System Management Interface (nvidia-smi)的獲取顯卡信息的接口,支持go語言
具體參考
https://github.com/NVIDIA/gpu-monitoring-tools/blob/master/bindings/go/samples/nvml/deviceInfo/main.go
Client-go
client-go提供了容器內應用獲取pod信息的途徑。
https://github.com/kubernetes/client-go
例子
https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration
有了前面這些技術鋪墊,我們就可以著手開始寫我們自己的gpu scheduler了
具體代碼可以看這里:
https://github.com/hyc3z/Omaticaya
核心思想:
利用Cron創建一個輪詢任務,每隔一段時間輪詢,更新緩存中的gpu信息,然后轉換成node tag標注在node上。轉換/標注這一塊速度很快,大約10ms就能完成。但輪詢因為nvml的關系,少則100ms,多則500ms不等。實時性相對還較弱。
初步實現:cron+nvml采集信息+zap實時日志+k8s client-go更新tag
后續計劃:Dcgm+prometheus+influxdb存儲信息,glusterfs持久化
初步實現最初的思想,這里還發現了一個坑:
vgo/Go modules
筆者這里也查閱了很多vgo相關的信息,發現go的包管理也是走了不少的彎路。今天,vgo是Russ Cox親手扶上寶座的Go包管理,但它真的好用嗎?
首先,第一個問題,就是包名和源名必須相同。也就是,如果你的包是發布在github.com/username/packagename下的,你在本地的module名必須也得是github.com/username/xxx。這對于github的用戶還相對友好,對于gitlab、其他平臺的用戶,真的相當蛋疼。
第二個問題,包版本依賴。筆者在調用k8s.io/client-go時,發現k8s接口對不上,原來在k8s上最新的tag是kubernetes-1.18.0 而go.mod居然只允許v開頭的版本號(v1.0.0等),輸入這種tag直接報錯。真的蛋疼死了……后面直接cmd輸命令,找依賴,找關系,感覺本來應該vgo干的事現在全讓程序員擦屁股。
第三個問題,本地模組的導入。在vgo中,由于不支持GOPATH,導入本地模組也必須是使用項目托管上的絕對路徑。
筆者作為一個學習golang的新人,沒有用過Go dep/vendor,聽說是另一個社區版本的包管理,但vgo究竟怎樣,見仁見智吧。
Docker build
在運行完go build . 之后,我們需要使用docker build -t <tagname> 進行鏡像的制作,這里需要編寫Dockerfile文件
FROM nvidia/cuda:10.1-base
WORKDIR /
COPY Omaticaya /usr/local/bin
CMD ["Omaticaya"]
然后docker push 把鏡像上傳,供k8s使用。
目前這個版本已經可以運行,并采集gpu相關信息,但性能還有待優化。