Setting up a local development environment that corresponds as close as possible to production can be a time-consuming and error-prone task. However, for OpenShift deployments, we have the Red Hat Container Development Kit (CDK) which does a good job at solving this and also provides a great environment for experimenting with containers and the Red Hat container ecosystem in general.

In this blogpost we will cover deploying applications using the OpenShift Enterprise PaaS that comes with the CDK. The whole process will be driven via the OpenShift CLI, in contrast to our last post which focused on OpenShift’s web interface. If you haven’t yet installed the CDK, check out the previous blog post for instructions.

By the end of this article you will know how to build existing applications on OpenShift, whether they already use

Docker containers or not. The blog will cover two scenarios:

  1. Running an application that already uses Docker containers on OpenShift
  2. Running an application with no Docker support on OpenShift using the source-to-image (s2i) tooling, which will automatically assemble applications and embed them in a Docker container for execution.

The source code used for these examples is available from the appropriate branch here.

OpenShift 101

First let’s go over the basic OpenShift console (oc) operations. Most oc commands run in the context of a project, which holds one or more applications for a given set of users. In turn, each application may be composed of multiple microservices (or, more accurately, pods in OpenShift and Kubernetes parlance).

oc login Logs the user into the local instance of OpenShift. To login to remote instances, append the URL of the instance to the command. Note that by default any login is allowed and the user will be created if it doesn’t exist.
oc project Describes the current project.
oc project project_name Switches to the project project_name.
oc new-project my_project_name Creates a new project called my_project_name and makes it the current project.
oc get projects Lists all the projects you have access to.
oc delete project project_name Deletes the project project_name.
oc new-app ... Creates a new application inside your current project.
oc get pods Lists all the pods in the current project
oc exec -it pod_name /bin/bash Opens a shell on the first container in the pod pod_name. If there is more than one container in the pod, the-cflag can be used to specify a container.
oc describe resource/name Provides extensive information about a specific resource in a project. This can be a build, a deployment, a service, etc. It is done by joining multiple API calls.
oc status Inside a project, the status command will show you a high level overview (all the pods, containers, components, relationships) of the applications in the project.

The new-app command is a bit more complex than the others, as there are several ways in which OpenShift applications can be created. Normally, the result of this command is to build and deploy one or more containers.

Through the new-app command, we can create applications in one of three ways:

  1. Using raw source code from a repository (OpenShift will automatically detect the the language and deploy it an appropriate container using the s2i tooling)
  2. Providing pointers to Docker images
  3. Using templates which define an application in detail

There are additional ways to create applications with OpenShift, such as the oc run and oc process  commands, but we will not be looking into these for this blog post.

The build and deployment tasks will be visible in the OpenShift UI (think of them as continuous integration), which can be used to perform a roll-back in the event of errors. OpenShift will perform those tasks with service accounts that will control API access without sharing the user's credentials.

Now that we have an overview of the OpenShift CLI and how projects are composed, it’s time to see how we can put an application together. For this purpose, we will build a NodeJS application that connects to a MongoDB database for storage.

We’ll show two approaches for building this application, first by using Docker images and secondly by using the s2i tooling to build from source code.

Before following the tutorials, start up the CDK VM and log-in:

$ cd $HOME/cdk/components/rhel/rhel-ose/
$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider…
...
$ vagrant ssh
$ oc login

Tutorial 1: Running a Dockerized Application in OpenShift

This tutorial will show you how to run an already “Dockerized” application in OpenShift.

First we need to create a new project:

$ oc new-project node-mongo-intro-docker
Now using project "node-mongo-intro-docker" on server "https://10.1.2.2:8443".

Now we can create an application to hold our MongoDB database. For this example we’ll use a pre-built MongoDB image from the Red Hat Registry (here we’re using the mongodb-26-rhel7 image which has been enhanced to read the user and password from environment variables):

$ oc new-app registry.access.redhat.com/rhscl/mongodb-26-rhel7:latest -e MONGODB_USER=node_user -e MONGODB_PASSWORD=secret -e MONGODB_DATABASE=mydb -e MONGODB_ADMIN_PASSWORD=monZZBq123456
--> Found Docker image 5ae161a (3 days old) from registry.access.redhat.com for "registry.access.redhat.com/rhscl/mongodb-26-rhel7:latest"
   * An image stream will be created as "mongodb-26-rhel7:latest" that will track this image
   * This image will be deployed in deployment config "mongodb-26-rhel7"
   * Port 27017/tcp will be load balanced by service "mongodb-26-rhel7"
--> Creating resources with label app=mongodb-26-rhel7 ...
   ImageStream "mongodb-26-rhel7" created
   DeploymentConfig "mongodb-26-rhel7" created
   Service "mongodb-26-rhel7" created
--> Success

OpenShift will get the MongoDB image from the Red Hat Registry. After the image has been downloaded (this may take a while depending on your internet connection speed) it will be stored in your local OpenShift Docker registry and the OpenShift deploy task will kick-off. Once the deploy task completes, you will have a fully functional database service ready to serve the other applications from this project, protected by the username and password we specified earlier.

To check the status of the deployment run:

$ oc status
In project node-mongo-intro-docker on server https://10.1.2.2:8443
svc/mongodb-26-rhel7 - 172.30.122.78:27017
 dc/mongodb-26-rhel7 deploys imagestreamtag/mongodb-26-rhel7:latest
   #1 deployed 4 minutes ago - 1 pod

Now let’s start our NodeJS application. We will use our GitHub repository (the branch called docker) where we have a Dockerfile, at the root level, that describes what our image should contain:

FROM registry.access.redhat.com/openshift3/nodejs-010-rhel7
# Create app directory
WORKDIR /opt/app-root/src/
# Install app dependencies
COPY package.json /opt/app-root/src/
RUN ["/bin/bash", "-c", "npm install"]
# Bundle app source
COPY . /opt/app-root/src/
EXPOSE 8080
CMD npm start

The Dockerfile will use a NodeJS image from the Red Hat registry as base image, install the dependencies and start a webserver using the source code from our GitHub repository.
We’ll ask OpenShift to use “docker” build strategy, which means the build process will look for a Dockerfile in our source code and use it to create our new application:

oc new-app https://github.com/ContainerSolutions/node-openshift-sample.git#docker  --strategy=docker -e MONGODB_USER=node_user -e MONGODB_PASSWORD=secret -e MONGODB_DATABASE=mydb -e MONGODB_ADMIN_PASSWORD=monZZBq123456
--> Found Docker image e033586 (3 weeks old) from registry.access.redhat.com for "registry.access.redhat.com/openshift3/nodejs-010-rhel7"
   * An image stream will be created as "nodejs-010-rhel7:latest" that will track this image
   * The source repository appears to match: nodejs
   * A Docker build using source code from https://github.com/ContainerSolutions/node-openshift-sample.git#docker will be created
     * The resulting image will be pushed to image stream "node-openshift-sample:latest"
     * Every time "nodejs-010-rhel7:latest" changes a new build will be triggered
   * This image will be deployed in deployment config "node-openshift-sample"
   * Port 8080 will be load balanced by service "node-openshift-sample"
--> Creating resources with label app=node-openshift-sample ...
   ImageStream "nodejs-010-rhel7" created
   ImageStream "node-openshift-sample" created
   BuildConfig "node-openshift-sample" created
   DeploymentConfig "node-openshift-sample" created
   Service "node-openshift-sample" created
--> Success

Here OpenShift has found the Dockerfile and built a new service called node-openshift-sample based on the GitHub repository name. The service has full access to the previously launched MongoDB instance.
To get the status of this new deployment you can run:

$ oc status
In project node-mongo-intro-docker on server https://10.1.2.2:8443
svc/mongodb-26-rhel7 - 172.30.122.78:27017
 dc/mongodb-26-rhel7 deploys imagestreamtag/mongodb-26-rhel7:latest
   #1 deployed 7 minutes ago - 1 pod
svc/node-openshift-sample - 172.30.163.31:8080
dc/node-openshift-sample deploys imagestreamtag/node-openshift-sample:latest <-
   docker build of https://github.com/ContainerSolutions/node-openshift-sample.git#docker through bc/node-openshift-sample
   #1 deployed 57 seconds ago - 1 pod

Finally, we can expose the route to the NodeJS app to the host machine:

$ oc expose service node-openshift-sample --hostname=node-openshift-sample-docker.rhel-ose.vagrant.dev
route "node-openshift-sample" exposed

Your app should now be available at http://node-openshift-sample-docker.rhel-ose.vagrant.dev  (assuming you used the same naming convention). The application is very simple and just displays an image whenever the user clicks on the screen. Note that the position of the images is stored in the database and will survive page reloads etc.

Test_Drive_OS_with_CDK

Tutorial 2: Building from Source in OpenShift

The “source” build strategy will automatically build a Docker container for running your application using the s2i tooling. OpenShift will examining the source code, assemble and build it if required, then inject the compiled code into a container which can run it.

Using this method it is possible to get applications running on OpenShift without any knowledge of Docker or Dockerfiles.

You can follow along with the commands below, or watch this screencast:

http://www.youtube.com/watch?v=c3hBTDB9Ivk

First create a new project:

$ oc new-project node-mongo-intro
Now using project "node-mongo-intro" on server "https://10.1.2.2:8443".

Now let’s create our database, using a built-in template that will use an OpenShift Docker image:

$ oc new-app --template=mongodb-ephemeral
--> Deploying template mongodb-ephemeral in project openshift for "mongodb-ephemeral"
     With parameters:
     DATABASE_SERVICE_NAME=mongodb
     MONGODB_USER=userG38 # generated
     MONGODB_PASSWORD=v3DOiOTV8Ob4XGP2 # generated
     MONGODB_DATABASE=sampledb
     MONGODB_ADMIN_PASSWORD=qswlN18suwGpYWqg # generated
--> Creating resources ...
   Service "mongodb" created
   DeploymentConfig "mongodb" created
--> Success
Run 'oc status' to view your app.

Note the MongoDB credentials that OpenShift has displayed - we’ll need to pass these to the NodeJS application later.

Check the status of our application:

$ oc status
In project node-mongo-intro on server https://10.1.2.2:8443
svc/mongodb - 172.30.53.212:27017
dc/mongodb deploys openshift/mongodb:latest
   #1 deployed about a minute ago - 1 pod
To see more, use 'oc describe <resource>/<name>'.
You can use 'oc get all' to see a list of other objects.

Next let’s deploy our NodeJS application. We will use our GitHub repository again, but note that this branch does not have a Dockerfile or any build configuration. We also need to set environment variables for accessing the MongoDB with the credentials OpenShift gave us earlier:

$ oc new-app https://github.com/ContainerSolutions/node-openshift-sample -e MONGODB_USER=userG38 -e MONGODB_PASSWORD=v3DOiOTV8Ob4XGP2 -e MONGODB_DATABASE=sampledb
--> Found image e033586 (3 weeks old) in image stream "nodejs in project openshift" under tag :0.10 for "nodejs"
   * The source repository appears to match: nodejs
   * A source build using source code from https://github.com/ContainerSolutions/node-openshift-sample will be created
     * The resulting image will be pushed to image stream "node-openshift-sample:latest"
   * This image will be deployed in deployment config "node-openshift-sample"
   * Port 8080/tcp will be load balanced by service "node-openshift-sample"
--> Creating resources with label app=node-openshift-sample ...
   ImageStream "node-openshift-sample" created
   BuildConfig "node-openshift-sample" created
   DeploymentConfig "node-openshift-sample" created
   Service "node-openshift-sample" created
--> Success
   Build scheduled for "node-openshift-sample" - use the logs command to track its progress.
   Run 'oc status' to view your app.

OpenShift has fetched the source code, recognised it as NodeJS and kicked off an appropriate s2i build to create a Docker image with the NodeJS code embedded. Once the build is complete, it will be pushed into the local registry and launched.

We can check that our application has been created:

$ oc status
In project node-mongo-intro on server https://10.1.2.2:8443
svc/mongodb - 172.30.53.212:27017
 dc/mongodb deploys openshift/mongodb:latest
   #1 deployed 10 minutes ago - 1 pod
svc/node-openshift-sample - 172.30.198.178:8080
 dc/node-openshift-sample deploys imagestreamtag/node-openshift-sample:latest <-
   builds https://github.com/ContainerSolutions/node-openshift-sample with openshift/nodejs:0.10 through bc/node-openshift-sample
     #1 build running for about a minute
   #1 deployment waiting on image or update
To see more, use 'oc describe <resource>/<name>'.
You can use 'oc get all' to see a list of other objects.

We can get more details about our new application with the describe command:

$ oc describe svc/node-openshift-sample
Name:            node-openshift-sample
Namespace:        node-mongo-intro
Labels:            app=node-openshift-sample
Selector:        app=node-openshift-sample,deploymentconfig=node-openshift-sample
Type:            ClusterIP
IP:            172.30.198.178
Port:            8080-tcp    8080/TCP
Endpoints:        172.17.0.9:8080
Session Affinity:    None
No events.

Lastly we will want to create a route so that we can access our application externally.

$ oc expose svc/node-openshift-sample --hostname=node-test.rhel-ose.vagrant.dev

Finally, we can open a web browser and see our application running: http://node-test.rhel-ose.vagrant.dev

This screencast shows the application running and demonstrates that is using the MongoDB to retain state:

http://www.youtube.com/watch?v=jcsNW5KS_zc

Conclusion

In this post we took a look at how to get a NodeJS/MongoDB application running on OpenShift inside the Red Hat CDK. We focused on using the CLI, which currently offers more capabilities than the web console. We looked at deploying existing Docker images, as well as leveraging the s2i tooling to create new images by building from source code and injecting into a template image.

We have shown that both “dockerized” applications and applications that don’t “speak Docker” can be easily imported into OpenShift. The source code of the branches used in our examples is identical, except for the addition of the Dockerfile in the first tutorial. The s2i strategy allows developers to run code on OpenShift with little or no prior knowledge of Kubernetes or Docker containers.

The speed with which a developer can get started with OpenShift is impressive, especially given the amount of power and configuration that is under the hood. We encourage all developers to investigate OpenShift, whether they are looking for a industry grade orchestration framework or just an easy way to start experimenting with containers.