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:
- Running an application that already uses Docker containers on OpenShift
- 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.
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:
- Using raw source code from a repository (OpenShift will automatically detect the the language and deploy it an appropriate container using the s2i tooling)
- Providing pointers to Docker images
- 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.
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:
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:
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.