過去幾年,利用容器打包和部署代碼的方式日益流行,愈來愈多企業開始測試或是已經在生產環境中運行了微服務架構應用,開始直接面對和解決分佈式服務化架構演變中出現的各類問題。html
在這樣的趨勢和大環境下,無服務器PaaS **Rainbond**圍繞着服務的拓展、監控、治理等角度,進行了一系列思考和嘗試,插件體系正是其中的重要一環。node
Rainbond的插件體系抽象集中在平臺的業務層面,理論基礎源於Kubernetes的pod機制和一部分容器概念。針對平臺業務層面對kubernetes容器編排進行抽象,轉變爲一個對用戶體驗友善的Rainbond插件產品的過程,方便用戶在不須要懂Kubernetes原理的狀況下使用。git
Rainbond插件體系的設計遵循易於理解和易於使用的原則:github
在Rainbond插件體系中,插件使用的過程即主容器與init或sidecar等容器結合的過程,原理是將插件容器以sidecar容器(大部分)的形式編排至主應用的pod中,共享主應用容器的網絡和環境變量,所以能夠插件化實現某些附加功能,例如對主應用進行流量分析等。docker
Pod是Kubernetes中模塊化容器服務的實例,由一個或多個共享資源的容器組合而成,共享包括文件系統、內核命名空間和IP地址等資源。它是Kubernetes集羣中調度的原子單元,經過提供更高層次的抽象,實現靈活的部署和管理模式。api
在如下Rainbond(www.rainbond.com)部署pod描述文件片斷中,咱們能夠看到該pod中包含兩個containers:394d2f238a603bf01eb5215e23237691
(主容器)與22dc8b12aeaf417fa7bd6466c136b9f4
(副容器),二者經過pod機制捆綁在一塊兒,共同完成該server提供的服務。tomcat
kubectl describe pod -n b314b3e7e44e45a082a0d00e125e88bf b314b3e7e44e45a082a0d00e125e88bf Containers: 394d2f238a603bf01eb5215e23237691: Container ID: docker://44018fa19a268c1f9ea5b20e9793290cbd89b167bd1fc9017a04ecbd9606d379 Image: goodrain.me/tomcat:latest_gr237691 Image ID: docker-pullable://goodrain.me/tomcat@sha256:701d36cde0b55d07f59a65e525e258523aae46b033297f80b44b0b6c07fc0277 Port: 8080/TCP State: Running Started: Sun, 21 Jan 2018 14:56:35 +0800 Ready: True Restart Count: 0 Limits: cpu: 640m memory: 512Mi Requests: cpu: 120m memory: 512Mi 22dc8b12aeaf417fa7bd6466c136b9f4: Container ID: docker://4c8bd31c2ec2200ee323fb1abdd7b652544ce3d110b1621c36acab4bae434c77 Image: goodrain.me/tcm_20180117175939 Image ID: docker-pullable://goodrain.me/tcm_20180117175939@sha256:d2b20d7eec4da05d953fb7862b9c9ead76797ea5542bff4b93cf2bc98331d279 Port: State: Running Started: Sun, 21 Jan 2018 14:56:36 +0800 Ready: True Restart Count: 0 Limits: memory: 64Mi Requests: memory: 64Mi
一個pod能夠封裝多個容器,應用運行在這些容器之中;同時,pod能夠有一個或者多個init容器,init容器在應用容器啓動以前啓動。若是某個pod的init容器啓動運行失敗,Kubernetes將不斷重啓pod,直到init容器啓動運行成功爲止。固然,咱們能夠設定pod restartPolicy值爲Never,阻止它重複啓動。服務器
利用pod中容器能夠共享存儲和網絡的能力,sidecar容器得以擴展並加強「主要」容器,與之共存並使其工做得更好。在上面pod描述文件片斷中,22dc8b12aeaf417fa7bd6466c136b9f4
就是一個sidecar類型的容器,用來協助分析主容器的一些性能指標。網絡
Rainbond插件體系易於使用的原則體如今類應用化
、綁定使用
、獨有的變量做用域
等方面。架構
Rainbond插件體系爲插件設計了與應用相似的生命週期,包含建立、啓用、關閉等模式,與Rainbond平臺用戶操做應用的習慣保持一致。同時,Rainbond插件體系簡化了插件建立類型,支持基於docker image和dockerfile建立,建立插件比建立應用更加簡單。
插件建立流程設計以下圖所示:
須要注意的是,當一個插件版本固定後,其內存、版本信息、插件變量沒法再作修改,這些元素僅做用於當前插件版本。須要修改插件變量等元素時,對插件進行從新構建
,重複建立流程便可。
插件的建立和使用過程步驟相對獨立,用戶可使用當前租戶下建立的插件和其餘團隊(或租戶)分享到雲市的插件(初期Rainbond將陸續爲用戶提供數款插件)。
若是用戶沒有建立本身的插件,在使用插件前,須要先將他人分享在雲市的插件安裝至本地。這個過程會將分享出來的插件元數據存儲至用戶租戶下,至關於用戶「建立」了這個插件(並無耗時的構建過程)。
建立完成後,用戶能夠對插件進行鍼對性設置,目前能夠設置變量和插件生效與否(後續會增長內存設定,知足主應用複雜狀況下附加功能對應內存的需求)。內存的限制將在pod建立時進行限制,插件變量生效與實時修改在下文中會繼續介紹。
注入到容器內的變量設計爲有兩類:共用變量
與插件變量
。
共用變量就是主容器的變量,爲使插件參與甚至擴展主應用的功能,在pod建立過程當中將主應用的環境變量注入到了插件容器中;插件變量則僅做用在該插件容器內部,防止插件間的變量重複與混用。
Rainbond目前默認爲用戶提供性能分析和服務治理兩款插件,詳情訪問 http://www.rainbond.com/docs/stable/user-app-docs/myapps/myapp-platform-plugin.html 查看。
如下咱們以網絡代理插件爲例,介紹Rainbond插件體系的工做過程。
用戶填入插件相關信息後,Rainbond將根據這些信息生成插件建立任務,發送至Rainbond消息組件中,由任務發現器處理該任務消息。Rainbond的builder組件接受任務後,將會對插件進行構建,生成插件容器鏡像。一個插件容器鏡像對應一個構建版本,關聯其相應的功能特點。在Rainbond中,插件將以一個構建完成後的鏡像來進行流通。相似於應用,插件也能夠在Rainbond及雲市中進行分享。
參照插件使用文檔,在應用的插件tab中點擊安裝後,會對插件的當前最新版本與應用標記爲關聯。此時重啓應用,在pod建立時,會對插件進行判斷,若存在插件,則進行PluginContainerCreate
,pod的container list中將會包含主容器與插件容器。
網絡代理插件在Rainbond中又名servicemesh, 是一個功能加強容器,在pod中與主容器共享網絡。
網絡代理插件要完成其功能須要徹底代理主容器的網絡, 接管主容器的出入口。結構如圖:
網絡代理分爲出口網絡模式
、入口網絡模式
兩種。
出口網絡模式(示意圖中訪問tomcat應用爲出口網絡模式),圖中service mesh1 plugin經過discover_service
獲取tomcat應用的網絡信息,包括listen ports,routers,endpoints等。這些信息由discover_service經過watching kubernetes集羣中tomcat應用的services和endpoints資源獲取。discover_service API相關請查看相關代碼 https://github.com/goodrain/rainbond/blob/master/pkg/node/api/router/discoverRouter.go
在service mesh1 plugin獲取所需的下游應用信息後則開始監聽本地對應tomcat的端口,代理當前應用訪問tomcat的請求,例如curl http://tomcat
。
爲什麼上述請求能夠由pod內的容器代理呢?這是因爲dns_service
將tomcat這類規則域名解析至本地,路由及負載均衡則全權交由service mesh1 plugin進行,即客戶端負載均衡的模式。
入口網絡模式較之於出口模式相似(示意圖中由外網訪問進入main container爲入口網絡模式),複雜之處在因而對當前應用用戶設置端口的轉發,因爲本地監聽因此沒法和主容器監聽相同的端口。
在處理這種場景時,將service mesh1 plugin的監聽端口進行了轉化,在開啓插件時會隨機生成一個不重複的端口port_outer1
供給外層監聽,service mesh1 plugin繼續轉發主應用的原端口,在生成k8s的service和pod資源時由新端口替代原端口,並標註對應關係。
在外網負載均衡註冊這個應用的外網端口訪問時會使用port_outer1
來進行註冊。分配給用戶使用的域名則基於原端口與新端口的映射規則保持不變,用戶並沒有感知
相關組件discover_service
下圖爲Rainbond提供的服務治理插件配置:
用戶在控制檯將應用與插件首次關聯(安裝)後,插件就會對應當前應用產生配置。經由region端存儲至數據中心的etcd中。修改配置相應的設置,進行更新操做,則會修改對應服務的插件資源。
分佈式服務化架構面臨的問題不少,想要實現服務化,服務治理是一個比較關鍵的點。在提供治理服務的基礎上,配置則須要實現實時生效和聯動。所以在rainbond設計中將插件的配置資源放置在了discover_service
中,由該發現服務來支持動態配置。
在Kubernetes建立pod時,插件容器的env中注入了一個相關的環境變量DISCOVER_URL
,該變量的值爲插件能夠經過GET請求獲取資源的url。後續用戶在使用平臺建立本身所需的功能插件時,這個變量也是你的插件獲取資源所必須的。
相關代碼請查看 https://github.com/goodrain/rainbond/blob/master/pkg/worker/appm/pod.go
Rainbond是國內首個開源的無服務器PaaS,深度整合基於Kubernetes的容器管理、多類型CI/CD應用構建與交付、多數據中心的資源管理等技術,提供雲原生應用全生命週期解決方案,構建應用與基礎設施、應用之間及基礎設施之間的互聯互通生態體系。