GCPのCloud Buildからnodejs8 on GAEを動かす時にはyarnでなくnpmを使おうというお話


Cloud Buildいいですよね。
今まではデプロイの自動化をしようとすると、CircleCIとか、werckerで同等機能を外部で用意するか、それともGCEでインスタンスを立ててとかやる必要があったんですが、GCP内でサーバレスで完結できるので構成がとてもシンプルにできます!
AWSだったらcode deployがあるのになぁと羨んでいたんですが、それも過去の話に

そんな便利なCloud Buildなんですが……cloud buildからnodejs8のソースをGAEにdeployする時にちょっとした罠っぽいものがあったので備忘録もかねて

問題のソース

package.json

{
  "name": "nodejs8-by-yarn",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "start": "node app.js"
  },
  "engines": {
    "node": "8.x.x"
  },
  "author": "",
  "license": "MIT",
  "dependencies": {
    "express": "*",
    "pug": "^2.0.3"
  }
}

yarn.lock

express@*:
  version "4.16.2"
  resolved "https://registry.yarnpkg.com/express/-/express-4.16.2.tgz#e35c6dfe2d64b7dca0a5cd4f21781be3299e076c"

cloudbuild.yaml

steps:
- name: 'gcr.io/cloud-builders/yarn'
  args: ['install']
- name: 'gcr.io/cloud-builders/gcloud'
  args: ['app', 'deploy', '--version', '1', 'app.yaml']

と、こういう構成になっています。
expressの最新版が4.16.2だった頃に*でinstallしたという設定のpackage.jsonです。
cloudbuildでもyarn installした後にデプロイしているので大丈夫そうですね。
(*でinstallするのはどうなんだろう? というのはあるんですが)

実際にアクセスしてみると

ローカルでの表示

サンプルページはこちら

あ…ありのまま今起こった事を話すぜ!
yarn.lockに書いて4.16.2をインストールしたと思ったのに、4.16.3がインストールされていた
な… 何を言っているのか わからねーと思うが おれも 何をされたのか わからなかった…
頭がどうにかなりそうだった… 催眠術だとか超スピードだとか そんなチャチなもんじゃあ 断じてねえ
もっと恐ろしいものの片鱗を 味わったぜ…

localからデプロイしてみる

頭がポルポル状態なので、まずはローカルの状態をデプロイしてみようと思います。

$ gcloud app deploy --project neko-tech-test --version 1 app.yaml

がっ……ダメっ……!
結果は変わらない……!

原因を調べてみる

という訳で原因を調べてみようと思います。
まず、localでgcloudコマンドを使ってdeployしようとすると、.gcloudignoreというファイルが作成されるので中を覗いてみると、node_modulesをdeployしないという設定になっているじゃないですか!

# Node.js dependencies:
node_modules/

確かにアップロードの速度がpython27 on GAEの場合と比べて明らかに早いのです。
python27の場合はpip installしたライブラリをlibディレクトリかどこかに追加した上でGAEにアップロードする必要があるのですが、そういったライブラリを全部含んだアップロードの速度とは思えない速さ!

つまり、nodejs8 on GAEをアップロードする時にはnode_modulesのディレクトリは除外されている……!

node_modulesのインストールはどこで実行されている?

つまり、node_modulesのインストールがどこで実行されているのか、ということになります。

と思ってcloud buildを見てみると……

nodejs8のruntimeをGAEにdeployした履歴が残っていました。
転送元が「-」になっているのが、対象の履歴になります!

中で何をしているのか

中で何をしているのかが気になるので見てみます。

Step #1 - "builder": INFO starting: build process for FTL image
Step #1 - "builder": INFO starting: rm_node_modules
Step #1 - "builder": INFO rm_node_modules rm -rf /workspace/node_modules
Step #1 - "builder": INFO `rm_node_modules` stdout:
Step #1 - "builder": 

Step #1 - "builder": INFO rm_node_modules rm -rf /workspace/node_modules

node_modulesを全て削除するという不穏な履歴が!
そしてこのままlogを読み進めてみると!

Step #1 - "builder": INFO npm_install npm install --production
Step #1 - "builder": INFO `npm_install` stdout:
Step #1 - "builder": added 113 packages in 5.001s
Step #1 - "builder": 
Step #1 - "builder": INFO `npm_install` had stderr output:
Step #1 - "builder": npm notice created a lockfile as package-lock.json. You should commit this file.

npm installでnode_modulesを用意し……package-lock.jsonがないよ!と警告を出されていました

まとめ

  • nodejs8のruntimeをGAEにdeployする時には、Google側のdeployの処理の段階でnpm installが走る
  • rm -rf /workspace/node_modulesも走る
  • なので、gcloud app deployをする前にyarnする必要はない
  • というか、yarn.lockではなくてpackage-lock.jsonで管理するようにしましょう

ということでした!!

最後に

株式会社ネコカリでは猫の手も借りたい🔥炎上中🔥なお仕事を募集しています!
一緒に働くメンバーも募集していますので、よかったら是非!