🌊

Azure App Service へのNode.jsアプリデプロイを大幅に改善した話

2023/09/05に公開

はじめに

仕事でNode.jsアプリを開発してましたが、デプロイに30 ~ 45分近くかかるようになり辛くなってきたので改善した話をまとめました。
改善後6分〜7分程度に短縮しました。

前提

今回はAzure App Service on Linuxをベースに試した内容を残しております。おそらく通常のApp Service (Windows版)も利用できるかと思います。
Web App for Containersは対象外です。

App Serviceとはなんぞや。という方はこちらをご覧ください。
https://learn.microsoft.com/ja-jp/azure/app-service/overview

要約

  • zipでまとめよう
  • 開発環境と、運用環境でパッケージの差分をなくすべく npm ci(rm -rf node_modules && yarn install --frozen-lockfile) を使いましょうね

詳細

App ServiceはGithubActionsとのデプロイ設定を行うと自動的に以下のようなワークフローを生成します。

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
# More GitHub Actions for Azure: https://github.com/Azure/actions
name: Build and deploy Node.js app to Azure Web App
on:
  push:
    branches:
      - stage
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
    
      - name: Set up Node.js version
        uses: actions/setup-node@v1
        with:
          node-version: '16.x'

      - name: npm install, build, and test
        run: |
          npm install
          npm run build --if-present
          npm run test --if-present
      - name: Upload artifact for deployment job
        uses: actions/upload-artifact@v2
        with:
          name: node-app
          path: .

  deploy:
    runs-on: ubuntu-latest
    needs: build
    environment:
      name: 'main'
      url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}

    steps:
      - name: Download artifact from build job
        uses: actions/download-artifact@v2
        with:
          name: node-app
      - name: 'Deploy to Azure Web App'
        id: deploy-to-webapp
        uses: azure/webapps-deploy@v2
        with:
          app-name: '< your app service name>'
          slot-name: 'staging'
          publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_B... }}
          package: .

改善の詳細は以降に記述。

ビルド

npm installをやめ、npm ciにすることで、package-lock.jsonをもとにインストールするようにしました。意図しないパッケージのバージョンインストールを防ぐため。
またunit test終了後、再度productionのみ必要なパッケージをインストールすることで容量の軽量化を図っております。 npm ci --production は実装の仕方やパッケージのインストールの仕方によっては不要にできる余地あり。

      - name: npm install, build, and test
        run: |
+         npm ci
+         npm run build --if-present
+	  npm run test --if-present
+         npm ci --production
-         npm install
-         npm run build --if-present
-         npm run test --if-present
	

zip化

zip化しました。軽量化。

+      - name: Zip all files for upload between jobs
+        run: zip --symlinks -r app.zip ./*

zipファイルを指定し、Artifactにアップロードするようにしました。

      - name: Upload artifact for deployment job
        uses: actions/upload-artifact@v2
        with:
          name: node-app
+         path: app.zip
-         path: .

App Serviceへの展開はzipファイル指定することで、自動で展開するようにしました。

      - name: 'Deploy to Azure Web App'
        id: deploy-to-webapp
        uses: azure/webapps-deploy@v2
        with:
          app-name: 'app-flier-slack-app-stg'
          slot-name: 'staging'
          publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_B... }}
+         package: app.zip
-         package: .

actionのVerup

以下のactioはデフォルトでv2になっているのでv3に上げる

  • actions/checkout
  • actions/setup-node
  • actions/upload-artifact
  • actions/download-artifact

コード全体はこちら

# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
# More GitHub Actions for Azure: https://github.com/Azure/actions

name: Build and deploy Node.js app to Azure Web App

on:
  push:
    branches:
      - main
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      - name: Set up Node.js version
        uses: actions/setup-node@v3
        with:
          node-version: '16.x'

      - name: npm install, build, and test
        run: |
          npm ci
          npm run build --if-present
	  npm run test --if-present
          npm ci --production

      - name: Zip all files for upload between jobs
        run: zip --symlinks -r app.zip ./*

      - name: Upload artifact for deployment job
        uses: actions/upload-artifact@v3
        with:
          name: node-app
          path: app.zip

  deploy:
    runs-on: ubuntu-latest
    needs: build
    environment:
      name: 'main'
      url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}

    steps:
      - name: Download artifact from build job
        uses: actions/download-artifact@v3
        with:
          name: node-app

      - name: 'Deploy to Azure Web App'
        id: deploy-to-webapp
        uses: azure/webapps-deploy@v2
        with:
          app-name: 'app-flier-slack-app-stg'
          slot-name: 'staging'
          publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_B... }}
          package: app.zip

最後に

cacheを使うなど、まだまだ改善の余地はある。
見つけ次第、updateしていきます。

Discussion