Next.js App Router部署至Azure App Service耗时42分钟优化咨询
Next.js应用部署Azure App Service CI/CD流水线耗时过长问题
我目前使用的CI/CD流水线将Next.js App Router应用部署到Azure App Service,但整个部署流程耗时长达42分钟,这个速度完全无法接受。

配置详情
App Service配置

机器上的文件结构

流水线配置
主流水线配置
name: Deploy Next.js to Azure Web App on: workflow_dispatch: env: NODE_VERSION: 20 NEXT_APP_DIR: src/FinPhlo.Web jobs: build: name: Build and Publish runs-on: ubuntu-latest defaults: run: working-directory: ${{ env.NEXT_APP_DIR }} steps: - name: Checkout uses: actions/checkout@v4 - name: Detect package manager id: detect-package-manager run: | if [ -f "yarn.lock" ]; then echo "manager=yarn" >> $GITHUB_OUTPUT echo "command=install" >> $GITHUB_OUTPUT echo "runner=yarn" >> $GITHUB_OUTPUT echo "cache-dependency-path=${{ env.NEXT_APP_DIR }}/yarn.lock" >> $GITHUB_OUTPUT exit 0 elif [ -f "package.json" ]; then echo "manager=npm" >> $GITHUB_OUTPUT echo "command=ci" >> $GITHUB_OUTPUT echo "runner=npx --no-install" >> $GITHUB_OUTPUT echo "cache-dependency-path=${{ env.NEXT_APP_DIR }}/package-lock.json" >> $GITHUB_OUTPUT exit 0 else echo "Unable to determine package manager" exit 1 fi - name: Setup Node uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} cache: ${{ steps.detect-package-manager.outputs.manager }} cache-dependency-path: ${{ steps.detect-package-manager.outputs.cache-dependency-path }} - name: Restore cache uses: actions/cache@v4 with: path: | .next/cache # Generate a new cache whenever packages or source files change. key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }} # If source files changed but packages didn't, rebuild from a prior cache. restore-keys: | ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}- - name: Install dependencies run: ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }} - name: Build with Next.js run: ${{ steps.detect-package-manager.outputs.runner }} next build --no-lint # Move the .next/static and public folders into the standalone directory. # The minimal server.js file does not copy these folders by default # because they are ideally handled by a CDN for performance optimization. - name: Move static and public folders run: | mv .next/static .next/standalone/.next/static mv public .next/standalone/public - name: Zip artifact for deployment run: zip ../../web.zip ./* .next -qr - name: Upload artifact uses: actions/upload-artifact@v3 with: name: web-app # Name of the artifact path: web.zip retention-days: 10 deploy-testing: name: Deploy needs: build uses: phlo-systems/finphlo-net/.github/workflows/reusable-workflow.yml@main permissions: id-token: write with: environment: Testing artifact_name: web-app secrets: inherit deploy-staging: name: Deploy needs: build uses: phlo-systems/finphlo-net/.github/workflows/reusable-workflow.yml@main permissions: id-token: write with: environment: Staging artifact_name: web-app secrets: inherit deploy-production: name: Deploy needs: [build, deploy-staging] uses: phlo-systems/finphlo-net/.github/workflows/reusable-workflow.yml@main permissions: id-token: write with: environment: Production artifact_name: web-app secrets: inherit
可复用流水线配置
name: Reusable workflow on: workflow_call: inputs: environment: required: true type: string artifact_name: required: true type: string secrets: AZURE_CLIENT_ID: required: true AZURE_TENANT_ID: required: true AZURE_SUBSCRIPTION_ID: required: true AZURE_AD_B2C_CLIENT_ID: required: true AZURE_AD_B2C_CLIENT_SECRET: required: true AZURE_AD_B2C_BACKEND_APP_CLIENT_ID: required: true NEXTAUTH_SECRET: required: true jobs: deploy: name: ${{ inputs.environment }} runs-on: ubuntu-latest permissions: id-token: write environment: name: ${{ inputs.environment }} url: ${{ steps.deployment.outputs.webapp-url }} concurrency: ${{ inputs.environment }} steps: - name: Diagnostics run: | echo "Environment: ${{ inputs.environment }}" echo "Artifact Name: ${{ inputs.artifact_name }}" echo "AZURE_APP_SERVICE_NAME: ${{ vars.AZURE_APP_SERVICE_NAME }}" echo "AZURE_AD_B2C_TENANT_NAME: ${{ vars.AZURE_AD_B2C_TENANT_NAME }}" echo "AZURE_AD_B2C_PRIMARY_USER_FLOW: ${{ vars.AZURE_AD_B2C_PRIMARY_USER_FLOW }}" echo "AZURE_AD_B2C_FINPHLO_RESET_PASSWORD_USER_FLOW: ${{ vars.AZURE_AD_B2C_FINPHLO_RESET_PASSWORD_USER_FLOW }}" echo "NEXT_SIGNALR_URL: ${{ vars.NEXT_SIGNALR_URL }}" - name: Download artifact uses: actions/download-artifact@v3 with: name: ${{ inputs.artifact_name }} - name: Azure login uses: azure/login@v2 with: client-id: ${{ secrets.AZURE_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }} subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - name: Deploy to Azure Web App id: deployment uses: azure/webapps-deploy@v3 with: app-name: ${{ vars.AZURE_APP_SERVICE_NAME }} package: web.zip - name: Configure Azure Web App settings uses: azure/appservice-settings@v1 with: app-name: ${{ vars.AZURE_APP_SERVICE_NAME }} app-settings-json: | [ { "name": "AZURE_AD_B2C_TENANT_NAME", "value": "${{ vars.AZURE_AD_B2C_TENANT_NAME }}", "slotSetting": false }, { "name": "AZURE_AD_B2C_CLIENT_ID", "value": "${{ secrets.AZURE_AD_B2C_CLIENT_ID }}", "slotSetting": false }, { "name": "AZURE_AD_B2C_CLIENT_SECRET", "value": "${{ secrets.AZURE_AD_B2C_CLIENT_SECRET }}", "slotSetting": false }, { "name": "AZURE_AD_B2C_PRIMARY_USER_FLOW", "value": "${{ vars.AZURE_AD_B2C_PRIMARY_USER_FLOW }}", "slotSetting": false }, { "name": "AZURE_AD_B2C_FINPHLO_RESET_PASSWORD_USER_FLOW", "value": "${{ vars.AZURE_AD_B2C_FINPHLO_RESET_PASSWORD_USER_FLOW }}", "slotSetting": false }, { "name": "AZURE_AD_B2C_BACKEND_APP_CLIENT_ID", "value": "${{ secrets.AZURE_AD_B2C_BACKEND_APP_CLIENT_ID }}", "slotSetting": false }, { "name": "NEXTAUTH_SECRET", "value": "${{ secrets.NEXTAUTH_SECRET }}", "slotSetting": false }, { "name": "NEXTAUTH_URL", "value": "${{ steps.deployment.outputs.webapp-url }}", "slotSetting": false }, { "name": "NODE_TLS_REJECT_UNAUTHORIZED", "value": "0", "slotSetting": false }, { "name": "NEXT_PUBLIC_API_BASE_URL", "value": "${{ vars.NEXT_PUBLIC_API_BASE_URL }}", "slotSetting": false }, { "name": "NEXT_SIGNALR_URL", "value": "${{ vars.NEXT_SIGNALR_URL }}", "slotSetting": false } ]
我的猜测
我怀疑是以下两个步骤导致构建速度过慢,但不知道正确的处理方式应该是怎样的:
- name: Move static and public folders run: | mv .next/static .next/standalone/.next/static mv public .next/standalone/public - name: Zip artifact for deployment run: zip ../../web.zip ./* .next -qr
注:该应用使用的是Next.js App Router。
内容的提问来源于stack exchange,提问作者nop
相关产品推荐
相关产品推荐

