我總是喜歡一些比喻,這樣可以讓我們更加形象地認識事物。
Erda 是一個 PaaS 平臺,底層用到的技術曾經從 marathon + mesos 切換到現在的 K8s,它們一般被認為是“容器層”。Erda 在“容器層”之上又堆疊了 CI/CD Pipeline、叢集和部署管理、應用監控、自動化測試等等能力,這樣分層的體現非常像網路的分層,每一層各司其職,不過我更喜歡將其比喻為「程式語言」。
封裝是為了減少“失誤”
一門高階程式語言擁有更符合人類理解的語法,其透過編譯成彙編或者機器碼來實現執行,或者是編譯成低階語言再進行二次編譯。
與此類似,Erda 透過對“容器層”的封裝,對我們的使用者呈現了具有“Erda 理念”的功能設計和使用體驗。而所謂封裝最重要的就是減少人為的“失誤”,就好像高階語言透過受限和優雅的語法、智慧的編譯提示以及豐富的類庫,大大減少開發者的心智負擔,可以輕鬆地寫出健壯的程式碼。而在其之上的程式設計方法、最佳實踐,為高速交付實現提供理論支撐。
何為製品
Erda 的身骨是以「應用」為中心打造的,假設 Erda 只能剩下一個功能的話,那就是應用的“交付”。
交付可以非常簡單,我稱之為“兩步走”:
- 將程式碼編譯成應用安裝包
- 在客戶要求的環境中安裝應用
實際的情況會稍顯複雜,但不會改變這個核心的步驟,大抵是多幾步的問題。
如果要追究細節的話,這兩步可以一直向下展開。Erda 做的事情就是讓使用者無須深究這些細節,就像我們使用個人電腦觀看影片時無須知道編碼、傳輸和解碼的過程,也無須知道有損和無損的區別。
當然,做這樣的比喻不代表 Erda 有意阻攔使用者進行深入探究,相反若懂得底層原理,更能夠加深對 Erda 功能設計的理解!
具體而言,Erda 規範了可在雲上交付的“軟體安裝包”格式,這樣的安裝包我們稱之為“Erda 製品”(下文稱之為“製品”),我們簡單羅列一下製品的特性,這樣大家可以有一個總體的印象:
- 製品是對 docker 映象的進一步抽象,類似 docker-compose.yml,涵蓋了多個映象(服務)的總體描述,以及互相之間的依賴關係
- 製品是對應用交付環境的宣告(結構化、可被系統識別的軟體安裝部署說明書),不僅宣告每個映象服務的資源限制,也能夠宣告所需要的中介軟體(比如 mysql)
需要補充一下,由於 Erda 是一個多應用架構(核心的主庫 erda、前端應用 erda-ui、監控相關的 telegraf、fluentbit 等),所以 Erda 交付的時候是多個應用共同交付,我們稱之為專案製品。專案製品在包含多個應用製品的同時還支援分批部署等特性。
這是 Erda 自己的製品(專案製品):
Erda 的專案製品
透過分組包含了多個應用製品(erda、erda-ui 等)
製品的 Addons 詳情
其中 rds 和 MySQL 可以互為替換
我們聚焦一下 Erda 主應用的製品內部,也就是分組 Group 3 中的 erda 主庫的應用製品。
由於 Erda 主應用是微服務架構(多服務),所以我們能看到一串微服務容器列表:
應用如果有多服務
每個服務都有 docker image
以及最核心的 dice.yml
:
version: "2.0"
envs:
ETCDCTL_API: "3"
services:
cluster-agent:
cmd: /app/cluster-agent
deployments:
replicas: 1
envs:
DEBUG: "false"
resources:
cpu: ${request_cpu:1}
max_cpu: 1
max_mem: 1024
mem: ${request_mem:1024}
addons:
mysql:
plan: mysql:basic
為了方便閱讀我們只列出了關鍵的資訊,如果大家需要看到完整的 dice.yml
,可以在開原始碼中找到:
https://github.com/erda-proje...
在這個例子中(也就是 Erda 自身的應用製品),大家可以充分感受到 Erda 是如何將“軟體交付”進行封裝的。
得益於 docker 對“執行環境”的封裝,再組合上 dice.yml
對微服務/多應用整體“交付環境”的封裝(例項個數、環境變數、資源消耗、中介軟體依賴),我們可以很自信地說:“開發者只需要關心其必要知曉的,其他由平臺代為負責”。
交付製品
雖然剛介紹完製品的來龍去脈,我們仍想再回顧一下製品的關鍵組成部分:
- 映象列表(docker images)
dice.yml
宣告瞭各個服務(映象列表所對應的)部署所需的資源,以及需要的中介軟體
映象(docker)的知識我們暫且按下,“開發者只需要關心其必要知曉的”且只有 dice.yml
的語法規範和配置了。
瞭解 Erda 的實現,可以知道平臺在部署製品時,讀取 dice.yml
內容,並最終轉換成“容器層”認知的結構(如果是 K8s 則是 Deployment、Service、Ingress,以及 StatefulSet 或者 Operator),進而交由“容器層”施展部署動作。熟悉 K8s 會知道,如果讓使用者手工編寫這些配置,需要理解許多本不用知曉的知識(大多是運維相關),並且容易出錯。
PS:不過針對 Addons(或者說中介軟體)的部署機制相對複雜,考慮到比如 Rds 等雲廠商提供的外部能力,Erda 單獨提供了一套部署和擴充套件能力
就像開篇講的,dice.yml
似乎是一門“高階語言”,而 K8s yml 則是“低階語言”(我們這裡所指高階和低階,並非認為“高階”一定是“優秀”和“正確”的,而是指相對於方便人類認知而言,是更傾向於易於理解和防止出錯的,而且恰恰是“低階”在效能、靈活度、控制力以及正確邏輯方面是更有優勢的),Erda 經過一次複雜的“編譯”,將使用者(我們不妨說業務研發人員)更容易理解的配置和宣告格式或者語法,轉變成實際部署的工作負載(Workload)和內生亦或外部的服務(Addons)。
聊了這麼多,很容易就能得出 Erda 是如何交付製品的結論:一鍵部署。
只需要選擇製品,就可以一鍵建立部署單,等待結果即可
當然真實的生產環境部署相對複雜,但不會改變核心的一鍵部署流程。Erda 在此之外展開了非常多額外的流程和功能:比如製品能夠匯出和匯入,我們同時也開發了 Gallery(集市)方便製品的傳播(Gallery 同時也承載了 Addons 以及 Pipeline 的 Action);製品也內建了 migration 的能力,能夠在部署的過程中進行資料遷移;等等。
當然最重要的是 Pipeline 也就是流水線的能力,透過其編排的核心 CI/CD 邏輯:“程式碼 -> 製品 -> 部署”,能夠從流程上控制生產環境(也包括測試或者其他環境)的准入,Pipeline 的 Action 擴充套件機制為方便對接外部流程節點提供可能,當然 Erda 內建提供了非常多開箱即用的能力諸如質量掃描、單元測試、自動化測試等等。
最後
本文只是從一個很小的側面:製品,講述了 Erda 如何交付自身,也包括如何交付各個其他軟體,但“製品”又是在 Erda 中最為重要最為核心的概念,也可以說是 Erda 至此不變的“理念”。這是 Erda 的起點、原點,此前 Erda 未有身骨,只是內部無名的打包部署平臺;此後 Erda 繁舟聚匯,不終不止。