Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save reimertz/9177ad66e1aae492aa238c0a85f52228 to your computer and use it in GitHub Desktop.
Save reimertz/9177ad66e1aae492aa238c0a85f52228 to your computer and use it in GitHub Desktop.
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]

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]
resources:
  cpu: .5
  memory_gb: 1.3
  disk_size_gb: 10
# [END resources]

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

env_variables:
  NODE_ENV: production
  • .dockerignore to list files to keep away from deployment.
node_modules
*.log

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

MODULE   VERSION          IS_DEFAULT
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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment