Application development with Bitnami Express container and VScode

Sameer Naik
Bitnami Perspectives
7 min readJun 13, 2017

Introduction

Express is a minimalist web application framework for Node.js. It’s a free and open-source framework released under the MIT License and is developed and maintained by the Node.js foundation.

In this post we’ll look at the workflow for developing an Express application using the Bitnami Express development container and Visual Studio Code. We’ll conclude by creating a Helm chart and deploy the application image to a Kubernetes cluster.

Prerequisites

The post requires that the reader has basic knowledge of developing applications with Express and Node.js. The Introduction to Express tutorial is a good resource to familiarize yourself with Express.

We use the Visual Studio Code (or VSCode) text editor for developing the application. Open-sourced by Microsoft; VSCode is a free and extensible text editor with a thriving marketplace for third party extensions. We will make use of the Docker and vs-helm extensions, please ensure you have these installed.

Bootstrapping an Express application

The Bitnami Express development container is engineered to provide a highly reproducible Node.js + Express runtime for development and production environments.

The GitHub repository provides a few Docker Compose files, pre-configured to get you started developing applications with the database backend of your choice. For our application we will use MongoDB for the application database.

To bootstrap a Express application create a directory named myapp and open it in VSCode. Next, use the VSCode shortcut Command+` to open a terminal and execute the following commands to download and launch the docker-compose.yaml.

$ curl -o docker-compose.yaml https://raw.githubusercontent.com/bitnami/bitnami-docker-express/master/docker-compose.yml
$ docker-compose up -d

The compose spec mounts the current working directory as a volume ( at the /app path) of the express container. The container sees that the /app directory is empty and uses express-generator to bootstrap a new express application. A Dockerfile is also generated which can be used to build a application image for production deployments.

Bootstrapping a Express application

The container detects that we want to use MongoDB as the database backend and will automatically add the mongodb npm module as a application dependency. Furthermore, thenodemon npm module is added as a development dependency. nodemon automatically restarts a node.js application whenever the application sources are updated.

Finally, the container will install the application development dependencies and start the express application.

With the Docker extension for VSCode, you can view the container logs by invoking the command from the command palette.

By default the application server listens on port 3000. Visit http://localhost:3000 in your web browser to access the express application.

To summarize, your current working directory now contains a bootstrapped Express application which is launched in a docker container using the Bitnami Express image and accessible at http://localhost:3000.

Develop your application

Let’s begin by changing the page title of the /indexroute to Hello Express. Edit the routes/index.js file as shown below:

Upon saving the changes, nodemon will automatically restart the Node.js application to apply your modifications. Refresh the web browser to view the changes:

Now, lets look at connecting to the MongoDB server from our application. The following snippet attempts a connection to the MongoDB server identified by the DATABASE_URL environment variable. This environment variable is added by the docker-compose.yaml file and its value addresses the MongoDB server running inside the MongoDB container. Modify the contents of routes/index.js so that it looks like the following snippet.

Next, edit views/index.jade as shown below, so that we can see the connection status with the MongoDB server,

Refresh the web browser after saving the changes and you should see the following page if the connection to the MongoDB server could be established successfully.

Installing NPM modules

Node packages (or modules) are bits of reusable code that can be downloaded and installed as application dependencies. The npm install command is used to add dependencies to a node.js application.

To install NPM modules use the docker-compose exec command to launch the npm install command. For example docker-compose exec myapp npm install underscore --save adds the popular underscore npm module as a application dependency.

Note: The myapp container may need to be restarted, using the command docker-compose restart myapp, for the installed NPM modules to be available to your application.

Creating a application Docker image

As you may recall the Bitnami Express container generates a Dockerfile in the application directory. Invoke the build from the command palette.

The Dockerfile copies the application source to the container and executes npm install to install the application dependencies. npm start is used to launch the application server.

The default NODE_ENV in the Dockerfile is set to production and using the SKIP_DB_WAIT, SKIP_DB_MIGRATION, SKIP_NPM_INSTALL and SKIP_BOWER_INSTALL environment variables the launch behaviour of the application image can be fine tuned. For our application we’re going to accept the default configuration.

Next, push the image to the Docker Hub,

Creating a production docker compose file

Using the existing docker-compose.yaml file as a template, create a docker-compose.prod.yaml file which uses the sameersbn/myapp:0.0.1 image as shown in the following snippet.

Unlike the docker-compose.yaml file used during the application development, the docker-compose.prod.yaml does not mount a volume at /app as the application source is copied into the image during the image build.

Deploy the application using the command docker-compose -f docker-compose.prod.yaml up and access the application at https://localhost:3000

Create a Helm Chart

Kubernetes is an open-source system for automating deployment, scaling, and management of containerized applications. It is quickly becoming the de facto standard for deploying and managing containerized applications at scale.

Helm is a package manager for Kubernetes. A package in Helm is referred to as a chart. In the next section we’ll create a chart to deploy our application image on a Kubernetes cluster.

Before continuing, create a Kubernetes cluster using the solution of your choice. Proceed by installing the helm command line tool and execute the helm init command to initialize Helm.

Tip: minikube is a cheap and easy way to set up a single node Kubernetes cluster

Now, with the Helm extension for VSCode, let’s bootstrap a new Helm chart from the VSCode command palette.

This creates a new myapp directory containing the bootstrapped chart. Update the values.yaml file to specify the default image and service parameters. The chart has ingress support by default, let’s enable it in the ingress.enabled parameter and update the ingress.hosts parameter with the myapp.local hostname as shown in the snippet below.

As our application requires to access a MongoDB server, create a requirements.yaml file in the chart directory to add themongodb chart as a requirement as shown in the snippet below:

Update template/deployment.yaml file from the chart directory to add the DATABASE_URL environment variable as shown in the following snippet.

Finally execute the commandhelm dependency update /myapp to download the mongodb chart to the myapp/charts/ directory so as to satisfy the chart dependencies.

Deploying the Chart

In the previous section we created a Helm chart to deploy our myapp application image. In this section we’ll deploy the chart to the Kubernetes cluster using the helm command line tool.

As we enabled ingress support in our chart, a deployment of the stable/nginx-ingress chart needs to exist in our cluster. Deploy it using the helm install --name nginx-ingress stable/nginx-ingress command.

Next, using the command below, get the external ip address of the nginx-ingress service and add it to the/etc/hosts file so that myapp.local resolves to the external ip address of the nginx-ingress service.

$ kubectl get services \
-l app=nginx-ingress,component=controller \
-o jsonpath="{ .items[0].status.loadBalancer.ingress[0].ip }"

We are now ready to deploy the myapp chart to the cluster using the command helm install --name myapp myapp/.

After a few minutes, open http://myapp.local in the web browser to access the application deployed on the Kubernetes cluster.

There you have it, our application is deployed on a Kubernetes cluster and is externally accessible. Future application updates can easily be deployed to the cluster by upgrading our deployed application using the helm upgrade command.

Conclusion

In summary, we bootstrapped a Express application using the Bitnami Express development container and used the generated Dockerfile to build a immutable production application Docker image.

We then bootstrapped a new Helm chart for our application and deployed it to a Kubernetes cluster using the helm command line tool.

The Bitnami Express development container has been engineered to be used very early in the development lifecycle of your application. We would like to get your feedback and learn how we could improve the Bitnami Express image.

You can request new features by creating an issue or submit a pull request with your contribution to the Bitnami Express repository on GitHub.

Most real time communication happens in the #containers channel at bitnami-oss.slack.com; you can sign up at slack.oss.bitnami.com.

--

--