How to Deploy a Node.js app on OpenShift
Do you want to know how to build a Docker image for your Node API, and then deploy it in OpenShift? Then read on.
In this tutorial I’ll go through deploying a Node.js hello world application onto OpenShift.
By the way, you’ll need the
oc tool installed for this.
What we’re going to build
When you deploy an app into OpenShift or Kubernetes, you’re basically creating a bunch of objects, that usually look like JSON or YAML files.
A typical application in OpenShift consists of a BuildConfig, a Deployment, a Service and a Route.
|Object||What it does|
|BuildConfig||Builds a Docker image inside OpenShift from our source code, and push it to OpenShift’s internal Docker registry. In this tutorial, we’re going to use the Source-to-Image (S2I) method for building an image.|
|Deployment||Deploys the image. It creates a set of Pods to run the image. (see some Deployment examples)|
|Service||This load-balances traffic across the Pods.|
|Route||Exposes the app outside the OpenShift cluster.|
The BuildConfig will build our Docker image, and then the other objects are responsible for deploying it, and making it available to the outside world.
First, we’ll need an app to deploy
First, we need an application to deploy.
If you just want to skip creating an app, and use one I made earlier, then use this one. This is using Node.js/Express:
If you’ve already got your own app, make sure you’ve configured Node to listen on all interfaces (
0.0.0.0) and listen on port 8080.
But what about if you want to create an app, from scratch? I’ll show you how I created one:
I decided to use Express JS, and started out by creating a new Express application, using the Express Generator:
If you use this generator to create your Express app, then make sure you add the
--no-view option. This is because by default, the generator sets up Jade as your HTML rendering engine, and it’s apparently already deprecated and full of critical bugs (!!!). So either swap to the pug engine, or add
Here’s the command that I used, in case you want to do the same as me:
npx express-generator node-hello-world --no-view
Now you should have a basic Express app.
cd into the directory, run
npm install and
npm start and you should get an API.
Got your Node.js application ready to deploy? Read on, in the next section we’ll look at building an image from your code.
Build and deploy with
So now we’ve got our Node.js application ready.
The next thing to do is create the necessary objects in OpenShift: a BuildConfig, a Deployment, a Service and a Route.
oc new-app command will create all of those objects for you. Just pass it your Git repo URL, and optionally a
context-dir (if your code is in a subfolder), and a
oc new-app https://github.com/monodot/container-up --context-dir=node-hello-world --name=node-app --strategy=source
(My example repo contains a Dockerfile, so I’m using
--strategy=source to force OpenShift to use an S2I build, instead of a Docker build.)
OpenShift will detect the language of the application (Node), and try to pick an appropriate S2I builder image, from the image streams that are installed in your cluster.
If your cluster is missing the node S2I builder images, or you just want to use a different S2I builder image, like the community CentOS NodeJS image, you can give the full image URL with a tilde, like this:
oc new-app quay.io/centos7/nodejs-12-centos7~https://github.com/monodot/container-up \ --name=node-app --context-dir=node-hello-world --strategy=source
And you’ll get output like this:
$ oc new-app https://github.com/monodot/container-up --name=node-app --context-dir=node-hello-world --> Found container image 995ff80 (7 days old) from Docker Hub for "node:14" * An image stream tag will be created as "node:14" that will track the source image * A Docker build using source code from https://github.com/monodot/container-up will be created * The resulting image will be pushed to image stream tag "node-app:latest" * Every time "node:14" changes a new build will be triggered * This image will be deployed in deployment config "node-app" * Port 8080/tcp will be load balanced by service "node-app" * Other containers can access this service through the hostname "node-app" * WARNING: Image "node:14" runs as the 'root' user which may not be permitted by your cluster administrator --> Creating resources ... imagestream.image.openshift.io "node" created imagestream.image.openshift.io "node-app" created buildconfig.build.openshift.io "node-app" created deploymentconfig.apps.openshift.io "node-app" created service "node-app" created --> Success Build scheduled, use 'oc logs -f bc/node-app' to track its progress. Application is not exposed. You can expose services to the outside world by executing one or more of the commands below: 'oc expose svc/node-app' Run 'oc status' to view your app.
Which port and host?
It’s really important that your Node app is serving on the correct host and port. Otherwise, OpenShift will not be able to route requests to it.
oc new-app to work, your app should run on the same port that is exposed by the S2I image. (A Docker image usually has an
EXPOSE instruction, which says which ports the container should expose)
The Red Hat and CentOS S2I images generally expose port 8080. This means that your Node app also needs to run on port 8080.
You also need to make sure that your app is listening on all interfaces. Set your server listen address to
0.0.0.0, not “localhost” or “127.0.0.1”.
Behind the scenes, OpenShift will start a Build to build your app and create a Docker image. You can follow the build logs:
oc logs -f bc/node-app
Finally, the last step is to expose your app by creating a Route (or you could create an Ingress object on OpenShift if you prefer):
oc expose svc/node-app
And now our app should be up and available! Super.
Accessing the app
We can test it out:
Get the URL to the app by using
oc get route. The Route is the thing you created at the end of the last section:
$ oc get route NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD node-app node-app-toms-project.apps.example.com node-app 8080-tcp None
If you’ve deployed my example app, then you can hit the endpoint with
/greeting to the end:
which will give you:
So there you have it. A Node JS Express application built and deployed onto OpenShift.
oc new-app to detect the language of our app, and create a BuildConfig. This ran a Source-to-Image (S2I) build, to create a Docker image.
oc new-app also created a Deployment and a Service to run the container in Pods. Finally, we created a Route so we could access the API outside the cluster.
And a reminder of the main gotchas:
Make sure your app is running on the same port as the S2I builder image you use. e.g. port 8080.
Make sure your app is listening on all addresses (
oc new-appcan’t find any suitable S2I builder images in the cluster, you can always specify the image you want to use, with
oc new-app <image url>~<git url>
Try updating your code in Git and run a new build, from the web console.
See how to run Docker builds in OpenShift, if you prefer that instead of S2I.
Thanks for reading!