7/4/2015 - 10:29 PM

Deploying NodeJS App on Google Cloud Platform

Deploying NodeJS App on Google Cloud Platform

# Deploying NodeJS App on Google Cloud Platform

`authored Jul 3 2015 by kengz`

## Installation
- Account with Google Cloud Platform.
- Install [Google Cloud Platform SDK]( to use `cloud` in the terminal.
- Install [Docker]( for the VM container.
- Locally, login for the first time: `gcloud auth login`

## Deployment
- Create and enable billing for a project in [Google Developers Console]( Name the project and remember the *Project ID* for use in `gcloud`. Say it is *appid-123*.
- Have your NodeJS app, say in the folder *coolapp*, with entry point `app.js`.

### Ingredients
We will deploy by building a custom runtime using Google Compute Engine, borrowing presets from Google App Engine.

Go into your project root directory, and add these files:

- `Dockerfile` for the VM to use nodejs runtime

# [START docker]
FROM google/nodejs-runtime
# [END docker]

- `app.yaml` to configure the GCE VM. [Details here](, also more [examples (in Python, but relevant)](

Below, `runtime: custom` and `vm: true` are required to run GCE VM with *Custom Runtimes*. See further below on *behind the scene*.

# [START runtime]
runtime: custom
vm: true
api_version: 1
module: default
# [END runtime]

# [START resources]
  cpu: .5
  memory_gb: 1.3
  disk_size_gb: 10
# [END resources]

# [START scaling]
  min_num_instances: 1
  max_num_instances: 3
  cool_down_period_sec: 60
    target_utilization: 0.5
# [END scaling]

  NODE_ENV: production

- `.dockerignore` to list files to keep away from deployment.


#### Pre-deploy
**Every time** when you do things with gcloud, you have to: 

- set the current project in gcloud

gcloud config list
gcloud config set project appid-123

- Initialize and set the VM environment for *Docker*

boot2docker up
eval "$(boot2docker shellinit)"

#### Deploy

gcloud preview app deploy app.yaml --set-default

This will take minutes if it's the first deployment of the project. Consecutive deployments should be faster because it seems that they build off the existing one by checking only the differences. Note that each deployment creates a new VM instance, and no you cannot modify a VM instance. Just redeploy and delete the old ones (see below).

The `--set-default` tag sets this to the *IS_DEFAULT* version of the module, so it will be the one running out of many deployed VMs.

**Known bug**: sometimes it just hangs at `Building and pushing image for module [default]` for a really long time. You can cancel it, and any following deployments will experience the same issue. To *solve it*, just restart your computer. The exact cause is not known, but restarting seems to reset some configs in *gcloud/Docker* that cause the issue.

See *behind the scene* below.

#### Post-deploy

You can monitor all your VM instances on GCE by 

gcloud compute instances list

With the tweaks above you need to do some things differently. Say you update your app and want to deploy the latest version. You have to rerun the command above to deploy a new VM instance; you can't access and reconfigure an existing one easily. Yet, as noted above, deploying a new one is good enough since it's fast and it builds off the previous by checking only differences.

To **delete** a VM instance you cannot do it normally from the terminal. Just do it from the [Google Developer Console]( select your project, under *Compute > Compute Engine*, select the instances to delete.

You may also need to go under *App Engine > Instances / Versions* to delete.

#### Port-settings and Versions
The [VM manual page]( says:

>Incoming HTTP requests for your application will be routed to port 8080. It is the responsibility of the container to interpret these requests and route them appropriately.

You'll need to enable the port and set the correct default version for your app to work. Do this from the *Google Developer Console*. 

Your app might be called on a different port, say 1234. First, go to *Compute Engine > Networks > default* to add a firewall rule for your port (the target tag must be blank). Now the port is opened, and all calls to it will be forwarded to 8080.

Next, make sure your deployed version IS_DEFAULT (it should be with the --set-default tag when deploying). Go to *App Engine > Versions* and select a proper deployed version (number from when you deployed from the terminal) to be the default.

Alternatively, do it from the terminal by looking up the version for the module first,

gcloud preview app modules list

which returns something like

default  20150704t180104  *
default  20150704t183125  -

Set the new IS_DEFAULT version and delete the old:

gcloud preview app modules set-default default --version 20150704t183125
gcloud preview app modules delete default --version 20150704t180104

## Behind the scene

Google Cloud Platform houses over 10 products, which are all integrated. The products relevant to us now are *Google Compute Engine (GCE)* and *Google App Engine (GAE)*. Google also hosts Git now, called *Cloud Source Repositories (CSR)*, and is a direct competitor of Github.

GAE and CSR can be integrated; you push to CSR, your code gets built, tested, and deployed onto GAE and voila, you have your app running automatically. This is very much like pushing to Github and auto-deploy to Heroku. However for now, GAE supports only Python, Java, PHP, Go; so the magic above won't work for anything else.

Other languages will have to use GCE, which is basically raw VMs for you to play with. You can create a VM instance, SSH into it, and install Node etc. manually. However Google introduced *Custom Runtimes* which saves you from doing these.

With *Custom Runtimes*, you specify the extra files to, well, host a custom runtime. So, when you deploy, GCE allocates a VM instance for you (with Debian/Linux installed), and Docker pulls some stuff from GAE and from google/nodejs-runtime to create a Container within the VM, so it will run Node. Voila, your app is now deployed, just as magical.

Basically, you get a mix of GCE calling GAE with Docker, and it gets done.

## Handy terminal aliases
Save these aliases into your `.bash_profile` for an easier life.

### gcloud
# set env for boot2docker each time
alias boot2eval='boot2docker up; eval "$(boot2docker shellinit)"'
# list all the projects
alias glist='gcloud config list'
# set project to a valid one. e.g. gset appid-123
alias gset='gcloud config set project'
# deploy your app module and set as IS_DEFAULT. e.g. gdeploy app.yaml
_deploy() {
	gcloud preview app deploy $1 --set-default
alias gdeploy=_deploy
# see the VM instances of your project
alias ginstances='gcloud compute instances list'
# list modules
alias glistmod='gcloud preview app modules list'
# set the new IS_DEFAULT version of a module
alias gsetdefault='gcloud preview app modules set-default default --version'
# set the new IS_DEFAULT version of a module
alias grmdefault='gcloud preview app modules delete default --version'

More reference on [Command-Line Tool Guide (gcloud)](