簡介: 自動化構建和CI/CD每每是相輔相成的,能夠理解爲,自動化構建是溫飽問題,解決了溫飽就會有更多的提升生產力的訴求,也就是對應的CI平臺,CI/CD本篇文章不作擴展。
前端
做者 | 琉克
來源 | 阿里技術公衆號java
只要是軟件開發就離不開構建,構建無處不在,構建是源代碼和用戶呈現之間的橋樑。python
這裏要澄清一點,構建 != 編譯,構建的本質是把源代碼翻譯成運行環境能識別的產物(源代碼多是Java代碼,也多是配置文件、資源文件等,運行環境多是物理機,也多是虛擬機,也多是mobile phone)。linux
因此工程師天天每時每刻都在構建,不構建就無法驗證。隨着規劃的擴大,把構建自動化掉,提供一個「打包平臺」也就是一個天然而然的事情,畢竟提升生產力是第一訴求嗎,這也就是構建平臺最開始的由來,把天天干的事情自動化掉,搬上平臺。android
自動化構建和CI/CD每每是相輔相成的,能夠理解爲,自動化構建是溫飽問題,解決了溫飽就會有更多的提升生產力的訴求,也就是對應的CI平臺,CI/CD本篇文章不作擴展。git
構建 != 編譯,構建自己是一個很複雜的編排過程。舉兩個例子:github
1 Android APK的構建過程
spring
上圖中綠色部分爲工具,淺藍色部門爲源代碼+中間產物。能夠看到是一系列的工具+輸入的編排,最終生成運行環境可識別的產物。上訴構建過程生成的產物(APK)可被Android手機識別並運行。docker
2 Java Jar包的構建過程
編程
能夠看到jar包的構建過程和上面APK的差別很是大,相對來講也是更簡單。
3 構建工具
上面兩個case能夠看出來,構建自己很複雜,要最終構建出一個能夠運行的產物須要作不少事情,咱們徹底能夠手動javac copy jar等等一系列操做實現構建過程。但當工程愈來愈大,文件愈來愈多,這個事情就不是那麼地使人開心了。這些命令每每都是很機械的操做。因此咱們能夠把這些機械的操做交給機器去作。對應的構建工具也應運而生,畢竟提升生產力是第一訴求。
拿Java舉例:
Ant
上面的示例中,Ant定義了五個任務:init、compile、build、test和clean。
每一個任務作什麼都定義清楚了。在打包以前要先編譯,因此經過depends來指定依賴的路徑。
若是在命令行裏執行ant build,那就會先執行compile,而compile又依賴於init,因此就會先執行init。
執行命令:
ant test
經過命令就能夠執行編程,打包,測試。爲開發者帶來了很大的便利,提供了工做效率。
可是Ant有一個很致命的缺陷,那就是沒辦法管理依賴。
咱們一個工程,要使用不少第三方工具,不一樣的工具,不一樣的版本。
每次打包都要本身手動去把正確的版本拷到lib下面去,不用說,這個工做既枯燥還特別容易出錯。爲了解決這個問題,Maven如約而至。
Maven
Ant僅是一個構建工具,它並未對項目的中的工程依賴以及項目自己進行管理,而且Ant做爲構建工具未能消除軟件構建的重複性,由於不一樣的項目須要編寫對應的Ant任務。
Maven做爲後來者,繼承了Ant的項目構建功能,而且提供了依賴關係,插件機制,項目管理的功能,所以它是一個項目管理和綜合工具, 其核心的依賴管理, 項目信息管理, 中央倉庫,Maven的核心理念是約定大於配置。每一種類型都有固定的構建生命週期。
和ant的build.xml相對的,maven項目的核心是pom.xml,java開發同窗確定都很熟。
Gradle
Gradle已經拋棄了Ant、Maven中Xml配置的形式,取而代之的是Gradle採用了領域特定語言Groovy的配置。Gradle繼承了Maven中倉庫,座標,依賴這些核心概念。文件的佈局也和Maven相同。但同時,又繼承了Ant中target的概念,咱們又能夠從新定義本身的任務(在Gradle中叫作task)。
相比maven會更簡潔,好比在maven中要引入依賴:
轉換成gradle腳本:
dependencies {
compile('org.springframework:spring-core:2.5.6') compile('org.springframework:spring-beans:2.5.6') compile('org.springframework:spring-context:2.5.6') compile('com.google.code.kaptcha:kaptcha:2.3:jdk15') testCompile('junit:junit:4.7')
}
配置從原來的28行縮減至7行!效果驚人。
同時gradle在構建性能上也碾壓maven,gradle在maven的基礎上額外增長了增量構建、build cache、daemon等特性,大大提高構建時間。
相似的構建工具其實還有不少,基本屬於百花齊放,好比facebook的BUCK,Google的bazel等,國內也有一些廠商本身的構建工具,好比騰訊的blade。不一樣的工具都會有本身的優點和劣勢。
1 原始時代
其實最開始的訴求很是簡單,構建工具基本都是現成的,人少,功能簡單。全部構建基本都是手動。
2 自動化
顯然,隨着人員的增加,規模的擴大,原始時代根本沒法支撐進一步發展,主要的矛盾:
這一階段最大的訴求:項目管理/多人協做/自動化構建。應運而生兩個平臺:CP SCM。
大概長下面這個樣子:
初級階段
這裏構建比較大的難點仍是在機器的管理和調度,其實作了不少事情:
上面框架運行了一段時間後仍是發生了不少問題,構建成功率愈來愈低,主要有幾個問題:
進階階段
其實這一塊,開源有很是成熟的方案 -- jenkins。咱們乾的不少的事情jenkins都已經幫咱們幹了。也能很好的解決咱們遇到的痛點:
改造完大概長這樣:
黑科技(填坑)
這裏要拋出一個新的概念「製品庫」。
Java開發中,你們對maven、gradle這些工具確定不能再熟悉了。前面講構建工具的時候講過,Java構建工具備幾代演進:Ant,Maven,Gradle。Maven以前的上古工具,用的人應該很是少了。
在Maven以前,是不存在版本管理,依賴管理這種概念的,全部的東西都在你的倉庫。你的工程裏面用到了gson,spring,log等開源框架和功能時,是須要去手動下載對應的jar包,而後放在代碼庫中。若是須要更新,須要不停去項目對應官網,下載最新發布的包。
Maven以後的工具,提供了強大的依賴管理功能,只要在pom.xml寫上你要使用的依賴,maven會自動下載依賴,修改和升級只須要修改GAV座標(groupid,artifactid,version),依賴的全部jar包都存儲在「製品庫」中。
此時的構建大概長這個樣子:
存在的問題
理解下這兩個問題,隨着業務的迅速發展,接入的系統愈來愈多,APP愈來愈多,構建的環境愈來愈「胖」。
好比:App除了支付寶,還有口碑,財富,香港錢包等,各個產品有本身的構建邏輯,也有本身的工具,好比支付寶用gradle4,口碑用gradle2。
其它的技術棧也愈來愈多,Java,GO,C++等,須要不一樣的JDK版本,GO環境等。
全部環境都塞進一臺物理機,這裏存在兩個比較嚴重的問題:
頻繁增長新的工具,如何確保不影響既有的環境和構建。
環境不可複製,新的構建機器,初始化困難,很難保證和舊有環境的一致性。
歷史發生過的問題
3 容器化
構建是一件很是值得敬畏的事情,須要保證構建的絕對正確,一旦構建異常了,後果不堪設想。
最好的保證構建正確性的方式,就是什麼都不要改,不要加機器,不要改環境,什麼都不要動。
可是現實是老是有愈來愈多新的場景冒出了,今天要支持這個,明天要支持那個,這裏是一個比較矛盾的點。
在容器技術出來以前,你們都是用的是虛擬機技術,咱們能夠模擬出來一臺乃至多臺電腦,可是太笨重了,也很差維護。2013年Docker開源,它輕量,高性能(秒級啓動),隔離性,讓他迅速成爲焦點。
構建也嘗試探索,docker技術很是適合在構建時使用,能夠很好的解決上面的問題。改造後長下面這樣:
以後升級環境不再是痛,各類場景容器隔離,升級互不影響,物理機秒級擴容。運維人員基本只要維護Dockerfile就行。
固然也會帶來新的問題:
前面講的都是軟件的構建過程和構建服務,這裏其實還存在一個問題,除了構建的一致性,軟件的運行環境一致性也相當重要。常常會發生,一個軟件,在個人電腦能夠,在別人的環境卻跑不起來。
隨着容器技術愈來愈火,serverless技術和應用微服務架構的演進。容器正迅速成爲企業應用打包和部署的基本單位,能夠真正的實現build once & run everywhere。
在螞蟻的歷史中也是如此,愈來愈多的場景開始鏡像化部署,因此鏡像構建自己也變得愈來愈重要,鏡像構建的效率,穩定性,安全性等相當重要。
鏡像構建也通過兩次演進:
docker build
docker build是比較簡單的,咱們在以前的架構之上新增了一種鏡像構建類型,主要存在下面幾個弊端。
(1)對於multi-stage 的Dockerfile 構建 沒法實現並行編譯
(2)docker build 緩存利用效率低,改變Dockerfile 前面的一層,後面全部的層都需
要從新構建而沒法使用緩存,這要求用戶不得不認真控制寫好本身的Dockerfile以確保鏡像緩存複用。
buildkit + K8S
buildkit是從docker build分離出來的單獨項目,目前buildkit已經集成到Docker 18.06以後的版本之中,核心特性:
這裏不進行擴展,有興趣的同窗能夠查看buildkit的官方項目(螞蟻目前天天運行着上萬數量的高可用鏡像構建服務)。
5 擁抱雲原生
隨着螞蟻愈來愈多的業務serverless化,雲原生慢慢成爲了趨勢。伴隨着的是對K8s之上的構建和資源的使用訴求。
而K8s自己使用門檻又極高,同時也缺少靈活的任務編排能力。相應的構建團隊也開始調研和投入雲原生的構建和調度解決方案。
2019年3月份持續交付基金會(CDF)正式成立,它致力於使企業在多個 CI / CD 平臺上更輕鬆地構建和複用 DevOps 管道。
第一批進入CDF項目的主要有四個:
Tekton 做爲谷歌捐贈的 CDF 重要項目 ,是一組用於構建 CI/CD 系統的共享開源組件,與 Kubernetes 緊密相連,其重要性不言而喻。
而且jenkinsX底層也選擇了tekton做爲執行引擎。
Jenkins X is committing fully to Tekton as its pipeline execution engine. We are convinced that this is the right choice for Jenkins X, as a cloud-native CI/CD platform on Kubernetes, and for our users.
內部落地
綜合權衡,採用tekton是一個比較合理的解決方案(站在巨人的肩膀,不重複造輪子)。
通過一段時間的探索和演進,逐步落地了雲原生的資源調度和構建解決方案——ironman。服務內部天天幾萬的構建、代碼掃描、CI任務等場景。
詳細細節能夠參考下面幾篇文章:
下一步計劃
tekton相比K8s,複雜度大大下降,而且提供了足夠靈活的編排和調度能力,可是仍然有缺陷:
概念複雜,偏厚重,總體調度相比直接使用POD會更慢
使用上仍然有一些成本,對一線用戶的接入使用不友好
目前正在投入POD預熱等極簡模式,解決上訴痛點。固然還有不少未解的難題,就不一一贅述。
6 構建中臺
經歷了自動化,容器化,鏡像化等場景,發現用戶的需求實在是千奇百怪,愈來愈多(只能說螞蟻的業務發展太快)。
咱們有愈來愈多的業務場景(IOT,小程序,大數據,...),構建的需求差別性也很是大。有Mac構建,Linux構建,Windows構建。應付仍是有點吃力。尤爲是在Mac和Windows兩種沒法虛擬化的場景,大量的機器分組,有點維護不動。現狀大概長這樣:
因爲構建邏輯基本都是在構建團隊維護,SCM和構建腳本中的代碼邏輯也處於一個很是混亂的狀態,基本就是大量的if else,僞代碼大概長這樣:
if (framework == "sofa") {
buildCmd = "mvn clean package" if (app == "special") { buildCmd = "mvn clean package -Ptest=true" }
} else if (framework == "android") {
buildCmd = "gradle clean assembleRelease"
} else if (framework == "jar") {
buildCmd = "mvn clean install && mvn deploy"
} else if (xxx) {
buildCmd = "xxx"
}
這個階段在面對一些個性化的構建需求其實有點力不從心,需求千奇百怪:「我要加個額外的參數」,「我要更多的CPU」,「我須要用Mac來跑構建」,「我須要用某某軟件的某某版本」。
當前階段是無法繼續支撐螞蟻將來的業務發展的,在加上當前底下已經有很是多的資源(linux,windows,Mac,K8S)管理困難。
因此將來的構建平臺,至少是能夠作到下面兩點:
構建可描述
全部的構建邏輯是透明的,可配置化,可代碼化,可描述內容包括:
這裏最關鍵的點是去掉大量分組維護帶來的難點,讓資源之間能夠共用,互相流動。同時能夠實現資源之間的任意切換,降級,保障構建服務的高可用(好比K8s資源下降到物理機構建)。
新的框架大概長下面這樣:
業務使用方只要定義好buildspec.yaml文件,就能夠實現任何個性化的構建需求。
底下執行構建的資源能夠是K8S,能夠是jenkins,能夠是物理機,whatever,構建資源描述好本身支持的類型入場便可。
buildspec.yaml大概長下面這樣:
name: android-aar-build params: - name: productLine default: alipay - name: sprintId default: ${SPRINT_ID} resources: - name: code-repo type: git url: https://code.alipay.com/xxxxx ref: master environment: type: LINUX_CONTAINER image: reg.docker.alibaba-inc.com/alipay/aarbuild:latest buildTasks: - name: Download config image: python:3 commands: - python --version - name: Install Dependency image: ruby:2.6 commands: - echo "-------2 in ruby:2.6" ruby -v artifacts: - name: pod-for-alipay type: iot-sign path: xxxx.zip
1 統一構建中臺
目前還在持續的開發和演進中,做爲服務螞蟻全棧的構建服務,其穩定性,高可用,靈活性相當重要。尤爲是極限生存能力。
2 雲原生調度基礎設施
面向K8s的CI/CD,讓K8s的資源使用簡單優雅。tekton的優雅升級,極簡的調度方案,友好的接入成本。
3 極致的構建效率和體驗
深度定製構建工具
製品庫升級
原文連接本文爲阿里雲原創內容,未經容許不得轉載。