ほりひログ

所属組織の製品 (Azure とか) に関連する内容が多めだけど、個人の見解であって、所属組織を代表する公式情報ではないです。

Web App に Node.js アプリをデプロイする GitHub Actions を速くする

Web App の [デプロイ センター] ブレードで、ソースコード等が置いてある GitHub レポジトリを選択すると、その Web App にデプロイするための GitHub Actions ワークフローを作成してくれる。

Node.js アプリの場合、既定では下記の yaml ファイルが GitHub レポジトリの .github/workflows に作成される。

# 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 - some-web-app-name

on:
  push:
    branches:
      - main
  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: 'production'
      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: 'some-web-app-name'
          slot-name: 'production'
          publish-profile: ${{ secrets.AzureAppService_PublishProfile_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx }}
          package: .

この既定のワークフローのままだと、ところどころ遅いところがあるので速くしてみる。

1. devDependencies なモジュールはデプロイしない

build ジョブの 3 つ目の step npm install, build, and test の中で npm run build でアプリをビルドしている。
その為に npm installpackage.jsondevDependencies で指定しているモジュールも全てインストールしている。

これ。

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

このインストールはビルドに必要だからしょうがないが、以降 node_modules に触れず、次の step, job まで進んでデプロイしているので、devDependencies なモジュールも含めて Web App にデプロイしていることになる。
当然、これらは運用環境に不要なモジュールなので、本当はビルドが終わったら削除するのが適切。

なので、

      - name: npm install, build, and test
        run: |
          npm install
          npm run build --if-present
          npm run test --if-present
          npm prune --production # `devDependencies` なモジュールを削除

と最後に npm prune --production を追加する。
これで dependencies なモジュールは残しつつ devDependencies なモジュールを削除できる。

2. artifact を zip 化する

既定では、ビルドした後のプロジェクトを、特にまとめることもなく、そのまま artifact として保存している。

ここ。

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

上の 1. で npm prune --production を実行してモジュールを減らしても、大抵node_modules 配下には大量のファイルがある。
なので、この artifact のアップロードをする actions/upload-artifact アクションと deploy ジョブ内のダウンロードをする actions/download-artifact アクションに時間がかかる。

こういう警告も出る。

そこで、build ジョブ内の actions/upload-artifact アクションの前に一度 zip ファイル化しておき、それを artifact としてアップロードする。
すると、アップロードするファイルが 1 つになるので速くなるし、release ジョブの actions/download-artifact アクションでも 1 つの zip ファイルのダウンロードになり、こっちも速くなる。 さらに azure/webapps-deploy アクションで Web App にデプロイする時も ダウンロードしてきた zip ファイルをそのまま使えば、デプロイするファイルが 1 つになるので速くなる。

build ジョブ

      - name: Zip artifact for deployment
        run: zip release.zip ./* -qr # 除外したいディレクトリがあるなら -x オプションで指定

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

release ジョブ

      - name: 'Deploy to Azure Web App'
        id: deploy-to-webapp
        uses: azure/webapps-deploy@v2
        with:
          app-name: 'some-web-app-name'
          slot-name: 'production'
          publish-profile: ${{ secrets.AzureAppService_PublishProfile_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx }}
          package: release.zip

完成形

以上、2 点を反映させた完成形がこちら。

# 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 - some-web-app-name

on:
  push:
    branches:
      - main
  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
          npm prune --production # `devDependencies` なモジュールを削除

      - name: Zip artifact for deployment
        run: zip release.zip ./* -qr # 除外したいディレクトリがあるなら -x オプションで指定する

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

  deploy:
    runs-on: ubuntu-latest
    needs: build
    environment:
      name: 'production'
      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: 'some-web-app-name'
          slot-name: 'production'
          publish-profile: ${{ secrets.AzureAppService_PublishProfile_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx }}
          package: release.zip