のらねこの気まま暮らし

技術系だけど、Qiita向きではないポエムとかを書くめったに更新されないヤツ

App Engineを試す vol3 ~NestJSでサブシステムを動かす~

概要

AppEngine勉強日記、3日目。 この記事ではNestJSで立てたAPIサーバをAppEngineでサブシステムとして動かすとこまでを解説します。

背景

AppEngineが便利っていう話を聞いたので、AppEngineでどこまでできるのかを試す連載。 連載のゴールとしては、NuxtをBFFとしておいてAPIで処理を行うというマルチサービスの構成。

ディレクトリの整理

昨日作ったNuxtのサービスをディレクトリを掘って移動する。 defaultサービスになるのでわかり易い名前を...と思ったが、defaultでは流石にわかりにくい。 とりあえずroot命名して移動する

> git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

  renamed:    app.js -> root/app.js
    renamed:    app.yaml -> root/app.yaml
    renamed:    nuxt.config.js -> root/nuxt.config.js
    renamed:    nuxt/pages/index.vue -> root/nuxt/pages/index.vue
    renamed:    package-lock.json -> root/package-lock.json
    renamed:    package.json -> root/package.json

NestJSのセットアップ

APIサーバには最近気になっているNestJSを使う。

@nestjs/cliを入れる。

> npm i -g @nestjs/cli
> nodenv rehash

apisディレクトリを指定してプロジェクトをセットアップする。

> nest new apis
⚡  We will scaffold your app in a few seconds..

CREATE /apis/.prettierrc (51 bytes)
CREATE /apis/README.md (3370 bytes)
CREATE /apis/nest-cli.json (64 bytes)
CREATE /apis/package.json (1687 bytes)
CREATE /apis/tsconfig.build.json (97 bytes)
CREATE /apis/tsconfig.json (336 bytes)
CREATE /apis/tslint.json (426 bytes)
CREATE /apis/src/app.controller.spec.ts (617 bytes)
CREATE /apis/src/app.controller.ts (274 bytes)
CREATE /apis/src/app.module.ts (249 bytes)
CREATE /apis/src/app.service.ts (142 bytes)
CREATE /apis/src/main.ts (208 bytes)
CREATE /apis/test/app.e2e-spec.ts (630 bytes)
CREATE /apis/test/jest-e2e.json (183 bytes)

? Which package manager would you ❤️  to use? npm
✔ Installation in progress... ☕

🚀  Successfully created project apis
👉  Get started with the following commands:

$ cd apis
$ npm run start


                          Thanks for installing Nest 🙏
                 Please consider donating to our open collective
                        to help us maintain this package.


               🍷  Donate: https://opencollective.com/nest

こんな感じのディレクトリが作成される。

> ls -lah apis/
total 848
drwxr-xr-x   15 mizuki  staff   480B 12  3 23:12 .
drwxr-xr-x    9 mizuki  staff   288B 12  3 23:11 ..
drwxr-xr-x    9 mizuki  staff   288B 12  3 23:11 .git
-rw-r--r--    1 mizuki  staff   375B 12  3 23:11 .gitignore
-rw-r--r--    1 mizuki  staff    51B 12  3 23:11 .prettierrc
-rw-r--r--    1 mizuki  staff   3.3K 12  3 23:11 README.md
-rw-r--r--    1 mizuki  staff    64B 12  3 23:11 nest-cli.json
drwxr-xr-x  668 mizuki  staff    21K 12  3 23:12 node_modules
-rw-r--r--    1 mizuki  staff   389K 12  3 23:12 package-lock.json
-rw-r--r--    1 mizuki  staff   1.6K 12  3 23:11 package.json
drwxr-xr-x    7 mizuki  staff   224B 12  3 23:11 src
drwxr-xr-x    4 mizuki  staff   128B 12  3 23:11 test
-rw-r--r--    1 mizuki  staff    97B 12  3 23:11 tsconfig.build.json
-rw-r--r--    1 mizuki  staff   336B 12  3 23:11 tsconfig.json
-rw-r--r--    1 mizuki  staff   426B 12  3 23:11 tslint.json

とりあえずローカル環境でサーバを起動する。

> cd apis
> npm start
> apis@0.0.1 start /Users/mizuki/workspace/20191203-example-appengine/apis
> nest start

[Nest] 47954   - 2019-12-03 11:15:03 PM   [NestFactory] Starting Nest application...
[Nest] 47954   - 2019-12-03 11:15:03 PM   [InstanceLoader] AppModule dependencies initialized +18ms
[Nest] 47954   - 2019-12-03 11:15:03 PM   [RoutesResolver] AppController {/}: +5ms
[Nest] 47954   - 2019-12-03 11:15:03 PM   [RouterExplorer] Mapped {/, GET} route +2ms
[Nest] 47954   - 2019-12-03 11:15:03 PM   [NestApplication] Nest application successfully started +2ms
> curl -v localhost:3000
* Rebuilt URL to: localhost:3000/
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 3000 (#0)
> GET / HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Content-Type: text/html; charset=utf-8
< Content-Length: 12
< ETag: W/"c-Lve95gjOVATpfV8EL5X4nxwjKHE"
< Date: Tue, 03 Dec 2019 14:15:52 GMT
< Connection: keep-alive
<
* Connection #0 to host localhost left intact
Hello World!%

プロジェクトをデプロイする

例によってapp.yamlを作成する。 今回はdefaultのサービスではなく、サブシステムとなるapisserviceに指定する。

> echo '
service: apis
runtime: nodejs10
' > app.yaml

apisディレクトリでデプロイコマンドを実行する。 以下のようにターゲットが表示されるので、問題なければyで実行。 target urlhttps://apis-dot-astral-web-260712.appspot.comになっていることに注目。

> gcloud app deploy
Services to deploy:

descriptor:      [/Users/mizuki/workspace/20191203-example-appengine/apis/app.yaml]
source:          [/Users/mizuki/workspace/20191203-example-appengine/apis]
target project:  [astral-web-260712]
target service:  [apis]
target version:  [20191203t232045]
target url:      [https://apis-dot-astral-web-260712.appspot.com]


Do you want to continue (Y/n)?  y

Beginning deployment of service [apis]...
Created .gcloudignore file. See `gcloud topic gcloudignore` for details.
╔════════════════════════════════════════════════════════════╗
╠═ Uploading 29 files to Google Cloud Storage               ═╣
╚════════════════════════════════════════════════════════════╝
File upload done.
Updating service [apis]...done.
Setting traffic split for service [apis]...done.
Deployed service [apis] to [https://apis-dot-astral-web-260712.appspot.com]

You can stream logs from the command line by running:
  $ gcloud app logs tail -s apis

To view your application in the web browser run:
  $ gcloud app browse -s apis

さー、デプロイできたぞー、と思ったがーー

> curl https://apis-dot-astral-web-260712.appspot.com

<html><head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>500 Server Error</title>
</head>
<body text=#000000 bgcolor=#ffffff>
<h1>Error: Server Error</h1>
<h2>The server encountered an error and could not complete your request.<p>Please try again in 30 seconds.</h2>
<h2></h2>
</body></html>

ーーなんかエラーになるな... 困ったときはとりあえずログを確認。-sでサービスを指定する。

> gcloud app logs tail -s apis
Waiting for new log entries...
2019-12-03 14:22:46 apis[20191203t232045]  "GET / HTTP/1.1" 500
2019-12-03 14:22:46 apis[20191203t232045]  sh: 1: exec: nest: not found
2019-12-03 14:22:48 apis[20191203t232045]  "GET /favicon.ico HTTP/1.1" 500
2019-12-03 14:22:49 apis[20191203t232045]  sh: 1: exec: nest: not found
2019-12-03 14:22:52 apis[20191203t232045]  "GET / HTTP/1.1" 500
2019-12-03 14:22:52 apis[20191203t232045]  sh: 1: exec: nest: not found
2019-12-03 14:22:52 apis[20191203t232045]  "GET /favicon.ico HTTP/1.1" 500
2019-12-03 14:22:53 apis[20191203t232045]  sh: 1: exec: nest: not found
2019-12-03 14:23:22 apis[20191203t232045]  "GET / HTTP/1.1" 500
2019-12-03 14:23:22 apis[20191203t232045]  sh: 1: exec: nest: not found

nest not foundらしい... @nestjs/clidevDependenciesに含まれているため、インストールされないようだ。

npm startのコマンドからnestの依存を外す。

diff --git a/package.json b/package.json
index 6f344f7..01bd10c 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,7 @@
     "prebuild": "rimraf dist",
     "build": "nest build",
     "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
-    "start": "nest start",
+    "start": "npm run start:prod",
     "start:dev": "nest start --watch",
     "start:debug": "nest start --debug --watch",
     "start:prod": "node dist/main",

さあさ、デプロイデプロイっ

> gcloud app deploy
Services to deploy:

descriptor:      [/Users/mizuki/workspace/20191203-example-appengine/apis/app.yaml]
source:          [/Users/mizuki/workspace/20191203-example-appengine/apis]
target project:  [astral-web-260712]
target service:  [apis]
target version:  [20191203t233112]
target url:      [https://apis-dot-astral-web-260712.appspot.com]


Do you want to continue (Y/n)?  y

Beginning deployment of service [apis]...
╔════════════════════════════════════════════════════════════╗
╠═ Uploading 1 file to Google Cloud Storage                 ═╣
╚════════════════════════════════════════════════════════════╝
File upload done.
Updating service [apis]...done.
Setting traffic split for service [apis]...done.
Deployed service [apis] to [https://apis-dot-astral-web-260712.appspot.com]

You can stream logs from the command line by running:
  $ gcloud app logs tail -s apis

To view your application in the web browser run:
  $ gcloud app browse -s apis

ログを起動しとく

> gcloud app logs tail -s apis
2019-12-03 14:33:24 apis[20191203t233112]
2019-12-03 14:33:24 apis[20191203t233112]  > apis@0.0.1 start:prod /srv
2019-12-03 14:33:24 apis[20191203t233112]  > node dist/main
2019-12-03 14:33:24 apis[20191203t233112]
2019-12-03 14:33:25 apis[20191203t233112]  [Nest] 28   - 12/03/2019, 2:33:25 PM   [NestFactory] Starting Nest application...
2019-12-03 14:33:25 apis[20191203t233112]  [Nest] 28   - 12/03/2019, 2:33:25 PM   [InstanceLoader] AppModule dependencies initialized +21ms
2019-12-03 14:33:25 apis[20191203t233112]  [Nest] 28   - 12/03/2019, 2:33:25 PM   [RoutesResolver] AppController {/}: +6ms
2019-12-03 14:33:25 apis[20191203t233112]  [Nest] 28   - 12/03/2019, 2:33:25 PM   [RouterExplorer] Mapped {/, GET} route +3ms
2019-12-03 14:33:25 apis[20191203t233112]  [Nest] 28   - 12/03/2019, 2:33:25 PM   [NestApplication] Nest application successfully started +3ms

満を持してcurlを叩くーー

> curl https://apis-dot-astral-web-260712.appspot.com

ーーが、レスポンスが帰ってこない!なんぞ!? 首をかしげながら考える私。 んー通信出来へんてこたぁサービス起動してへんのかな? やー、ゆうてもログでは起動しるやん?

... ... ...あっ 唐突に思いつく私。

diff --git a/src/main.ts b/src/main.ts
index 13cad38..7357152 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -3,6 +3,6 @@ import { AppModule } from './app.module';

 async function bootstrap() {
   const app = await NestFactory.create(AppModule);
-  await app.listen(3000);
+  await app.listen(Number(process.env.PORT) || 3000);
 }
 bootstrap();

あー

> npm run build
> gcloud app deploy

ああー

> gcloud app logs tail -s apis
2019-12-03 14:40:25 apis[20191203t233845]  > apis@0.0.1 start:prod /srv
2019-12-03 14:40:25 apis[20191203t233845]  > node dist/main
2019-12-03 14:40:25 apis[20191203t233845]
2019-12-03 14:40:27 apis[20191203t233845]  [Nest] 28   - 12/03/2019, 2:40:27 PM   [NestFactory] Starting Nest application...
2019-12-03 14:40:27 apis[20191203t233845]  [Nest] 28   - 12/03/2019, 2:40:27 PM   [InstanceLoader] AppModule dependencies initialized +23ms
2019-12-03 14:40:27 apis[20191203t233845]  [Nest] 28   - 12/03/2019, 2:40:27 PM   [RoutesResolver] AppController {/}: +7ms
2019-12-03 14:40:27 apis[20191203t233845]  [Nest] 28   - 12/03/2019, 2:40:27 PM   [RouterExplorer] Mapped {/, GET} route +25ms
2019-12-03 14:40:27 apis[20191203t233845]  [Nest] 28   - 12/03/2019, 2:40:27 PM   [NestApplication] Nest application successfully started +3ms

あ〜〜〜〜〜〜〜

> curl https://apis-dot-astral-web-260712.appspot.comHello World!%

まとめ

AppEngineかんたんでとてもわかり易いですね!!!!!

次回予告

サービス2つ作っただけじゃね? 明日は連携できるようにコード書きます!がんばります!