サーバーアプリケーションとnginx unit

ブートキャンプで学生たちを相手にしていると、バックエンドでサーバーアプリケーションを立ち上げる方法について混乱が多いため、ここに整理する。

ここでは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
```

1. unit: main [unitd]
   これはNginx Unitのメインプロセスで、全体のシステムの管理と調整を担当します。起動時に初期化を行い、その後は他のプロセスの実行を管理します。
2. unit: controller
   コントローラープロセスは、Nginx Unitの設定および管理APIリクエストを処理します。このプロセスは、新しい設定変更を受け取り、それらの変更をシステムに適用する役割を果たします。
3. unit: router
   ルータープロセスは、入ってくるリクエストを適切なアプリケーションプロセスに転送する役割を果たします。リクエストのURL、ヘッダーなどを分析し、設定されたルールに従ってどのアプリケーションにリクエストを転送するかを決定します。
4. unit: “nestjs_app” prototype
   プロトタイププロセスは、特定のアプリケーション（この場合は“nestjs_app”）の初期インスタンスを作成します。このプロトタイプは、実際のリクエスト処理用のアプリケーションプロセスを作成するために使用されるテンプレートとして機能します。新しいリクエストが到着し、追加のプロセスが必要な場合、このプロトタイプを基にアプリケーションプロセスが作成されます。
5. unit: “nestjs_app” application
   アプリケーションプロセスは、実際に入ってくるウェブリクエストを処理します。“nestjs_app”プロセスは、Nodeアプリケーションのコードを実行してリクエストに応答します。このプロセスは、必要に応じて動的に作成および終了されることがあり、各インスタンスは別々のリクエストを独立して処理できます。

このようにすると、unitdプロセスが全体的にnestjs_appを管理しながらスケーリングなどを調整することができます。スケーリングテストの部分は、後で再度取り上げることにします。

4000番ポートで実行した結果は以下の通りです。

![](https://raw.githubusercontent.com/cheuora/cheuora.github.io/master/_posts/2024/images/image-20240305160926049.png)