Google App Engine を安く Node.js で使う

# **重要な追記**

2017年3月に GCE の無料枠が拡大され、[f1-micro インスタンスが無料枠に入りました](https://cloud.google.com/free/)。

しかし GAE の仕様変更もあり、**この記事の方法は既に陳腐化しています**。例えば `vm: true` は deprecated で、 `env: flex` とする必要があります。

また、この記事の方法でマシンタイプを極小にしようとしても、小さすぎる指定がエラーになるようになってしまいました。このあたりは [app.yaml のリファレンス](https://cloud.google.com/appengine/docs/flexible/nodejs/configuring-your-app-with-app-yaml)に詳しいです。

色々試してみましたが、エラーを避けつつ f1-micro インスタンスで起動する方法は見つかりませんでした。

一方で、2016年6月頃にこの記事の方法でデプロイしたアプリケーションは f1-micro で動き続けており、課金額もほぼ無料になっていました。

以下の内容は2016年6月時点のものとしてお読みください。

# tl;dr

~~無料で~~可能な限り安く Node.js アプリを動かしたい！！！！ので `app.yaml` を書きなおした。

# 先人の知恵

- [Google App Engineを無料で運用する方法（2016年版） - koni blog](http://koni.hateblo.jp/entry/2016/01/06/130613)

# しかし

先人の知恵そのままに Node.js アプリをデプロイしようとすると

```
ERROR: (gcloud.preview.app.deploy) Error Response: [400] VM-based automatic scaling should NOT have the following parameter(s): [min_pending_latency, max_idle_instances]
```

と怒られてしまった。どうやら言語によって `app.yaml` に定義すべき内容の仕様が微妙に違うらしい。

- こちらは PHP [app.yaml Reference  |  PHP  |  Google Cloud Platform](https://cloud.google.com/appengine/docs/php/config/appref)
- こちらは Node.js [Configuring your App with app.yaml  |  App Engine flexible environment for Node.js docs  |  Google Cloud Platform](https://cloud.google.com/appengine/docs/flexible/nodejs/configuring-your-app-with-app-yaml)

`automatic_scaling` まわりの設定項目が異なるのをおわかりいただけるだろうか……

調べてみると、 GAE for Node.js は Python や PHP のそれらと違った仕組みで動いているらしい。

> 既存のPythonやGoランタイムとは違って、利用できるのはApp Engine上の真のPaaSではない。代わりに、Node.jsは彼らの[App Engine「flexible environment」](https://cloud.google.com/appengine/docs/flexible/)内で実行される。このflexible environmentは、[Google Compute Engine](https://cloud.google.com/compute/)上に構築されたManaged VMに基づいている。

（[Google App EngineでNode.jsのベータ版が利用可能に](https://www.infoq.com/jp/news/2016/03/nodejs-google-app-engine) より引用）

つまり、 GAE for Node.js は実質 GAE に見せかけて GCE で動いている。言い換えると、  **GAE for Node.js は無料枠（[28 インスタンス時間 / 日](https://cloud.google.com/appengine/docs/quotas#Instances)）を使うことができない**。現実は残酷である。

# ならば

Node.js 用の仕様に沿ってケチケチに設定する必要がある。

PHP や Python では使用するインスタンスクラスを `app.yaml` で明示的に指定でき、そのデフォルト値は最小インスタンスである `f1-micro` を含む `F1` になっている。

これに対し、Node.js （というか前述の Managed VM 環境）では [`cpu` と `memory_gb` の値を指定](https://cloud.google.com/appengine/docs/flexible/nodejs/configuring-your-app-with-app-yaml#resource-settings)し、その設定に応じて自動的にインスタンスクラスが選択される。これらのデフォルト値はそれぞれ `.5` と `1.3` であり、このままでは `g1-small` が使用されてモリモリ課金されてしまう。 

`app.yaml` に設定するリソース容量は**アプリケーションが使用できるリソース容量**と思われ、インスタンスのスペックのギリギリ下だと一段階上のインスタンスが選択されてしまう。従って、 `f1-micro` のスペックを**大幅に下回るように**設定する。

- [Setting f1-micro resource limits in app.yaml for google cloud compute node.js app without vm_settings - Stack Overflow](http://stackoverflow.com/questions/31273834/setting-f1-micro-resource-limits-in-app-yaml-for-google-cloud-compute-node-js-ap)

# そして

試行錯誤の結果、このような `app.yaml` になり、つつがなく `f1-micro` で動くようになった。最高！！！！！！

```yaml:app.yaml
runtime: nodejs
vm: true
skip_files:
  - ^(.*/)?.*/node_modules/.*$
threadsafe: true
automatic_scaling:
  min_num_instances: 1
  max_num_instances: 2
  cool_down_period_sec: 60
  cpu_utilization:
    target_utilization: .7
resources:
  cpu: .2
  memory_gb: .15
```

しかし無料枠はお預け。現実は無情である。