《從頭搭建持續集成 DevOps 流水線》由資深敏捷教練、極限編程學院高級講師、CODING 特邀敏捷顧問李小波老師主講,將基於 CODING 展現如何編寫 Jenkinsfile 搭建 CI/CD 流水線,包括單元測試,端到端測試,代碼規範檢查,製品庫,Docker 化部署。前端
你們好,今天課程的主要內容爲如何從頭搭建 DevOps 流水線以及其在研發工做中的意義,最後是 DevOps 流水線實踐與敏捷開發的關係的總結。數據庫
最開始是在極限編程裏提出了持續集成,而後 ThoughtWorks 又提出了持續交付,以後又提出了DevOps 這個概念,爲何要作這些呢?我認爲緣由是隨着時間的增加,生產力會不斷的降低。團隊剛開始時效率很高,從 0 到 1,功能上線很快,可是到了後期速度就會愈來愈低,直到最後開發停滯。系統開發的後期每每會出現三個難點:第一,增長新特性難。隨着系統功能的累積,會出現不少重複的代碼以及不合理的設計,致使增長一個新特性時要改的地方很是多,改動成本很是高;第二,修復缺陷難。用戶可能會報一些缺陷或 Bug,可是由於代碼太亂、太複雜致使很難定位到缺陷;第三,引出新的缺陷。作新 Feature 時,很容易出現打地鼠的現象,按下一個 Bug 結果又冒出來三個 Bug,給團隊帶來困境。編程
出現這些現象的緣由首先是在需求演變的過程當中,有的代碼會不斷地腐壞,方法會愈來愈長,類會變得愈來愈大,代碼出現大量的重複。雖然有些團隊會制定代碼規範,但在實際應用中,可能基本上都在 Word 或 PDF 裏「躺着」,檢查執行難以長期堅持。後端
其次是架構也會腐壞。項目開始時架構師一般會根據業務設計好架構,有多少個模塊、對象,分到幾層,哪層能夠調,哪層不能調,怎麼依賴關係,這些都會很清楚,但在不斷的演變過程當中,架構每每會變得亂七八糟。瀏覽器
戴明(William Edwards Deming)提出了質量內建的概念,即產品的質量在建設過程當中就已經嵌入,並非靠後期的檢測來發現的。後期的檢測並不能增進代碼質量,也不能提高產品質量,問題發現的越早修復的成本越低。因此咱們但願每一次往代碼庫提交代碼時,都可以立刻得到反饋:此次修改是好的仍是很差的,是否是增長了重複的代碼,是否是下降了測試覆蓋率,是否是破壞了某一些功能等等。有了這樣的評判標準,就可以始終保證每一個人每次提交代碼都是在產品上增長價值,而不是破壞它。在這個背景下就引入了流水線這個概念。安全
流水線是一個隱喻,意思是將軟件研發的各個環節銜接起來。我認爲流水線在研發管理過程當中扮演了三個角色:不辭辛勞的臨時工、鐵面無私的守護者以及快速精準的操做員。服務器
流水線是不辭辛勞的臨時工。如今的構建流水線均可以按需建立。好比說 CODING,這麼多的企業在用它的持續集成功能,不可能給每個用戶分配固定的計算、存儲等資源。若是要能線性的增加,策略應該是當用戶須要構建時會按需進行建立,而且用完以後進行銷燬。從這一點上看,流水線就很像一個臨時工。除此以外,流水線還能夠不厭其煩地作重複的事情,尤爲是持續集成的團隊天天都要提交不少次代碼,每一次提交都人工作一次檢查就很痛苦,但機器就能重複機械運動。架構
流水線是鐵面無私的守護者。首先是代碼規範。不少開發團隊的代碼規範都「活」在 Word 或 PDF 裏,即便有資深教練或者技術 Leader 偶爾會作一些代碼評審,這種執行力度也是遠遠不夠的。可是經過集成到流水線中的方式,好比指定一個方法不能超過多少行,一個類不能超過多少行,代碼重複率不能超過多少,代碼的寬度及命名等,進行自動化、標準化的檢測,就能夠有效的保證代碼規範的落地;第二是測試覆蓋率。在平常的開發工做中會有單元測試、組件測試、接口測試、集成測試、端到端測試等多種測試,每一次提交代碼都須要檢查測試覆蓋率有沒有降低。但不少團隊這一塊是缺失的,他們在流水線上只是作了構建、打包、部署等動做,並無跑測試覆蓋率,而是靠大規模的手工測試來保證質量,致使沒法快速迭代;第三是架構約束。代碼通常有分層,每一層裏應該放什麼文件,哪一個文件可以調哪一個文件,這些都是有約束的,須要一套自動化的機制來保證落地;其次還有安全性檢查。好比作 Web 開發會引入一些第三方的開源代碼,這些開源代碼每每會有安全缺陷,須要在每次引入新內容時進行安全性檢查。單元測試
流水線是快速精準的操做員。越複雜的系統,環境就越多,包括開發聯調環境、測試環境、預發佈環境等,到正式的環境還會有多個實例。每一個環境上訪問數據庫的 URL 不同,訪問其餘服務的環境也會不同,如何保證在操做過程當中都不出錯?能夠依靠流水線來標準化、流程化、自動化地完成這些動做,每次代碼提交時都檢查規範,針對不一樣的環境打出不一樣的包,持續的部署到不一樣的環境上面。測試
那麼如何搭建一條流水線?有一種方式叫作流水線即代碼(Pipeline as Code),即把流水線放到代碼裏。我認爲這樣作的好處是版本化,傳統的搭建方式問題在於操做沒有記錄,也沒法強制 Review,當一臺服務器掛掉,換一臺服務器時須要把原來流水線的配置從新操做一遍。若是將流水線變成代碼,就能夠跟蹤及重複建立,提升生產效率。另外補充一點,流水線在構建時主要有兩種方式,一個叫聲明式,一個叫指令式。聲明式就是規定好環節與步驟,須要怎樣的東西。而指定式須要寫不少的條件判斷,是邏輯式的,維護成本也會高一些,因此聲明式是目前廣泛採用的一種方式。
一條典型流水線應該包含四個關鍵環節。第一是構建。前端、後端的代碼都須要編譯,前端好比 HTML、JS、CSS 等,可能還會用到一些模板,須要作編譯工做將其轉成瀏覽器可以支持的格式;第二是檢查。編譯完成以後須要檢查代碼是否是符合規範,是否是有不少的重複代碼,重複率超過了多少等等;第三是測試。測試環節很重要,會影響團隊對於產品發佈的信心。這裏講一個測試金字塔理論:底層是大量的單元測試,中間是組件測試或者接口測試,頂部是端到端測試。由於大量的邏輯都是在各類 If else 分支裏,單元測試能夠覆蓋到這些分支,那麼上層的測試就不須要再覆蓋下層已經覆蓋過的邏輯了。而上層測試的價值在於把這些代碼集成起來,站在用戶的角度去使用它,看看可否正常工做。上層和下層的測試關注點不同,解決的問題也不同;第四是部署。最後須要構建鏡像,並推到製品庫裏面去,更新服務器,作完這一系列的事情以後,流水線實例就會銷燬。
最後總結一下,爲何會衍生出 DevOps 實踐及其跟敏捷開發的關係:
第一,咱們最重要的目標是經過持續不斷地及早交付有價值的軟件使客戶滿意。我認爲這跟敏捷是一脈相承的。敏捷的原則裏說可工做的軟件高於詳盡的文檔,客戶更但願看到的是可用的軟件,而不只僅是文檔說明,可是因爲開發過程的不透明,形成了客戶喜歡作微觀管理的現象,同時也會讓開發團隊變得很被動。敏捷裏有個價值觀叫尊重,這種尊重是須要團隊本身去贏得的。經過創建一套流程,提升開發過程的透明度,從而創建客戶與團隊之間的信任。另外跟敏捷原則相契合的一點是響應變化高於遵循計劃。這不是一句口號,而是一種能力,它包含:項目管理能力、需求管理能力、配置管理能力以及質量保障能力。這四種能力建設起來以後,團隊才能擁有響應變化的能力。持續集成、自動化測試、自動部署等這些核心能力,搭配上代碼規範、CodeReview、TDD等這些實踐,才能真正提高開發團隊的實力,而不是僅僅把 Scrum 導入進來,開開計劃會、站立會就好了。
第二,可工做的軟件是進度的首要度量標準。不是天天站會或者每週寫個郵件告訴客戶這周完成了多少工做,而必定是部署完成後,變成了能夠看到的、能夠體驗的功能纔算是真正的進度。
第三,堅持不懈的追求技術卓越和良好的設計,敏捷能力由此加強。開發團隊擁有了代碼規範檢查、自動化測試等這些質量門禁之後,纔有底氣去不斷的作優化,獲得可持續的、快速迭代的速率。實踐都會隨着技術的變化而變化,團隊能力也在持續的變化,但能不能持續地保持敏捷,那就要看價值觀、原則是否是可以持續地符合。