對敏捷研發和DevOps過程實踐的若干問題思考總結
在前面提到云原生完整技術解決方案的時候,已經提到了公司DevOps技術支撐平臺和容器云解決方案。但是DevOps絕對不是一個簡單的開源技術集成或者技術解決方案,而是結合本身的微服務架構優化,敏捷開發的企業研發過程改進和持續優化。
敏捷研發和CI/CD持續集成過程脫節,往往才是當前最大的一個問題點。
今天談的重點不是DevOps具體的底層開源工具鏈和技術,而是對于敏捷研發,微服務如何更好的和DevOps過程形成一個高度協同的整體。在這個過程實踐中,可能會形成多篇文章,都是對我們實踐過程的一些問題總結,思考和復盤。
先從單體微服務拆分談起
圖片
最早的時候,我們自己的DevOps管控治理平臺拆分為20多個微服務,20多個微服務每個都是獨立的項目,獨立設計流水線,部署在獨立的容器里面。可想而知,整個后續集成,部署和運維管控的復雜度有多大。
在去年,團隊進行了重構,將微服務進行了合并,在合并完成后包括基礎組件和能力中心微服務,一共在10個左右的微服務模塊。合并到這個粒度后基本才處于一種可控的狀態。
微服務拆分的顆粒度實際上還和你團隊規模有關系,當你團隊規模本身就不大的時候一定不要拆分的太細,一個人如果就管理多個微服務,實際當初進行微服務劃分,希望進行的邊界和解耦往往根本就無法做到。
在合并完成后仍然存在兩個問題。
其一是數據庫仍然沒有拆分是一個大數據庫。如果從理想的微服務架構來說,并沒有做到完全的微服務化,數據庫層面沒有解耦。
但是當你數據庫本身就沒有海量并發和數據量大幅擴展的壓力時候,你的數據庫為啥要拆分?數據庫本身不要為了拆分而拆分,數據庫的拆分更多是為了擴展性的需求。當構建的應用在DB層本身沒有太大的性能壓力的時候,實際沒必要馬上就去做數據庫的拆分。
其次,我在很早就提出了微服務域的概念,即使上層是10個微服務,你的數據庫本身也不需要就一定拆分為10個,而是應該根據微服務域的劃分來進行數據庫的拆分。比如上層的編譯,構建,流水線,交付管理等微服務,完全可以合并在一個數據庫里面。
其二是在前后端分離情況下,整個平臺的BS前端合并在一個項目里面。這個我個人認為并不太合理,也就是說一個功能如果涉及到前端應用有改動,那么整個前端應用都需要重新部署。比如資源管理部分的前端界面變化了,實際整個應用前端都需要重新部署,那么對于流水線,資產庫這些微服務模塊對應的前端是否造成影響并不清楚。
也就是說前端并沒有做到完全的解耦。
如果你是開發一個APP應用功能,那么前端整合為一個項目無可厚非,但是如果是傳統的企業級的PC端的BS應用,最好的方式仍然是前端需要進行分離。
從需求用戶故事到任務拆分
圖片
在敏捷研發里面我們強調基于用戶故事進行全流程的跟蹤。我們將收集的需求進行分析,將需求定義為用戶故事或需求點,同時將需求規劃到具體的項目版本中。這個是最基本的產品-項目-項目版本的分解過程。
當需求規劃到項目版本后,一個重點就是將需求轉變為具體的任務。你采取的不同研發過程,不同的管控顆粒度下,實際上任務的分解本身是有標準可以遵循的。如果從傳統的方式下,任何一個需求點往往包括了如下任務分解:
1.資源配置功能需求
1.1 資源配置需求文檔編寫
1.2 資源配置功能開發
1.3 資源配置測試用例編寫
1.4 資源配置功能測試
這是最常見的一個任務分解安排。
在敏捷開發和前后端分離下,你可以看到一個功能的開發同時涉及到前端和后端,后端開發完成后輸出的是接口,前端基于接口進行集成和聯調。在這個過程中測試人員又需要接入進行測試,其一是針對后端開發完成的接口測試,其二是針對前端完成的功能做黑盒測試。那么基于這個思路,你會看到任何一個功能的實現都可以分解為如下:
1.資源配置管理功能實現
1.1. 需求開發-》需求人員
1.2 后端功能和API接口開發-》后端開發
1.3 API接口測試-》測試人員
1.4 前端功能開發和集成-》前端開發
1.5 功能整體測試-》測試人員
當思考到這里的時候,實際我們希望的是,對于敏捷研發項目管理工具,在你的開發模式確定后,基于某個需求點的子任務拆分應該是自動化進行的。或者說可以基于標準的開發任務分配模板進行自動的子任務生成。
如果做到這點,實際上還是沒有辦法解決問題。因為我們任務的跟蹤實際上還是按照單個任務的方式,按未開發-進行中-已完成等任務狀態進行看板跟蹤。
但是我們實際需要的是按照開發模式關鍵技術進行任務跟蹤。比如前面談到的我們跟蹤的是用戶故事或需求點,我們關心的狀態是當前用戶故事處于需求開發階段,還是后端開發,還是前端開發集成階段。這個才是關鍵的看板跟蹤點。
也就是說傳統看板你看到的是類似下圖:
圖片
但是實際上我們希望看到的是基于需求或用戶故事點為核心的看板。這個看板并不是現實具體的子任務,而是只到任務基本,子任務影響到的是看板面板卡片的狀態。
圖片
比如上圖,我們可以很清楚的看到當前迭代版本一共規劃了11個功能點,同時每個功能點當前在哪個階段或狀態。其次,對于某個崗位角色的人上來,也可以很清楚的看到他當前自己的關鍵todo事項,他要做的是盡快完成自己泳道的事情,將任務狀態轉移到下個階段。也就是說當做了如上改進了時候,才能夠更好的做到敏捷研發模式和敏捷任務看板管理的一個融合協同。
從需求變更到項目版本規劃
在這里我們將已有功能的需求變更和新增的小需求都納入到需求變更的范疇。當前談CI/CD持續集成和持續部署,更多的都是應用系統上線后的缺陷修改,需求變更引發的迭代版本開發和部署操作。
因此需求變更才是后續軟件應用持續集成的一個基礎輸入。
圖片
在前面談產品和項目兩級流水線設計的時候,我就談到了一個產品拆分為了多個微服務模塊,每個微服務模塊都相對獨立和解耦。
但是用戶最終看到的仍然是整個應用系統。
一次需求變更過來后,我們通過分析最終需要確定的就是涉及到哪幾個微服務模塊需要變更。在分析清楚后,最好的方式就是僅僅變更的微服務模塊需要重新進行持續編譯,構建和部署集成,而對于沒有變更的模塊不應該進行重新的編譯構建操作。
微服務下對傳統單體應用解耦后,最基本要做到的就是某個微服務如果沒有變更,就不應該去重復地進行編譯和部署,任何重復多余的編譯部署操作往往都容易引入新的缺陷或問題。
比如上圖的例子,一次需求變更過來我們規劃V2版本,但是實際上只有綠色的三個微服務模塊需要進行版本升級和變更,而灰色的三個并沒有變更,不用進行重新的編譯構建等操作。在這個時候容器管理部分的功能在應用發版后不需要進行回歸測試,即使容器管理部分功能出現問題,我們也應該追溯容器暴露接口相關的外圍消費和調用。
當這個思考清楚后,你會看到需求變更納入到項目版本,那么我們實際最關心的是當前的項目版本整體進展,這個進展不是只是需求,任務和缺陷的研發管理過程和任務,同時也應該包括了整個CI/CD過程進展。
簡單來說就是:研發管理過程和CI/CD過程應該基于項目版本主線形成一個完整的類似看板一樣的管理視圖。這個視圖就是整個敏捷團隊的工作界面。
對于這個可視化看板,簡單構思應該如下:
圖片
也就是說我們希望看到一個完整的基于項目當前版本的看板視圖,在這個視圖一個是可以看到當前需求,任務的直接進展情況;其次是可以清楚地看到涉及到當前項目版本的編譯構建和部署情況。
這個也是我們進一步將研發任務管理的狀態和CI/CD過程進行集成的基礎。
比如我們在前面很多文章里面談到的。
開發人員對一個開發任務反饋完成,這個時候任務本身的狀態應該是在待部署狀態,這個是一個看板上的隱藏狀態并不需要人工去關心。而只有流水線執行成功后相關的任務才會從待部署狀態轉移到待測試狀態。
也就是說開發完成任務,這個功能本身仍然在開發人員的看板中,只有后臺的流水線執行成功,完成了功能的自動部署后,該需求功能才會自動轉移到測試中這個看板。
這些關鍵環節必須系統自動銜接。
否則一個功能開發反饋已經完成,但是測試人員上去發現并不能測試,最終追溯才看到流水線任務實際執行失敗,導致開發完成的功能并沒有成功部署。這些都勢必會導致大量無效的人工溝通和協同工作。
流水線觸發和構建頻率
圖片
在DevOps實踐方法論里面,始終在強調隨時隨地的觸發構建,一天不需要去約束構建次數,只要代碼一check in就應該觸發流水線編譯構建流程進行構建。
在講這個問題前,我想先談兩個例子。
一個是在游樂園里面做一個旋轉的游樂設施,剛開始的時候速度不快,完全能夠接受。但是后面速度越來越快,最后感覺就是腦袋一陣眩暈。實際上這個設施可以轉得更加快或者說頻度跟高,但是就個人來說,你始終會有一個你能夠接受的極限值,超過了就暈。個人由于各自的身體素質差異,實際上這個極限值本身存在不同。
還有一個我們寫文章的例子。
比如我寫文章,我專門找了一個編輯幫我進行審核和修訂,我既可以是每寫一小段就發給對方讓他修改,也可以是我每天或每周發送一次給對方讓對方統一修改。如果我每寫一個小時就發送一次,那么對方馬上反饋問題后,我實際的寫作過程都在隨時被打斷,這個顯然是對我正常寫作造成影響。
圖片
回到我們構建頻率這件事情上。
實際上構建方式或頻率包括了代碼check in就自動構建,也可以是人手工發起構建,還可以是每天或每半天定時構建一次。如果按DevOps最佳實踐方法是代碼提交即構建,但是我要說的是這種方法并不適合大部分的團隊,什么原因呢?
其一是團隊和個人本身的成熟度和敏捷度就無法適應這種高頻率構建,工具高頻率容易,但是人要高頻率需要的是高度的自律。其二是當隨時都在構建的時候,你發現開發人員隨時都在解決構建過程中出現的問題或依賴沖突,導致開發真正專注在編碼上的時間越來越少,也就是是高頻率構建極其容器導致我們開發時間碎片化,這個顯然是開發的大忌。
當做了上述思考后,最佳的方式仍然是按天或半天定時構建,同時對于關鍵bug的解決根據業務驅動由測試手工發起流水線運行。
很多互聯網應用每2到3天就再發布和迭代版本,但是對于企業內部信息化應用,實際上遠遠不需要如此敏捷和高頻,因此我們持續集成和構建的頻率也無須如此。
當團隊和個人自身的能力和成熟度達到后,我們可以進一步縮短構建頻率,比如從半天到每2個小時一次構建。同時對于構建頻率的縮短往往還伴隨著PMS任務顆粒度的細化,你原來的任務顆粒度是1周或2到3天,那么新的顆粒度則可能是2小時或4小時。
父子流水線和環境遷移
圖片
首先再次強調一個關鍵點,即:
對于CI/CD的價值一定體現在跨環境的自動遷移部署能力,而不是單個環境的自動化編譯構建和應用部署。編譯構建的過程只有一次,形成的是二進制文件包;而環境遷移可以多次并靈活編排,環境遷移不需要重新編譯構建,最終確保基礎依賴的一致性。
也正是如此,環境遷移一定是我們流水線設計編排的一個重點。
比如最常見的業務場景,我們準備了SIT集成測試環境和UAT用戶驗收測試環境,當某個版本的軟件開發在SIT環境完成集成測試,所有的Bug都修復后。我們需要將軟件部署到UAT環境,并通知用戶進行驗收測試。
如何確保用戶驗收測試的版本就是我們SIT測試通過的版本?
即前面談到的基于二進制和鏡像文件的遷移,對于UAT環境部署重新編譯部署,而僅僅是鏡像文件在UAT環境的部署,這是CI/CD強調的一個重點。
圖片
那么問題的復雜度在哪里?
即前面談到的傳統的一個單體應用系統以及拆分為了10個微服務模塊,每個微服務都可以獨立編譯構建,打包和部署。每個微服務都有自己各自的流水線設計。
但是實際上就一個項目版本來說,我們只關注這個項目版本的完整性。比如這個項目版本僅僅涉及到3個微服務模塊要變更,那么在SIT測試通過后就應該將這三個微服務模塊的最新測試通過版本遷移部署到UAT環境。
也就是說應該在微服務流水線基礎上增加一個對應產品或項目版本的流水線。編譯或構建是以微服務為最小顆粒度單位,但是環境遷移構建,是以產品或項目版本為單位進行。
我們還是回到前面的場景,比如DevOps平臺研發規劃了V2版本,這個版本涉及到門戶管理,研發管理,持續集成三個微服務模塊的變更和發布。
對于上面三個微服務模塊本身就已經有自己的獨立編譯構建部署流水線任務。
那么現在重點就是基于本次規劃的項目版本V2,構建一個父流水線,同時將已經有的三個微服務模塊流水線掛接進來,形成一個完整的父子流水線模式。
也就是說在父流水線上我們只會編排環境遷移的關鍵節點,比如:開發測試環境-》SIT環境-》UAT環境
我們會在流水線上設置由測試人員參與的手工審核和處理節點,當測試人員確認SIT測試通過的時候,我才進行自動化的環境遷移動作。同時父節點必須是在各個子流水線運行成功后再跳轉到下一個活動節點狀態。
比如前面談到發起一次父流水線運行,那么先去執行各個子流水線,子流水線如何全部執行成功則將父流水線狀態轉移到待測試狀態。測試人員在完成一輪測試后,如果不通過則進行不通過處理,將流水線退回到初始狀態。
同時在進入流水線視圖的時候,可以清楚地看到當前整體流水線的執行情況,即當前項目版本涉及到幾個子流水線,各自對應哪個微服務模塊,每個子流水線是否允許成功,如果失敗可以進入到詳細的流水線任務查看界面查看原因等。