GitHub Actions部署Node.js到Azure耗时久,如何优化?
优化Azure Web App Node.js应用的GitHub Actions部署速度
一、实现增量发布(仅部署变更文件)
完全可以实现增量发布,核心是通过缓存减少重复操作,只处理变更内容:
缓存依赖包
利用GitHub Actions缓存功能,仅当package-lock.json变更时才重新安装依赖,否则直接复用缓存:- name: Cache npm dependencies uses: actions/cache@v3 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} restore-keys: | ${{ runner.os }}-node-识别并打包变更文件
- 先获取当前提交与上一次部署的差异文件:
- name: Detect changed files id: changed-files uses: tj-actions/changed-files@v35 with: separator: "\n" files: | ./src/**/* ./build/**/* # 根据项目结构调整,监控源码和构建产物 - 仅对变更文件执行必要构建(若为编译型源码),再打包这些文件:
- name: Zip changed files if: steps.changed-files.outputs.any_changed == 'true' uses: TheDoctor0/zip-release@0.6.1 with: filename: delta-release.zip files: ${{ steps.changed-files.outputs.all_changed_files }} - 部署时上传增量包,关键设置
clean: false避免清空现有文件:- name: Deploy delta to Staging slot if: steps.changed-files.outputs.any_changed == 'true' uses: azure/webapps-deploy@v2 with: app-name: 'appname' slot-name: 'Staging' publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_*** }} package: delta-release.zip clean: false
注意:如果是编译型项目(如React/Vue),需确保变更源码对应到正确的构建产物,可能需要自定义脚本做文件映射。
- 先获取当前提交与上一次部署的差异文件:
二、替代优化方案(无需复杂增量逻辑)
若增量发布适配成本高,这些方案也能大幅压缩部署时间:
切换到Linux运行环境
当前流程使用windows-latest,Linux环境下npm安装、构建速度普遍更快,将runs-on改为ubuntu-latest,可减少环境初始化和依赖安装耗时。启用Run from Package模式
在Azure门户进入Web App的「配置」>「常规设置」,开启「运行从包」。该模式下Azure直接从ZIP包运行应用,无需解压,部署速度更快,还能避免文件锁定导致的停机问题。同时仅打包构建后的产物目录(如build),而非整个项目,减少上传文件数量。缓存构建产物
仅当源码或依赖变更时重新构建,否则复用之前的构建产物:- name: Cache build artifacts uses: actions/cache@v3 id: cache-build with: path: ./build # 替换为你的构建产物目录 key: ${{ runner.os }}-build-${{ hashFiles('**/src/**', '**/package-lock.json') }} restore-keys: | ${{ runner.os }}-build- - name: Install dependencies and build if: steps.cache-build.outputs.cache-hit != 'true' run: | npm install npm run build --if-present优化部署槽预热
你已使用Staging槽,需开启槽预热功能,让应用在交换到生产前完成启动,避免用户感知停机。部署完成后再执行槽交换,彻底消除生产环境停机风险。
三、优化后的完整Workflow示例
name: Build and deploy Node.js app to Azure Web App on: push: branches: - develop workflow_dispatch: jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Node.js 16.x uses: actions/setup-node@v4 with: node-version: '16.x' cache: 'npm' # 自动缓存npm依赖 - name: Cache build artifacts id: cache-build uses: actions/cache@v3 with: path: ./build key: ${{ runner.os }}-build-${{ hashFiles('**/src/**', '**/package-lock.json') }} restore-keys: | ${{ runner.os }}-build- - name: Install dependencies and build if: steps.cache-build.outputs.cache-hit != 'true' run: | npm install npm run build --if-present - name: Detect changed build files id: changed-files uses: tj-actions/changed-files@v35 with: separator: "\n" files: ./build/**/* - name: Zip full release if: steps.cache-build.outputs.cache-hit != 'true' uses: TheDoctor0/zip-release@0.6.1 with: filename: full-release.zip path: ./build - name: Zip delta release if: steps.cache-build.outputs.cache-hit == 'true' && steps.changed-files.outputs.any_changed == 'true' uses: TheDoctor0/zip-release@0.6.1 with: filename: delta-release.zip files: ${{ steps.changed-files.outputs.all_changed_files }} - name: Upload full artifact if: steps.cache-build.outputs.cache-hit != 'true' uses: actions/upload-artifact@v3 with: name: node-app-full path: full-release.zip - name: Upload delta artifact if: steps.cache-build.outputs.cache-hit == 'true' && steps.changed-files.outputs.any_changed == 'true' uses: actions/upload-artifact@v3 with: name: node-app-delta path: delta-release.zip deploy: runs-on: ubuntu-latest needs: build environment: name: 'Staging' url: ${{ steps.deploy-outputs.webapp-url }} steps: - name: Download full artifact if: needs.build.outputs.cache-hit != 'true' uses: actions/download-artifact@v3 with: name: node-app-full - name: Download delta artifact if: needs.build.outputs.cache-hit == 'true' uses: actions/download-artifact@v3 with: name: node-app-delta - name: Deploy full release to Staging if: needs.build.outputs.cache-hit != 'true' uses: azure/webapps-deploy@v2 id: deploy-outputs with: app-name: 'appname' slot-name: 'Staging' publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_*** }} package: full-release.zip clean: true - name: Deploy delta release to Staging if: needs.build.outputs.cache-hit == 'true' uses: azure/webapps-deploy@v2 id: deploy-delta-outputs with: app-name: 'appname' slot-name: 'Staging' publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_*** }} package: delta-release.zip clean: false
内容的提问来源于stack exchange,提问作者Malky
相关产品推荐
相关产品推荐

