Running the Node.js Bookshelf on Container Engine

This tutorial shows how to run the Node.js Bookshelf Application on Google Container Engine. Follow this tutorial to containerize and deploy an existing Node.js web application to Container Engine. You don't have to be familiar with the Bookshelf application to follow this tutorial, but if you would like to learn more, you can follow the tutorial for App Engine Flexible.

Objectives

  • Create a Container Engine cluster.
  • Containerize a Node.js application.
  • Create a replicated front end for the Bookshelf application.
  • Create a replicated back end for the Bookshelf application.
  • Create a load-balanced service to route HTTP traffic to the Bookshelf front end.

Costs

This tutorial uses billable components of Cloud Platform, including:

  • Google Container Engine
  • Google Compute Engine
  • Google Cloud Storage
  • Google Cloud Datastore
  • Google Cloud Pub/Sub

Use the Pricing Calculator to generate a cost estimate based on your projected usage. New Cloud Platform users might be eligible for a free trial.

Before you begin

  1. Sign in to your Google account.

    If you don't already have one, sign up for a new account.

  2. Select or create a Cloud Platform project.

    Go to the Projects page

  3. Enable billing for your project.

    Enable billing

  4. Enable the Cloud Datastore, Cloud Storage, and Cloud Pub/Sub APIs.

    Enable the APIs

  5. Install and initialize the Cloud SDK.
  6. Install the kubectl command line tool. You can install it with the Cloud SDK:
    gcloud components install kubectl
  7. Install Docker. Docker is used to build container images locally.

Creating a Container Engine cluster

A Container Engine cluster is a managed set of Compute Engine virtual machines that operate as a single Kubernetes cluster. This tutorial needs a cluster with a minimum of two nodes, and these nodes will need access to all Google APIs.

  1. Create the cluster:

    gcloud container clusters create bookshelf \
        --scopes "cloud-platform" \
        --num-nodes 2
    
  2. Verify that you have access to the cluster:

    kubectl get nodes
    

    Running this command lists the nodes in your container cluster and indicates that your container cluster is up and running and you have access to it.

You'll use the kubectl command to create resources in a Container Engine Cluster. To learn more about kubectl, see Container Engine Cluster Operations. In general, you'll use gcloud to manage resources in your Google Cloud project and you'll use kubectl to manage resources within your Container Engine cluster. A single project can have multiple clusters, which makes it easy to have clusters that are made up of different machine types to satisfy different needs. When you create a cluster with gcloud it will automatically set up authentication for kubectl.

Cloning the sample application

The sample application is available on GitHub at GoogleCloudPlatform/nodejs-getting-started.

  1. Clone the repository:

    git clone https://github.com/GoogleCloudPlatform/nodejs-getting-started.git
    
  2. Navigate to the sample directory:

    cd nodejs-getting-started/optional-container-engine
    

Initializing Datastore

The Bookshelf application uses Cloud Datastore to store the books. To initialize Datastore in your project for the first time:

  1. Open the Datastore on Cloud Platform Console.

  2. Select a region for your Datastore and click Continue. When you reach the “Create an Entity” page, you can close the window as the Bookshelf application is ready to create entities on Datastore.

Creating a Cloud Storage bucket

The Bookshelf application uses Google Cloud Storage to store image files.

The following instructions show how to create a Cloud Storage bucket.

To create a bucket:

  1. Invoke the following command in a terminal window:

    gsutil mb gs://[YOUR-BUCKET-NAME]

  2. Set the bucket's default ACL to public-read, which enables users to see their uploaded images:

    gsutil defacl set public-read gs://[YOUR-BUCKET-NAME]

Configuring the application

In the sample directory, create a config.json file with this content:

{
  "GCLOUD_PROJECT": "[YOUR_PROJECT_ID]",
  "CLOUD_BUCKET": "[YOUR_CLOUD_BUCKET]",
  "DATA_BACKEND": "datastore"
}

Replace [YOUR_PROJECT_ID] with your project ID and [YOUR_CLOUD_BUCKET] with the name of your Cloud Storage Bucket.

Containerizing the application

The sample application includes a Dockerfile, which is used create the application's Docker image. This Docker image is used to run the application on Container Engine.

# Dockerfile extending the generic Node image with application files for a
# single application.
FROM gcr.io/google_appengine/nodejs
# Check to see if the the version included in the base runtime satisfies
# '>=0.12.7', if not then do an npm install of the latest available
# version that satisfies it.
RUN /usr/local/bin/install_node '>=0.12.7'
COPY . /app/
# You have to specify "--unsafe-perm" with npm install
# when running as root.  Failing to do this can cause
# install to appear to succeed even if a preinstall
# script fails, and may have other adverse consequences
# as well.
# This command will also cat the npm-debug.log file after the
# build, if it exists.
RUN npm install --unsafe-perm || \
  ((if [ -f npm-debug.log ]; then \
      cat npm-debug.log; \
    fi) && false)
CMD npm start
The sample application also includes a .dockerignore file that lists filepaths that will not be included in the resulting Docker container. Typically, this includes build artifacts and local dependency installations.

# Copyright 2015 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

node_modules
.dockerignore
Dockerfile
npm-debug.log
.git
.hg
.svn

Build the application's Docker image:

docker build -t gcr.io/[YOUR_PROJECT_ID]/bookshelf .

Push the image to Google Container Registry so that your cluster can access the image:

gcloud docker -- push gcr.io/[YOUR_PROJECT_ID]/bookshelf

Deploying the Bookshelf front end

The Bookshelf application has a front end server that handles the web requests and a backend worker that processes books and adds additional information.

The cluster resources needed to run the front end are defined in bookshelf-frontend.yaml. These resources are described as a Kubernetes Deployment. Deployments make it easy to create and update a replica set and its associated pods.

# Copyright 2016 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License

# This file configures the bookshelf application frontend. The frontend serves
# public web traffic.

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: bookshelf-frontend
  labels:
    app: bookshelf
# The bookshelf frontend replica set ensures that at least 3
# instances of the bookshelf app are running on the cluster.
# For more info about Pods see:
#   https://cloud.google.com/container-engine/docs/pods/
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: bookshelf
        tier: frontend
    spec:
      containers:
      - name: bookshelf-app
        # Replace [GCLOUD_PROJECT] with your project ID or use `make template`.
        image: gcr.io/[GCLOUD_PROJECT]/bookshelf
        # This setting makes nodes pull the docker image every time before
        # starting the pod. This is useful when debugging, but should be turned
        # off in production.
        imagePullPolicy: Always
        # The bookshelf process listens on port 8080 for web traffic by default.
        ports:
        - name: http-server
          containerPort: 8080
  1. In bookshelf-frontend.yaml, replace [GCLOUD_PROJECT] with your project ID.
  2. Use kubectl to deploy the resources to the cluster:

    kubectl create -f bookshelf-frontend.yaml
    
  3. Track the status of the deployment:

    kubectl get deployments
    

    Once the deployment has the same number of available pods as desired pods, the deployment is complete. If you run into issues with the deployment, you can delete it and start over:

    kubectl delete deployments bookshelf-frontend
    
  4. Once the deployment is complete you can see the pods that the deployment created:

    kubectl get pods
    

Deploying the Bookshelf back end

The Bookshelf back end is deployed the same way as the front end.

# Copyright 2016 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License

# This file configures the bookshelf task worker. The worker is responsible
# for processing book requests and updating book information.

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: bookshelf-worker
  labels:
    app: bookshelf
# The bookshelf worker replica set ensures that at least 2 instances of the
# bookshelf worker pod are running on the cluster.
# For more info about Pods see:
#   https://cloud.google.com/container-engine/docs/pods/
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: bookshelf
        tier: worker
    spec:
      containers:
      - name: bookshelf-app
        # Replace [GCLOUD_PROJECT] with your project ID or use `make template`.
        image: gcr.io/[GCLOUD_PROJECT]/bookshelf
        # This setting makes nodes pull the docker image every time before
        # starting the pod. This is useful when debugging, but should be turned
        # off in production.
        imagePullPolicy: Always
        # The SCRIPT environment variable is used by `npm start` to control
        # which script is executed. This tells npm start to use `worker.js`
        # instead of the default `app.js`.
        env:
        - name: SCRIPT
          value: worker.js
  1. In bookshelf-worker.yaml, replace [GCLOUD_PROJECT] with your project ID.
  2. Use kubectl to deploy the resources to the cluster:

    kubectl create -f bookshelf-worker.yaml
    
  3. Verify that the pods are running:

    kubectl get pods
    

Creating the Bookshelf service

Kubernetes Services are used to provide a single point of access to a set of pods. While it's possible to access a single pod, pods are ephemeral and it's usually more convenient to address a set of pods with a single endpoint. In the Bookshelf application, The Bookshelf service allows you to access the Bookshelf frontend pods from a single IP address. This service is defined in bookshelf-service.yaml

# Copyright 2016 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License

# The bookshelf service provides a load-balancing proxy over the bookshelf
# frontend pods. By specifying the type as a 'LoadBalancer', Container Engine
# will create an external HTTP load balancer.
# For more information about Services see:
#   https://cloud.google.com/container-engine/docs/services/
# For more information about external HTTP load balancing see:
#   https://cloud.google.com/container-engine/docs/load-balancer
apiVersion: v1
kind: Service
metadata:
  name: bookshelf-frontend
  labels:
    app: bookshelf
    tier: frontend
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: http-server
  selector:
    app: bookshelf
    tier: frontend

Notice that the pods and the service that uses the pods are separate. Kubernetes uses labels to select the pods that a service addresses. With labels, you can have a service that addresses pods from different replica sets and have multiple services that point to an individual pod.

  1. Create the Bookshelf service:

    kubectl create -f bookshelf-service.yaml
    
  2. Get the service's external IP address:

    kubectl describe service bookshelf
    

    Note that it may take up to 60 seconds for the IP address to be allocated. The external IP address will be listed under LoadBalancer Ingress.

Accessing the Bookshelf application

You have now deployed all the resources needed to run the Bookshelf application on Container Engine. Use the external IP address from the previous step to load the application in your web browser and create books. If you deployed the worker, the books will be automatically updated with information from the Google Books API.

Cleaning up

To avoid incurring charges to your Google Cloud Platform account for the resources used in this tutorial:

Deleting the project

The easiest way to eliminate billing is to delete the project you created for the tutorial.

To delete the project:

  1. In the Cloud Platform Console, go to the Projects page.

    Go to the Projects page

  2. In the project list, select the project you want to delete and click Delete project. After selecting the checkbox next to the project name, click
      Delete project
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

Deleting the cluster

Deleting the cluster removes all Container Engine and Compute Engine resources, but you need to manually remove any resources in Cloud Storage, Cloud Datastore, and Cloud Pub/Sub.

Public IP addresses, which are billable resources when not in use, and load balancing resources are not up when the cluster is deleted. To clean up these resources used by the Bookshelf service, run:

kubectl delete -f bookshelf-service.yaml

Then, delete the container cluster:

gcloud container clusters delete bookshelf

What's next

Monitor your resources on the go

Get the Google Cloud Console app to help you manage your projects.

Send feedback about...