GoogleクラウドのPaaS「App Engine」を使ってオートスケールするWebサーバーをNode.jsで書いてみた

Googleが提供している「Google App Engine」は、PaaS(Platform as a Service)に分類されるクラウドサービスで、サーバーなどのインフラ設定を何もしなくてもアクセス数に応じてスケールするアプリケーションを設置できるサービスです。このGoogle App Engineの標準環境が2018年6月にNode.jsに対応したとのことで、早速Node.jsを使ってWebサーバーを設置してみました。なお、今回はmacOSを使用していますが、Windowsでも同様の手順でサーバーを設置できます。
App Engine - Build Scalable Web & Mobile Backends in Any Language | App Engine | Google Cloud
https://cloud.google.com/appengine/
まずNode.jsがインストールされていない場合は公式サイトからLTS版をダウンロードしてインストールしておきます。
Node.js
https://nodejs.org/ja/

そしてプログラミング用のエディタを用意します。どんなエディタでも大丈夫ですが、今回は「Visual Studio Code」を使用します。画面左側にある緑のボタンをクリックするとダウンロードできます。

ダウンロードしたファイルを実行してVisual Studio Codeをインストールし、起動すると下の画面になります。「ワークスペース フォルダーを追加」をクリックします。

「nodeWebServer」という名前でフォルダを作成し、「追加」をクリックします。

左のカラム一番上の「エクスプローラー」の「ワークスペース」に先ほどのフォルダが追加されるので、右クリックして表示されるメニューから「ターミナルで開く」をクリックします。

すると右下に「ターミナル」が表示されます。ターミナルが「nodeWebServer」を開いていることを確認して
npm init -y
と入力します。この「npm」はnode.jsと同時にインストールされるnode.js用のパッケージ管理ツールのことです。「npm init」というコマンドを入力するとnpmに初期化動作(initialize)をさせ、パッケージ管理用のコードである「package.json」を生成させることができます。本来は対話形式でどのようなコードなのかの説明を書いていくのですが、「-y」オプションをつけることで全てデフォルトのままの設定でpackage.jsonを生成することができます。

続いてサーバーのセットアップを超簡単にしてくれるパッケージの「express」をインストールします。
npm install express
と入力するとnodeWebServerの下に「node_modules」というフォルダが生成され、そこにexpressとそれを動かすためのライブラリがインストールされます。また、同時に生成される「package-lock.json」はライブラリのバージョンを記録するためのコードで、他人とコードを共有する際にこのpackage-lock.jsonを渡せばどのライブラリのどのバージョンを使えば良いのかが一発で理解できるようになっています。

続いてサーバー本体のコードを書いていきます。「nodeWebServer」フォルダに「app.js」というファイルを作成します。

ExpressのHello Worldコードを参考にして、app.jsに以下のようなコードを書いてみました。
/** * expressライブラリをインポートします。 */ var express = require("express"); /** * インスタンス化してappに代入します。 */ var app = express(); /** * HTTPリクエストメソッドが'get'の場合の返答を書きます。 */ app.get('/', function(req, res) { res.send('Hello World!'); }); /** * ポート3000で接続を待ち受けます。 */ app.listen(3000, function() { console.log('App listening on port 3000'); });
app.jsにコードを入力したらターミナルに
node app.js
と入力してnode.jsでapp.jsを実行します。

http://localhost:3000/にアクセスしてみると無事、「Hello World!」が表示されました。なお、動いているアプリを終了する際にはターミナル上で「Ctrl+C」と入力します。

今回はexpressの詳細な仕様には立ち入らず、この簡単な「Hello World!」を表示するアプリをGoogle App Engineにデプロイしてみます。Google App Engineを使用するにはGoogleのクラウドサービスであるGoogle Cloud Platformに登録する必要があるので、まだ登録していないという人は以下の記事の冒頭部分を参考に登録しておいてください。
無料でGoogleのクラウド上にマインクラフトのサーバーを立てて複数人でマルチプレイする方法 - GIGAZINE

続いてGoogle Cloud Platformを管理するためのツール「Cloud Tools」をインストールします。自分のOSを選択し、「Cloud SDKのインストーラ」をダウンロードして実行します。

Cloud ToolsがインストールできたらいよいよアプリをGoogle App Engineにデプロイするための設定をしていきます。まず先ほど作成したapp.jsについてなのですが、App Engine上で動かす際にはどのポート番号を使えば良いのかがはっきりと定まらないため、「どのような環境で動いているのか」という情報が入った「process.env」という環境変数を使用するように書き換えます。こうすることでApp Engine上で動作するサーバーが適切なポートで待ち受けることができ、ちゃんとアクセスできるようになります。
/** * ポート3000で接続を待ち受けます。 */ app.listen(3000, function() { console.log('App listening on port 3000'); });
↓↓↓
/** * 環境変数「PORT」が設定されていればその番号、 * されていなければポート3000で接続を待ち受けます。 */ app.listen(process.env.PORT || 3000, function() { console.log('App listening on port 3000'); });
次にGoogle App Engineでどのように動作させるのかという設定ファイルである「app.yaml」を作成していきます。app.jsと同じフォルダに「app.yaml」を作成し、以下のように書き加えます。
runtime: nodejs8
Cloud Toolsをインストールしたおかげで「gcloud」というコマンドが使用できるようになるので、ターミナルで
gcloud app deploy
と入力してエンターキーを押します。以下のような確認のダイアログが出るので、確認して「y」と入力するとアプリがデプロイされます。

デプロイが完了したら、
gcloud app browse
と入力するとデプロイ先のページが表示されます。「Hello World!」と表示されていれば成功だったのですが、なぜかエラーが表示されてしまいました。

App Engine内部でどのようなエラーが起きているのかについてはApp Engineのダッシュボード下部で確認できます。

エラーメッセージは以下の通り。大抵はこのエラーメッセージをGoogleで検索するだけでなんとかなるのですが、今回は何もヒットしなかったので自力で調べます。
Error: Cannot find module '/srv/server.js' Function.Module._resolveFilename (module.js)
色々実験してみたところ、どうやらpackage.jsonの「scripts」の部分を、
"scripts": { "test": "echo \"Error: no test specified\" && exit 1" },
から以下のように書き換える必要があるようです。
"scripts": { "start": "node app.js" },
package.jsonのscriptsを修正したら再びターミナルに
gcloud app deploy
と入力してデプロイし直します。先ほど
gcloud app browse
で開いていたページをリロードするときちんと「Hello World!」が表示されました。

こうしてGoogle App Engineにデプロイしたサーバーはアクセス数に応じて自動でスケールするようになっており、そのスケーリングに応じて料金が発生します。実装を間違えるなどしてしまった際に大金を請求されないようにするには左の「設定」タブから……

「1日の使用量上限」を設定すればOKです。

・関連記事
Webサイトのクローリングやスクリーンショット撮影が簡単にできるヘッドレスChromeがGCPに登場 - GIGAZINE
超お手軽にペアプログラミングも可能なプログラミング環境が構築できるAWSの「Cloud9」を使ってみた - GIGAZINE
Lighthouseで満点を獲得したハイパーパフォーマンスのサイトのコードがGithubで公開中 - GIGAZINE
30代後半や50代からでもソフトウェア開発者になるのには遅くないという10人の実例 - GIGAZINE
エンジニアの能力の高さと学歴の間には何の関係もないことが判明 - GIGAZINE
世界各地に散らばったエンジニアをまとめ上げる方法 - GIGAZINE
・関連コンテンツ
in ソフトウェア, ネットサービス, ウェブアプリ, Posted by log1d_ts
You can read the machine translated English article I tried to autoscale Web server with Nod….