Published on

GitHub ActionsでblogをNginxにdeployする

Authors
  • avatar
    Name
    Nomad Dev Life
    Twitter
2024-11-02-github-actions

JavaScript heap out of memory

まだ3記事目だというのに、Webサーバー上でNext.jsのブログをyarn buildすると"JavaScript heap out of memory"が発生し、buildできなくなりました…。

 ? Compiled successfully
   Linting and checking validity of types  . ? TypeScript project references are not fully supported. Attempting to build in incremental mode.
   Linting and checking validity of types  .
<--- Last few GCs --->

[295983:0x71075a0]    62412 ms: Scavenge 472.8 (485.6) -> 472.5 (486.9) MB, 12.6 / 0.0 ms  (average mu = 0.760, current mu = 0.650) allocation failure;
[295983:0x71075a0]    62580 ms: Scavenge 473.5 (486.9) -> 473.2 (491.4) MB, 103.4 / 0.0 ms  (average mu = 0.760, current mu = 0.650) allocation failure;


<--- JS stacktrace --->

FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
 1: 0xb85bc0 node::Abort() [/home/user/.nvm/versions/node/v18.18.2/bin/node]
 2: 0xa94834  [/home/user/.nvm/versions/node/v18.18.2/bin/node]
 3: 0xd66d10 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/home/user/.nvm/versions/node/v18.18.2/bin/node]
 4: 0xd670b7 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/home/user/.nvm/versions/node/v18.18.2/bin/node]
 5: 0xf447c5  [/home/user/.nvm/versions/node/v18.18.2/bin/node]
 6: 0xf56cad v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/home/user/.nvm/versions/node/v18.18.2/bin/node]
 7: 0xf313ae v8::internal::HeapAllocator::AllocateRawWithLightRetrySlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/home/user/.nvm/versions/node/v18.18.2/bin/node]
 8: 0xf32777 v8::internal::HeapAllocator::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/home/user/.nvm/versions/node/v18.18.2/bin/node]
 9: 0xf1394a v8::internal::Factory::NewFillerObject(int, v8::internal::AllocationAlignment, v8::internal::AllocationType, v8::internal::AllocationOrigin) [/home/user/.nvm/versions/node/v18.18.2/bin/node]
10: 0x12d8caf v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [/home/user/.nvm/versions/node/v18.18.2/bin/node]
11: 0x1705b39  [/home/user/.nvm/versions/node/v18.18.2/bin/node]
   Linting and checking validity of types  ..

Tailwind CSS BlogのIssueを見ると、"12500ページのbuildだとメモリ16GBではbuildできない"とか、"100ページ超でも8GBでは足りない"という話がでています。SSGはコンテンツ生成時にかなりメモリを使うようですね。

確かにWebサーバーのランニングを安く上げる為にスペックをケチっているのですが、それにしても3記事目でダメか…と。

WebサーバーはVPSなのでスペックを上げることはできるのですが、ランニングは少しでも安い方が助かります。ですので、今回はGitHub Actionを使い、GitHub上でbuildして、生成したhtml等をWebサーバーにdeployしてみることにしました。

イメージ

今回は、git pushしたらGitHub Actionsyarn buildし、成果物(out)をVPSにSSH/SCPでdeployしたいと思います。イメージは以下です。

2024-11-02-github-actions

Webサーバーは、24時間立ち上げっぱなしなのでVultr VPSにdeployしています。そのおかげでサーバー代は月¥1,000もかかっていません😄

SSH/SCPの準備

GitHub ActionsからWebサーバーにコンテンツをdeployする際に、SSH/SCPを使います。その為、GitHub Actionsに事前にSSH鍵を登録しておく必要があります。予めSSH鍵を作成し、その鍵でdeploy先のサーバーにSSH接続できることを確認しておいてください。

SSH鍵は、GitHubのリポジトリを選択 -> Settings(画面上) -> Secrets and variables(画面左) -> Actionsと辿って表示される画面で"New repository secret"をクリックすると登録することができます。

2024-11-02-github-actions-secrets

登録する際に、このSSH鍵に名前を付ける必要があります。今回はWEB_SSH_KEYとしました。

Deploy

SSH/SCPでdeployする際に、VPS上で以下を実行します。

  1. コンテンツが配置されているディレクトリ(以下、out)をアーカイブ(tar.gz)し、backupフォルダに移動する
  2. outを削除する
  3. GitHub Actionsでbuildしたコンテンツ(out.tar.gz)をSCPでサーバーに転送する
  4. 転送されたout.tar.gzを展開する
  5. nginxをreloadする

その処理を行うymlファイルは以下です。これを、リポジトリの.github/workflowディレクトリの下に任意の名前で配置します。

name: Deploy

on:
  push:
    branches:
      - main
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install dependencies
        run: npm install

      - name: Build Next.js
        run: npm run build && npm run export

      - name: Archive the output folder
        run: tar -czf out.tar.gz out

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: out-folder
          path: out.tar.gz

  deploy:
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: out-folder

      - name: Set up SSH
        uses: webfactory/ssh-agent@v0.9.0
        with:
          ssh-private-key: ${{ secrets.VPS_SSH_KEY }}

      - name: Backup remote directory
        run: |
          ssh -o StrictHostKeyChecking=no user@your-vps-ip 'bash -s' << 'EOF'

          BACKUP_DIR="/path/to/backup"
          TARGET_DIR="/path/to/target-directory"

          DATE=$(date +"%Y%m%d")
          tar -czvf "$BACKUP_DIR/backup_$DATE.tar.gz" "$TARGET_DIR"
          rm -rf "$TARGET_DIR"

          echo "Backup completed: $BACKUP_DIR/backup_$DATE.tar.gz"
          EOF

      - name: Deploy to VPS using scp
        run: |
          scp -o StrictHostKeyChecking=no out.tar.gz user@your-vps-ip:/path/to/your/remote/directory

      - name: Extract files on VPS
        run: |
          ssh -o StrictHostKeyChecking=no user@your-vps-ip "tar -xzf /path/to/your/remote/directory/out.tar.gz -C /path/to/your/remote/directory && rm /path/to/your/remote/directory/out.tar.gz && docker exec <container_name> nginx -s reload"

secrets.VPS_SSH_KEYには、先ほど登録したSSH鍵に付けた名前を指定します。私の場合はsecrets.WEB_SSH_KEYになります。 また、sshやscpのコマンドの/path/to/your/remote/directoryは、VPS上のパスに書き換える必要があります。

このファイルを加えてgit commit->git pushすると、その後GitHub Actionsが実行され、VPSにbuildされたコンテンツがdeployされます。

おわりに

GitHub Actionsを使ってブログコンテンツをbuildし、deployしました。これでVultr VPSのspecを上げずに済みます😊