herokuからazureに轉進

この度新日本語を長年(と云ふ程でもないが)親しんだHerokuからAzure App Serviceに移すことにした。のだが、この移行が意外と罠だらけだつたので恆例のメモ。最終的にはHeroku時代と同樣Nx workspaceで作つたモノレポをGitHubで管理し、これをLinuxコンテナのAzure Web Appに繼續的にデプロイすることを目指す訣だが、Azure App Serviceでnode.jsをやる時のやり方の組合せがそれなりにあるやうで、自分の案件がどの組合せなのかで迷兒になると途端に袋小路に嵌る印象。

移行の動機

そもそも何故移行が必要かに就いてだが、やはりHerokuの無料枠で使へるPostgreSQLが10000行までなのが大きい。新日本語はJIS X 0208の第一、二水準の漢字のみを扱ふが、これだけでも既󠄀に6000强の字があるので使へる枠の6割も消費してゐる。こゝから讀み假名等を保持するに邊り、まともな設計であれば多對多の關聯にするところを無理やりvarcharの配列に押込め、讀み假名での問合せはこれをunnestしたものにLIKEをかける等かなり複雜なものとなつてゐた。更にグリフのデータはMongoDBに置くと云ふのも、煩雜さを殖やす一因となつてゐる。ORMの利用でそれなりに統一された界面で扱へはするものの、それぞれのDBに接續する爲の分岐は必要になる。グリフの算料は名前と影算料のみと云ふ單純な鍵と値の組合せで、本家グリフウィキもRDBではなくKey-Value型の算料庫を使つてゐるとも聞くので、RDBよりもMongoDBの方が扱ひやすい可能性も見はしたが、特にそんなことはなく外部キー制約が利かないだけの不安な存在と化しただけと云ふ所感に終る。

月1000圓程拂へばこの制限が1000,0000行と一氣に1000倍になるのでそれくらゐは課金すればとも思はなくもないが、そもそもは自分の電算機で算料は扱ひ、成果物のフォントを配布するのでもよいし、誰か繼續的に見る人がゐるのか、と云ふことがどうしても過る。さう云ふ狀態で定期的に維持費が出て行くのはやはりあまり好ましくない。

そこで打開策はないかと色々漁つたが、無料で扱へる枠が多いNoSQL系ではやはりうまいこと行かないやうに思へた(單に自分がRDB腦なだけかもしれないが)。NoSQL系では算料を非正規化するが基本なので、漢字の算料庫のやうに比較的型がしつかり決まりやすいものではやはりきちんと正規化した方がよいだらう。無料枠の貧弱な性能でも耐へられる程度の接續數しか考慮してゐないところで大量の接續を捌くことに長けるNoSQLを選ぶチグハグ感も拭へない。

そんな中で發見されたのがElephantSQLである。こちらの無料枠が提供するPostgreSQLは算料の容量こそ20MBと心もとないが、行數制限はなささうである。新日本語は行數は嵩むが算料容量はそこまで喰はない見込みなので、まづはこちらに移行することにした。

ElephantSQLにHerokuから接續でも良かつたのだが、ElephantSQLはリージョンになんと東京を選べる。どこに算料があるかが分らないふわふわクラウドコンピューティング、と言ひつゝも、その實體は近所にある方が算料を取つてくるのに早くて都合がいいので、近いに越したことはない。そこで問題になるのがHerokuのリージョンである。こちらは無料枠ではアメリカか歐羅巴しか選ぶことができない。するとなんと日本からブラウザで接續すると、まづアメリカにあるHerokuの算料中心に問合せを行なひ、そこから東京にあるElephantSQLのPostgreSQLから漢字の算料を引いてきて、それを日本のブラウザに返すと云ふ一大移動となつてしまふ。ElephantSQLのリージョンもHerokuに合せてアメリカか歐羅巴にすればこの無駄の一部は省けるが、どうせなら無料で東京リージョンを選べるPaasはないものかとなり、そこで白羽の矢が立つたのがAzure App Serviceだつたと云ふ話である。

Azure App Serviceの罠

それにしてもこのサービスは一筋繩では行かなかつた。チュートリアル通りにやればさうでもないのだらうが、Nx workspace等を絡めるとなんだかよくわからない擧動に嵌ることが多々ある。GitHubに譜片を置く場合はGitHubActionsを使ふのがよささうだつたので、最終的に以下のやうなymlで落着いた。が、これで本當によいのかは實はよくわかつてゐない。

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@v2

     - name: Set up Node.js version
       uses: actions/setup-node@v2
       with:
         node-version: '14.x'
         cache: 'yarn'

     - name: Install dependencies
       run: yarn --frozen-lockfile

     - name: Format
       run: |
         yarn ci:lint
         yarn ci:format:check

     - name: Test
       run: yarn ci:test

     - name: Build
       env:
         NX_HOGEHOGE: ${{ secrets.NX_HOGEHOGE }}
       run: yarn build

     - name: Upload artifact for deployment job
       uses: actions/upload-artifact@v2
       with:
         name: node-app
         path: |
           ./package.json
           ./process.json
           ./dist
 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: Install dependencies
       run: yarn --production

     - name: 'Deploy to Azure Web App'
       id: deploy-to-webapp
       uses: azure/webapps-deploy@v2
       with:
         app-name: アプリ名
         slot-name: 'production'
         publish-profile: ${{ secrets.AzureAppServicePublishProfile }}
         package: .

基本的にはAzure App Service側が吐いたものを使ふのだが、それをそのまゝではいきなり詰んだ。まづbuildのUpload artifact for deployment jobのところだが、こゝでビルド結果を含む總ての算帳を上傳しようとすると算帳數が多すぎてCIがこける。そこで必要さうな算帳(./package.jsonやビルド結果の./dist下)のみを上げるやうにした。その後deploy側でdevDependenciesを除いた依存關係のみinstallして、これらを合せたものをAzure Web Appに配置する。そもそもbuildとdeployを分けることで一々算帳を上傳したり下戴したりする手間をかける意義があるのかがよく分つてゐない(それをせずにひとつのjobにしてゐる例も見かける)。

もうひとつの罠がフロントエンド側で讀む環境變數。Buildのyarn build前のenvのところでNX_HOGEHOGE等としてGitHubのsecretに登錄しておいた値を事前に設定ておかないと、本番でprocess.env.NX_HOGEHOGEで環境變數を取らうとしてもundefinedが返つてくる。process.envは今までてつきり實行時に實行環境での環境變數を讀むものだとばかり思つてゐたので(バックエンドで讀むPORTやらNODE_ENVはきちんと見えるので)、Azure Web Apps側の管理畫面で當該環境變數を設定してゐたのだが、それでは讀まれないのでどうもビルド時に解決してゐるやうである(なのでGitHubActions上ではビルドせずに試驗だけにして、Azure Web Appに必要算帳を配置してそこでビルドするやうにすればAzure Web Apps側の管理畫面で設定したものが反映されさうでもある)。この邊がどう云ふ仕組みを採用してゐるのかを餘り把握してゐないのでいづれなんとかしたいところだが、確かにフロントエンドのjsが實行されるのは誰かのブラウザなので、build時に解決するのが堅いやうな氣がしないでもない。

最後の罠が、PM2。Azure App ServiceのNode.jsのページによれば本番環境ではnpm startではなくPM2を使へ、process.jsonがあればそれを元にPM2が上がる、と書いてあつたのでPM2の起動設定を書いたprocess.jsonを配置するやうにしたのだが、それだとNode.jsのプロジェクトだと認識されずにAzure Web Apps側が事前に用意した標準のページが表示された。やむを得ずpackage.jsonの"start"に"pm2 start process.json"を記述したのだが、これだと立上がらない。代りに"node dist/apps/api/main.js"等としてnodeで上げるやうにすれば上がるので、Node.jsのプロジェクトと認識されるやうにはなつてはゐるやうなのだが、pm2ではログも何も出ないし八方塞がりのやうに思はれた。が、DockerでPM2を使ふ場合は"--no-daemon"を附與する必要があると云ふのがあつたので、これを試したみたところ無事上げることができた。この邊りもpackage.jsonに書く形にしなれけば嵌らない罠のやうにも思ふので、嵌る必要のない罠を澤山踏拔いてゐるやうにも思へる。今回の案件の組合せでも使へる罠のないNode.jsの王道な配置方法を知りたいところである。

この記事が気に入ったらサポートをしてみませんか?