Last active
December 8, 2019 18:56
-
-
Save kengz/c8d59ff0697bb00f71e1 to your computer and use it in GitHub Desktop.
Deploying NodeJS App on Google Cloud Platform
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Deploying NodeJS App on Google Cloud Platform | |
`authored Jul 3 2015 by kengz` | |
## Installation | |
- Account with Google Cloud Platform. | |
- Install [Google Cloud Platform SDK](https://cloud.google.com/sdk/) to use `cloud` in the terminal. | |
- Install [Docker](https://cloud.google.com/tutorials/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](https://console.developers.google.com/). 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](https://cloud.google.com/appengine/docs/managed-vms/config), also more [examples (in Python, but relevant)](https://cloud.google.com/appengine/docs/python/config/appconfig). | |
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](https://console.developers.google.com/): 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](https://cloud.google.com/appengine/docs/managed-vms/config) 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)](https://cloud.google.com/sdk/gcloud/reference/). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment