ブートキャンプで学生たちを相手にしていると、バックエンドでサーバーアプリケーションを立ち上げる方法について混乱が多いため、ここに整理する。
ここではnginx Unitを使います。以前では私が誤って考えていたこともあり、nginx unitの技術の真価を十分に理解していなかったと感じたため、再びここに整理することにしました。
サーバープロセスの起動方法の基本
サーバープロセスを起動する基本は「バックグラウンド」で実行することです。例えば、Spring Bootの配布jarファイルを起動する場合は
$ java -jar build/libs/application.jar &
のようにして「&」を付けてバックグラウンドで起動するのです(いわゆるnohub起動)。
このように起動するとどのような問題があるでしょうか?
- プロセスの管理が難しい。
- 別の管理ツールがなければ、プロセス管理の基本はログを見ることになりますが、ログはアプリケーションから別途に残す必要があります。職人技でログの生成や保存を実装する必要があります。
- オートスケーリング
- 負荷が発生した場合は、プロセスの数を増やすか、負荷が減少したらプロセスの数を減らす必要があります。これも管理ツールがなければ困難な部分です。
ここで目立つのは動的構成と含まれるプロセス管理機能です。負荷が増加すると自動でスケーリングを行い、これもオプションで調整可能です。
nginx unitのインストール
nginx unitのインストールはmacOSおよびほとんどのLinuxをサポートしています。
インストールの詳細は公式ウェブサイトを参照すれば良いですが、注目すべき点はunitのメインとパッケージをインストールする必要があるということです。例えば、ubuntu 20.04(筆者が使用しているバージョン)の場合のインストールコマンドは次のようになります。
sudo apt update
sudo apt install unit
sudo apt install unit-dev unit-jsc11 unit-perl \
unit-php unit-python3.8 unit-ruby unit-wasm
sudo systemctl restart unit
(もしubuntu20.04でpython3.11をインストールされてもunit-python3.11パッケージを設置はできません。defaultバージョンはpython3.8なのでunit-python3.8のみできます。)
ここでのunit-dev, unit-jsc11, unit-python3.8などは、それぞれ汎用、Java11、Perl、Python3.8のプロセスをunitで管理するという意味です。
Nest.jsをunitで実行する
よく使われるフレームワーク(Spring Boot、Flaskなど)や言語については、すでに公式ウェブサイトに設定方法が記載されています。ここでは、公式ウェブサイトには記載されていないNest.jsをunitで実行する方法について説明します。
nest.jsテストプロジェクトのフォルダです。
~/nestjs/tddtest$ ll
total 396
drwxr-xr-x 7 ubuntu ubuntu 4096 Mar 5 06:03 ./
drwxrwxr-x 3 ubuntu ubuntu 4096 Nov 2 05:16 ../
-rwxr-xr-x 1 ubuntu ubuntu 663 Nov 2 05:16 .eslintrc.js*
drwxr-xr-x 7 ubuntu ubuntu 4096 Nov 2 05:16 .git/
-rwxr-xr-x 1 ubuntu ubuntu 391 Nov 2 05:16 .gitignore*
-rwxr-xr-x 1 ubuntu ubuntu 51 Nov 2 05:16 .prettierrc*
-rwxr-xr-x 1 ubuntu ubuntu 3340 Nov 2 05:16 README.md*
drwxrwxr-x 2 ubuntu ubuntu 4096 Mar 5 05:29 dist/
-rwxr-xr-x 1 ubuntu ubuntu 171 Nov 2 05:16 nest-cli.json*
drwxr-xr-x 485 ubuntu ubuntu 20480 Mar 5 04:39 node_modules/
-rwxr-xr-x 1 ubuntu ubuntu 325381 Nov 2 05:16 package-lock.json*
-rwxr-xr-x 1 ubuntu ubuntu 1948 Nov 2 05:16 package.json*
drwxr-xr-x 2 ubuntu ubuntu 4096 Mar 5 05:25 src/
drwxr-xr-x 2 ubuntu ubuntu 4096 Nov 2 05:16 test/
-rwxr-xr-x 1 ubuntu ubuntu 97 Nov 2 05:16 tsconfig.build.json*
-rwxr-xr-x 1 ubuntu ubuntu 638 Nov 3 04:11 tsconfig.json*
我々が興味があるのは/distフォルダです。
~/nestjs/tddtest/dist$ ll
-rw-rw-r-- 1 ubuntu ubuntu 181 Mar 5 05:25 app.controller.d.ts
-rw-rw-r-- 1 ubuntu ubuntu 1595 Mar 5 05:25 app.controller.js
-rw-rw-r-- 1 ubuntu ubuntu 428 Mar 5 05:25 app.controller.js.map
-rw-rw-r-- 1 ubuntu ubuntu 35 Mar 5 05:25 app.module.d.ts
-rw-rw-r-- 1 ubuntu ubuntu 1146 Mar 5 05:25 app.module.js
-rw-rw-r-- 1 ubuntu ubuntu 351 Mar 5 05:25 app.module.js.map
-rw-rw-r-- 1 ubuntu ubuntu 104 Mar 5 05:25 app.service.d.ts
-rw-rw-r-- 1 ubuntu ubuntu 2855 Mar 5 05:25 app.service.js
-rw-rw-r-- 1 ubuntu ubuntu 863 Mar 5 05:25 app.service.js.map
-rw-rw-r-- 1 ubuntu ubuntu 193 Mar 5 05:25 constants.d.ts
-rw-rw-r-- 1 ubuntu ubuntu 363 Mar 5 05:25 constants.js
-rw-rw-r-- 1 ubuntu ubuntu 265 Mar 5 05:25 constants.js.map
-rw-rw-r-- 1 ubuntu ubuntu 11 Mar 5 05:25 main.d.ts
-rw-rw-r-- 1 ubuntu ubuntu 340 Mar 5 05:25 main.js
-rw-rw-r-- 1 ubuntu ubuntu 287 Mar 5 05:25 main.js.map
-rw-rw-r-- 1 ubuntu ubuntu 108543 Mar 5 05:25 tsconfig.build.tsbuildinfo
-rw-rw-r-- 1 ubuntu ubuntu 143 Mar 5 05:25 user.json
Nest.jsでは、メインエントリーファイルはmain.jsであり、デプロイフォルダーを実行するにはnode main.jsコマンドでプロセスを起動しますが、これをnginx unitで実行する方法について説明します。
まずconfig.json(ファイル名はなんでもいいです。)を作成します。
{
"listeners": {
"*:4000": {
"pass": "applications/nestjs_app"
}
},
"applications": {
"nestjs_app": {
"type": "external",
"working_directory": "/home/ubuntu/nestjs/tddtest/dist",
"executable": "/usr/bin/env",
"arguments": [
"node",
"--loader",
"unit-http/loader.mjs",
"--require",
"unit-http/loader",
"main.js"
]
}
}
}
このファイルを簡単に説明すると、4000番ポートを使用し、typeは「external」に、working_directoryは「dist」フォルダに設定します。executableはenv(/usr/bin/env)にして、argumentを通じてnodeコマンド及びmain.jsファイルの起動を設定します。
これは次のコマンドを通じて反映されます(ubuntu Linuxを基準としています。他のOSの場合は公式ウェブサイトを参照してください)。
$ sudo curl -X PUT --data-binary @config.json --unix-socket\
/var/run/control.unit.sock http://localhost/config
成功すると、次のように表示されます。
{
"success": "Reconfiguration done."
}
プロセスが起動されたか確認してみましょう。
~$ ps -ef | grep unit
root 196630 1 0 05:17 ? 00:00:00 unit: main v1.32.0 [unitd]
unit 196632 196630 0 05:17 ? 00:00:00 unit: controller
unit 196633 196630 0 05:17 ? 00:00:00 unit: router
unit 196799 196630 0 05:31 ? 00:00:00 unit: "nestjs_app" prototype
unit 196800 196799 0 05:31 ? 00:00:00 node --loader unit-http/loader.mjs --require unit-http/loader main.js
- unit: main [unitd]
これはNginx Unitのメインプロセスで、全体のシステムの管理と調整を担当します。起動時に初期化を行い、その後は他のプロセスの実行を管理します。 - unit: controller
コントローラープロセスは、Nginx Unitの設定および管理APIリクエストを処理します。このプロセスは、新しい設定変更を受け取り、それらの変更をシステムに適用する役割を果たします。 - unit: router
ルータープロセスは、入ってくるリクエストを適切なアプリケーションプロセスに転送する役割を果たします。リクエストのURL、ヘッダーなどを分析し、設定されたルールに従ってどのアプリケーションにリクエストを転送するかを決定します。 - unit: “nestjs_app” prototype
プロトタイププロセスは、特定のアプリケーション(この場合は“nestjs_app”)の初期インスタンスを作成します。このプロトタイプは、実際のリクエスト処理用のアプリケーションプロセスを作成するために使用されるテンプレートとして機能します。新しいリクエストが到着し、追加のプロセスが必要な場合、このプロトタイプを基にアプリケーションプロセスが作成されます。 - unit: “nestjs_app” application
アプリケーションプロセスは、実際に入ってくるウェブリクエストを処理します。“nestjs_app”プロセスは、Nodeアプリケーションのコードを実行してリクエストに応答します。このプロセスは、必要に応じて動的に作成および終了されることがあり、各インスタンスは別々のリクエストを独立して処理できます。
このようにすると、unitdプロセスが全体的にnestjs_appを管理しながらスケーリングなどを調整することができます。スケーリングテストの部分は、後で再度取り上げることにします。
4000番ポートで実行した結果は以下の通りです。
