build 之前执行task_一次NPM前端项目的CI-Build速度优化
Base
基礎設施部分,項目發布在中國區亞馬遜云,使用了AWS的容器服務(ECS)、容器注冊表(ECR)、對象存儲(S3)、彈性計算(EC2)
源碼管理使用Atlassian出品的bitbucket,一款Git體系的代碼倉庫
CI/CD使用Jenkins與pipline實現與維護
項目開發語言為nodejs
項目代號salmon
項目打包&發布使用NPM&docker
一、標準的發布流程
二、癥結反饋
同事A:“目前自動化的CI/CD流程在線上環境比較緩慢,可能拖累開發測試工作,請尋找一些優化點”
同事B:“我的項目在本地打包只要一兩分鐘,但是線上構建流程要花10+分鐘”
三、成因分析
查閱Jenkins Console Output && 分析Jenkin blue-ocean的時間統計,主要分為三個關鍵步驟:
stage{'Build'} 編譯代碼 // > 10min
stage{'Publish'} 推到倉庫 // < 10s
stage{'Deploy'} 運行服務 // < 1min
隨后繼續分析“構建”這一步,時間消耗在docker build,進一步分析各個step,發現npm run build消耗了最多時間,約為9分鐘
剛剛提到,我們線上發布流程是容器化的,包括Jenkins的slave,也是在EC2虛擬機上面啟動的jnlp-slave-container,再執行docker build命令,編譯過程寫在dockerfile當中。
與開發工程師本地構建這一過程相比,容器化的CI流,每一次構建,它的基礎設施都是純凈的、無狀態的,除了推送到遠端的image也是沒有文件留存的。即傳統基礎設施與容器化純凈環境的差異,可能就是build速度差異的關鍵。
四、問題復現
我選用了一臺EC2(2核8GB),用于復現非容器化的構建流程并統計耗時,模擬開發者在自己的Mac開發環境從源碼到build的過程。
step1.
$ mkdir /code
拉取最新slamom項目代碼,執行npm install,隨后執行5次npm build,初次build約8分鐘,隨后的4次為2分半。
step2.
在同一個項目目錄(/code),回滾至5個版本前的salmon代碼 git reset --hard HEAD^5;
執行npm install,隨后執行5次npm build,初次build約1分鐘,隨后的4次為1分鐘。
step3.
回復至第一步的最新版代 git reset --hard HEAD;
執行npm install,隨后執行5次npm build,初次build約2分半,隨后的4次為2分半。
下圖為腳本輸出記錄。
1~5 step1;101~105 step2小結:在已build過的項目目錄進行后續build,會大大減少這一過程耗時,是否是因為生成了編譯的緩存文件?
step4.
復現與審查CI流程,主要為3步,多次復現發現項目目錄容量增長如下
- 拉代碼 # 14MB
- npm install # 434MB
- npm run build #525MB
已知.next/目錄下為npm run build編譯后的成品項目代碼,刪除這部分后,有470MB
經過多重文件對比,定位到在編譯后的項目中,node_modules/目錄下會有一個.cache 目錄
多次調試,驗證了build前后差30MB文件的問題,確實是在 .cache 目錄中
將.cache目錄的內容應用到已執行npm install未build的目錄,有以下場景:
- 同版本號的代碼,build時間 8min → 2.5min
- 臨近兩三個版本號的代碼,build時間 8min → 4min
- 差較大版本號的代碼,build時間仍為 8min
五、優化設計
接下來考慮的是如何將這個目錄,或稱緩存池,維護和利用起來?考慮CI流基本都在小版本號之前變更,決定將這個緩存目錄維護在線上,build之前拉取,build之后推送。
我使用了AWS的S3服務,S3有一個目錄同步功能(sync)
文檔地址:https://docs.amazonaws.cn/cli/latest/userguide/cli-services-s3-commands.html
# s3 sync 命令使用如下語法。可能的源-目標組合有:# 本地文件系統到 Amazon S3# Amazon S3 到本地文件系統# Amazon S3 到 Amazon S3$ aws s3 sync <source> <target> [--options]在EC2測試機上運行的結果:
六、優化編譯腳本(即dockerfile)
改造了原有的node-builder鏡像,添加了aws cli工具用以操作S3,imageURL:
***.http://dkr.ecr.cn-northwest-1.amazonaws.com.cn/node-builder-with-awscli:normal
改寫后的dockerfile摘錄如下:
# 添加了build過程與緩存池的pull&oush交互-20191213 FROM ***.dkr.ecr.cn-northwest-1.amazonaws.com.cn/node-builder-with-awscli:normal as builder# Create app directory WORKDIR /usr/src/app# Install app dependencies # A wildcard is used to ensure both package.json AND package-lock.json are copied # where available (npm@5+) # Bundle app source COPY . .RUN npm cache clear --force && NPM_CONFIG_REGISTRY=https://registry.npm.taobao.org npm install && mkdir node_modules/.cache && aws s3 sync --quiet s3://zhiwen-build-cache/salmon/.cache/ node_modules/.cache/ && npm run build && aws s3 sync --quiet node_modules/.cache/ s3://zhiwen-build-cache/salmon/.cache/ && rm -rf node_modules/.cacheFROM node:10.15.3-alpineWORKDIR /usr/src/appCOPY --from=builder /usr/src/app .#USER nodeEXPOSE 3000 CMD [ "npm", "start" ]七、驗證優化效果
摘錄了Jenkins blue-ocean的統計,一個Jenkinsfile包含4個stage的執行時間
salmon-DEV-661 : stage{&#39;Build&#39;} 耗時4m7ssalmon-DEV-661 : next build 耗時2m41s對比一個未優化的CI流
salmon-DEV-399 : stage{&#39;Build&#39;} 耗時9m43ssalmon-DEV-661 : next build 耗時8m4s提速效果還是比較明顯的
八、關于線上緩存池
- 緩存池會越來越大,會不會反過來拖累build時間
- 設置了創建時間大于5天即刪除的緩存池過期策略,看看好不好使,或把這個時間改更短些
這是當時實施留存的兩個issue,根據后續的運行觀察:
- 緩存池(一個S3 Bucket的目錄)保存了大概3000~3600個靜態文件,build樣本為dev環境的14個,時間均在4分半到5分鐘
- sync操作需要20s~30s
- 5天的緩存池過期策略能夠正常運行,也比較匹配開發周期
九、問題與總結
其他項目沒有使用 .next 框架或webpack打包工具可能鋪展不開這套 .cache 緩存池的優化策略。
本文使用的工具都比較簡單,得益較大的是在優化探索中
- 問題采集與復現
- 數據對比
- 成因分析
- 優化方案設計
- 搜尋適合工具
- 思路舉一反三
- 成果檢驗
這些項目工程邏輯與解決問題的思考和方法論,希望能對自己和讀者都有些啟發
總結
以上是生活随笔為你收集整理的build 之前执行task_一次NPM前端项目的CI-Build速度优化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 两物体的相对速度公式_最全物理公式合集,
- 下一篇: 2017年html5行业报告,云适配发布