本文根據OPPO雲平臺高級後端工程師蔡逸煌在DBAplus的線上分享整理而成,主要講述OPPO雲平臺存儲容器化的實踐。關於做者:蔡逸煌,OPPO雲平臺高級後端工程師,主要從事雲平臺開發工做,擅長K8S、容器網絡、存儲等領域。node
今天分享的主題是OPPO雲存儲的上雲之路。docker
存儲相比於其餘組件,更底層,因此有必要作一個簡單的科普。後端
主要是對整個文件進行操做,提供了對整個文件進行增刪查改的能力。不支持對對象內容進行增量修改,如七牛的對象存儲,AWS S3,阿里OSS,呈現給咱們調用方式是http api。api
文件存儲實現了文件的POSIX接口,因爲整個文件系統不依賴操做系統,經常使用於實現共享文件系統,常見的好比說ceph fs,gluster fs呈現給咱們的使用方式是文件系統。網絡
提供裸塊的能力交由物理機使用,協議是SCSI,iSCSI,文件系統層由操做系統提供。呈現給咱們的使用方式是裸盤,不帶任何文件系統,須要格式化後使用,或者使用塊API。架構
目前塊存儲主要是三個組件,gateway、storage、 cluster manager。app
gateway主要是解析iscsi協議,把塊請求解析發送到storage進行處理;運維
如今Kubernetes 的趨勢愈演愈烈,Kubernetes 逐漸成爲雲原生時代的基礎設施,爲了給上雲的程序提供服務,雲原生也隨之出現,目前世面上已經有OpenEBS Portworx 和Rook等產品。分佈式
雲原生存儲不只要爲上雲的服務提供服務,自身也利用雲的特性加強自身的功能,依賴Kubernetes的特性,咱們能夠輕運維,輕部署,利用容器隔離的能力,減小異常進程以前的相互影響,提升總體資源的利用率。ide
Kubernetes做爲將來雲上的操做系統,把存儲整個生命週期和管理抽象成三種資源。
抽象了管理存儲相關的配置,主要是provisioner、parameters、reclaimPolicy這三個配置。
經過聲明不一樣stroageclass能夠管理多種類型的存儲好比說ceph,glusterfs等等。
表示一段已分配的存儲,能夠是文件系統,也能夠是裸塊,雲存儲的雲盤或者文件系統映射到Kubernetes 就是一個PersistentVolume。
用戶存儲的請求,能夠請求特定的容量大小和訪問模式(例如,能夠以讀/寫一次或指向屢次模式掛載)。
抽象出PersistentVolumeClaim把存儲和管理分離,經過PersistentVolumeClaim咱們能夠控制訪問存儲的權限,存儲的容量和類型。
下圖是Kubernetes使用存儲的一個方式:
這裏衍生下Kubernetes 的一些設計理念,Kubernetes 使用聲明式的API,經過YAML聲明請求,並保存到etcd,這樣作的好處是把整個請求記錄下來,對於問題的回溯也比較方便,不用本身去記錄日誌提煉請求。
另外Kubernetes 還提供了對於各類資源的watch Api,各類資源的crud均可以經過watch api實時的拿到對應的YAML,這樣的設計的好處是讓Kubernetes 擁有很是好的擴展性,經過實現controller 去watch各類資源的變化狀況,定義該資源的crud行爲。
提供一個將任意塊或者文件存儲系統對接到給容器編排系統(COs)上的接口標準,如Kubernetes。
把存儲從建立到銷燬整個生命週期抽象成一組標準接口,Kubernetes經過對接CSI,實現對存儲整個生命週期的管理。
下圖就是CSI定義的存儲卷的生命週期:
上文說道Kubernetes 對存儲的抽象是StorageClass,PersistentVolume ,PersistentVolumeClaim等資源CSI 則是提供一組標準接口。因此須要引入一層把Kubernetes 中的資源行爲轉爲CSI接口的程序,Kubernetes 提供了多個sidecar屏蔽這個過程。
這裏簡單科普下sidecar,通常來講,引入sdk實現某些功能,在編譯的時候把sdk代碼編譯進去,更新sdk要從新發布,和工程耦合的比較緊密,sidecar則是把sdk實現的功能經過在pod運行一個獨立的容器實現,經過sidecar們提供rpc接口進行交互,能夠做爲被調用方,也能夠是把服務包裝起來加強服務功能,增長這樣子的好處是解耦,讓更新sidecar容器的版本更簡單。
經過引入如下sidecar,咱們能夠只專一於實現CSI定義的接口。
從官網給的圖咱們就能夠直白的看到粉紅色框的sidecar們至關於一層膠水,把Kubernetes和csi連接起來。
至此咱們已經講完了Kubernetes和CSI與K8S怎麼交互的,接下來說下PV與調度的關係。
在調度階段,PV的affinity 會影響Pod的調度,因此有調度需求的能夠經過PV的affinity控制。
以前查閱資料的時候發現這兩個接口的說明講的比較少。
NodeStatgeVolume的接口是把遠端的雲盤掛到物理機上面。NodePublishVolume的接口是把NodeStatgeVolume以後的盤掛進容器裏面。Kubernetes 在NodeStatgeVolume階段會給每一個PV生成一個全局掛載點,以下圖:
經過判斷這個掛載點是否掛載能夠方式PV重複掛載致使出錯。接下來NodePublishVolume把NodeStatgeVolume的的掛載點掛載的本身Pod文件夾下,最終這個Pod的掛載點會被掛載進容器裏面。
存儲做爲基礎組件,直接和本地盤打交道,因此咱們一個要解決的事情就是若是Kubernetes 管理本地盤。
kubernetes管理本地盤
經過官方提供的local-static-provisioner自動生成LocalPersistentVolume管理磁盤。
LocalPersistentVolume是Kubernetes提供的一種管理本地盤的資源。
經過statefulset 管理有狀態的存儲服務, 爲每一個pod分配一個單獨的磁盤可使用volumeClaimTemplates給每一個pod生成惟一的pvc,具體規則${claimNmae}-${podName},事先準備好PVC 和 PV,經過Statefulset 咱們就能夠把咱們的存儲託管到雲上了。另外借助daemonset,能夠把咱們gateway模塊部署到每個node上面。處理雲存儲的請求。
基於Kubernetes和statfulset得到了滾動更新,灰度更新,健康檢查,快速擴容等功能,只須要一組yaml文件就能夠快速搭建一個集羣,相比於傳統寫ansible腳本部署的方式複雜度大大下降。
因爲Kubernetes把存儲抽象成StorageClass PersistentVolume PersistentVolumeClaim。咱們能夠經過他們管理咱們的存儲資源,基於Kubernetes lable的過濾功能,能夠實現簡單的關係查詢,經過PVC與PV管理存儲資源,減小管理端的開發。定位問題也能經過POD信息快速定位到問題機器和問題雲盤。並且接入Kubernetes生態上的prometheus後,監控告警也能快速開發。
docker限制cpu memory使用,減小進程之間資源互相干擾,進一步提高資源利用率。
Q1:基於K8S的在線集羣實現離線任務的混合部署,有什麼心得嗎?
目前咱們線上的轉碼job就是部署在在線集羣,因爲離線任務用到的cpu比較多,部署的時候須要經過affinity策略設置pod強制分散在各個物理機,不過最重要仍是要看整個集羣的監控大盤,根據負載設置離線任務的資源。
Q2:OPPO這邊用的是什麼監控?作了什麼改進嗎?
咱們這邊是自研的監控,監控核心是tsdb,咱們這邊自研了一個分佈式的tsdb,性能很是強大,每秒支撐上千萬的metrics入庫,因此咱們如今是每秒採集一次監控指標,相比於廣泛的30秒採集一次,咱們在分析性能峯刺的問題有更多數據能夠參考。
Q3:自研監控和Prometheus相比,對於監控是怎麼取捨的?
咱們這邊的tsdb是監控Prometueus的接口,可以充分利用Prometheus的開源生態,至關因而分佈式版本的Prometheus。
Q4:存儲的伸縮性是怎麼處理的?
這裏不知道是指哪一個伸縮性哈,我理解的有兩個:
存儲集羣的伸縮性:有存儲集羣自己的擴縮容機制保證;
存儲卷的伸縮性,csi提供了expand接口,能夠經過此次接口實現對卷的擴縮容。
Q5:K8S每次更新pod版本判斷服務ready有什麼好的方法嗎?
咱們這邊是寫了個controller watch了K8S pod的事件,經過事件判斷pod是否ready。
Q6:除了經過storageclass、pv/pvc對接存儲外,有嘗試過把ceph、hdfs等存儲集羣自身也部署到容器集羣內嗎?
有的,咱們目前有部分存量數據用了ceph,storageclass、pv、pvc這三個是K8S對於整個分佈式存儲的抽象,想要靈活高效的使用存儲都避不開這三個,此外K8S還提供了flexvolume,這個是以二進制的形式擴展到K8S裏面的,比較簡單,沒有controller作中控,對動態擴容、快照之類的功能支持的比較弱。