Node.js microservices on Google App Engine

Taras Mankovski
This Dot Labs
Published in
6 min readJan 15, 2017

I spent the last three years doing exclusively frontend development with Ember.js. In the meantime, microservices became all the craze on the server land.

The difficulty of being a late adopter is that you have to learn everything right away to be able to use the tools effectively. On the bright side, many tools had time to go through a few iterations of improvements. Mature and better-integrated tooling makes learning much easier.

Google App Engine is one of the oldest PaaS providers. It’s backed by the Google Cloud which has an offering that’s very similar to Amazon AWS. GAE is the higher level abstraction over Google Cloud infrastructure that offers auto-scaling, managed deployment and microservices architecture.

GAE allows developers to compose complex applications from smaller microservices. Each microservice runs inside of it’s Docker container isolated from other microservices. A microservices driven application behaves like a regular web application. Between the user and the microservices sits a load balancer that routes user’s requests to a service for a particular URL.

This kind of architecture sounds amazing, very complicated and too difficult for most people to implement on their own. GAE gives all of this to you by default; you just need to know how to configure it.

I’m going to show you how to compose an app from multiple Node.js microservices. Before we begin, make sure to setup your computer by following Before you begin section on Quickstart for Node.js in the App Engine Flexible Environment page.

Part 1: Deploy main app to GAE

  1. Run gcloud init to sign in to Google Cloud on your command line.
  2. Create an empty directory with mkdir ~/node-microservices-example
  3. Go into the directory with cd ~/node-microservices-example
  4. Create a Google App Engine project with gcloud app create
  5. Initialize a Node.js project with npm init

So far, you’ll have a directory with only package.json in it. Next step is to modify your package.json to have all of the configurations that GAE needs to properly configure the app when it’s deployed.

6. Create server.js file. It’ll contain the code for the Node.js server that that’ll respond to all requests for this application.

7. Edit your package.json file to tell GAE how to start your server when it’s deployed. To do this, add start property to scripts hash.

{
...
"scripts": {
"start": "node server.js"
},
...
}

GAE uses node start command to start the server. This command looks for start script. node server.js will execute server.js with node executable.

8. Let’s tell GAE to use Node.js 6 to run our server by specifying engines property in package.json.

{
...
"engines": {
"node" : ">=6.0.0"
},
...
}

GAE uses app.yaml file as default entrypoint into your application. This file tells GAE the runtime to use for the project and the environment configuration.

9. Create app.yaml file with with nodejs runtime and flex environment.

runtime: nodejs
env: flex

10. Now, let’s create a simple express server in server.js that’ll respond to requests. Edit server.js and add the following code

"use strict"; const express = require('express'); const app = express(); app.get('/', (req, res) => {    
res.status(200).send('Hello world!');
});
app.listen(process.env.PORT);

On the last line of the script app.listen(process.env.PORT);, we’re allowing the environment to specify the port that our server should be listen for incoming requests. By default, GAE routes requests to port 8080 and this port will be automatically provided to your server.

11. Before we deploy our application, we have to make sure that our app has the dependencies that it needs to run our application. We used express package so we need to install run npm install --save express to add express package to the dependencies in package.json.

In addition to everything that was generated by npm init , your package.json must have the following entries in it.

{
"name": "node-microservices-example",
"scripts": {
"start": "node server.js"
},
"engines": {
"node": ">=6.0.0"
},
"dependencies": {
"express": "4.14.0"
}
}

12. Let’s deploy our app with gcloud app deploy.

13. After deploying you can see the result by running gcloud app browse. This will open the app in a browser.

Hello world! is displayed in the app

So far we deployed an application to Google App Engine. This it the first app in our group of microservices. GAE calls this the default service. This app is the catch all for everything that’s not handled by other microservices.

Let’s add a microservice that’ll be responsible for admin section of our application.

Part 2: Add first microservice

We’ll create a new service called admin and we’ll route all traffic from /admin to this service. Each microservice is a separate application with its own dependencies and an app.yaml file. Routing requests to this microservice is done by configuring dispatch.yaml in our main application(ie default service).

  1. Let’s begin by creating a directory for our admin service. This directory can be anywhere but we’ll put it inside of our node-microservices-example directory for convenience. mkdir ~/node-microservices-example/admin
  2. Your admin application has to be complete on it’s own. It must have a package.json file with it’s own start script, engines property and it’s own dependencies. Follow steps 5–8 from part 1 for directions.
  3. To tell GAE that you’re creating another service, you must provide a service name in the app.yaml file of your microservice.
env: flex
runtime: nodejs
service: admin

app.yaml does not need to be called app.yaml. You could call it admin.yaml as long as service: admin property is set, GAE will know that you’re deploying a microservice and not the default service. Using app.yaml makes it possible to run gcloud app deploy inside of admin directory and gcloud command will look for app.yaml automatically.

4. Create a server.js for the admin section.

"use strict"; const express = require('express'); const app = express(); app.get('/', (req, res) => {    
res.status(200).send('Admin Section');
});
app.listen(process.env.PORT);

5. We’re not done yet, but let’s deploy this service to see what happens. To deploy a microservice, you can run gcloud app deploy inside of the microservice’s directory or gcloud app deploy admin/app.yaml from main app’s directory.

6. If you run gcloud app browse -s admin, a browser window will open on a subdomain of your default service’s url. Every service automatically get’s a subdomain that can be accessed by going to the url.

7. We want our admin service to be accessible from /admin url instead of the subdomain. We can configure routing for our default app by creating a dispatch.yaml file.

dispatch:
- url: '*/admin'
module: admin

8. The dispatch configuration tells GAE how to route requests inside of your application. It doesn’t do any rewriting of urls. So our server must explicitely listen to requests on /admin. Let’s modify admin/server.js to handle /admin url.

"use strict";const express = require('express');const app = express();app.get('/admin', (req, res) => {    
res.status(200).send('Admin Section');
});
app.listen(process.env.PORT);

9. Let’s deploy our updated admin service and routing configuration by running gcloud app deploy admin/app.yaml dispatch.yaml

Now you have an app that is composed of two apps. The main app that’s served by the default service and admin app served by admin service. GAE will automatically handle routing requests from /admin url to the admin service and these services run in isolation from each other in their own containers.

Code for this application is available on GitHub. Follow me to learn more about building applications with Google App Engine.

Please, leave me a comment if you found this article useful. You can also tell me what you would like to learn next.

--

--