Application development with Bitnami Express container and VScode
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.
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 /index
route 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 commanddocker-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.