In a previous article I have written
on how easy it is to stand up a test environment of OpenShift. In this article
I will describe an example application from the sourcecode to the created image
and how this gets deployed. The steps are explained using manual steps, and how
OpenShift does it all automated. You will notice, at no point do you have to
For this article it is not necessary to have a working test environment, however
it does make things clearer. I would suggest you to use OpenShift Origin v1.3 on
CentOS 7. Although my previous article showed how to get it up and running on
Fedora 24, I experienced an issue with deployment not succeeding*.
The steps in the deployment article can be performed by replacing
Description of the example
The OpenShift project publishes several test applications on GitHub, of which one is a very simple Ruby applica8080. Please, have a look at: http://github.com/openshift/ruby-ex
You will see it consists of four files:
The application itself is only described in
config.ru and the needed dependencies
To make the application work, we first need:
$ gem install bundler
This will install
bundler that can install dependencies as described in the
Gemfile. This file describes:
source 'https://rubygems.org' gem 'rack' gem 'puma'
The first line says
source which points to a gem repository, and each line
gem are bundled packages containing libraries for use in your
project. To install all of the required gems (dependencies) from the specified
$ bundle install
Gemfile.lock is a snapshot of the Gemfile and is used internally.
The application is specified in the file called
config.ru. If you open the
file you will see it contains route mappings, lines starting with
This is a commonly used to provide a simple health-check for applications that
are automatically deployed. It allows to quickly test if the application got
deployed. In projects I worked on, we also did quick dependency checks, such as
a configuration file exists, or another needed endpoint is available. In this
application it will respond with a HTTP status code 200 and returns
This is a test provided by rack. It shows an ASCII-art lobster. By adding a
variable to the URL querystring
?flip=left the direction can be changed.
This is the mapping to a bare route. It shows a greeting message on how to use the application using OpenShift to trigger automated builds.
Rack is an interface for using Ruby and Ruby frameworks with webservers. It
provides an application called
rackup to start the application:
$ bundle exec rackup -p 8080 config.ru
Using this command the webserver will bind to port 8080, according to the
description in the
config.ru file. To see what the mappings do, open:
Use the example with OpenShift
Deploying an application on OpenShift from source is very simple. A single command can do this. First have a look
$ oc new-app openshift/ruby-20-centos7~https://github.com/[username]/ruby-ex
But before we do, I will explain what this command does. Oversimplified OpenShift does two things:
Note: If you want to perform the command, go ahead. Please fork the repository
and change the
[username] in this command.
Build: source to image
OpenShift runs container images which are in the Docker format. It will run
CMD instruction for this. So, how does OpenShift know what to run?
Convention. Most frameworks have a standard way of doing things, and this is
as you noticed also the case with the Ruby example. The creation of the image
happens with a tool called source-to-image (S2I).
Source-to-Image (S2I) is a toolkit and workflow for building reproducible Docker images from source code. It uses a base image, and will layer the application on top, configures the runn command, which then results in a containter image for use.
$ s2i build https://github.com/[username]/ruby-ex openshift/ruby-20-centos7 ruby-ex
If you look at the
Dockerfile source, you will see
Software Collections is used to install a specific Ruby version.
In this case version 2.0. Software collections solves one of the biggest
complaints of using CentOS (or RHEL) as a basis as part of your delivery. It
allows you to use multiple versions of software on the same system, without
affecting system-wide installed packages.
The image also describes a label
which inidcate that the application on port 8080 will be exposed as HTTP
traffic. This also means the container does not need root privileges as the port
assignment is above 1024. The application itself will be installed into the
Running this container can be done with:
$ docker run -p 8080:8080 ruby-ex
 Puma starting in cluster mode...  * Version 3.4.0 (ruby 2.0.0-p645), codename: Owl Bowl Brawl  * Min threads: 0, max threads: 16  * Environment: production  * Process workers: 1  * Phased restart available  * Listening on tcp://0.0.0.0:8080  Use Ctrl-C to stop  - Worker 0 (pid: 32) booted, phase: 0
Open the links as previously stated will yield the same results.
$ curl http://localhost:8080/health
The build process can be as simple as a copy for static content, to compiling Java or C/C++ code. For the purpose of this article I will not explain more about the S2I process, but this will certainly be explained in future articles.
If we now look at the previous command again:
$ oc new-app openshift/ruby-20-centos7~https://github.com/[username]/ruby-ex
you can clear see the structure. The first element
describes the S2I container image for Ruby as hosted at the Docker hub. The
second part is the source code path pointing to a git repository.
Please try the command now... OpenShift will create containers for each of the
deploy and the final running container. You can check
the containers using the command:
$ oc get pod
NAME READY STATUS RESTARTS AGE ruby-ex-1-build 0/1 Completed 0 1m
If you create this new application, a new container named
What happened is that the Source-to-image container got pulled which uses the
base image and layers the source code on top.
To see what happened, as with the previous command, you can see the build configuration:
$ oc logs bc/ruby-ex
Cloning "https://github.com/gbraad/ruby-ex" ... Commit: f63d076b602441ebd65fd0749c5c58ea4bafaf90 (Merge pull request #2 from mfojtik/add-puma) Author: Michal Fojtik <[email protected]> Date: Thu Jun 30 10:47:53 2016 +0200 ---> Installing application source ... ---> Building your Ruby application from source ... ---> Running 'bundle install --deployment' ... Fetching gem metadata from https://rubygems.org/............... Installing puma (3.4.0) Installing rack (1.6.4) Using bundler (1.3.5) Cannot write a changed lockfile while frozen. Your bundle is complete! It was installed into ./bundle ---> Cleaning up unused ruby gems ... Pushing image 172.30.108.129:5000/myproject/ruby-ex:latest ... Pushed 0/10 layers, 10% complete Pushed 1/10 layers, 34% complete Pushed 2/10 layers, 49% complete Pushed 3/10 layers, 50% complete Pushed 4/10 layers, 50% complete Pushed 5/10 layers, 50% complete Pushed 6/10 layers, 61% complete Pushed 7/10 layers, 71% complete Pushed 8/10 layers, 88% complete Pushed 9/10 layers, 99% complete Pushed 10/10 layers, 100% complete Push successful
The difference is that the resulting image will be placed in the
namespace, and pushed to the local repository.
After the image has been composed, OpenShift will run the container image on the scheduled node. What happens here can be checked with:
$ oc get pod
NAME READY STATUS RESTARTS AGE ruby-ex-1-an801 1/1 Running 0 26s ruby-ex-1-build 0/1 Completed 0 1m
This means that the build succeeded, the image got deployed and now runs in the
a container identified with
ruby-ex-1-an801. Note: The container
ruby-ex-1-deploy is not shown here as only the logs are of importance.
The deployment configuration logs can be shown with:
$ oc logs dc/ruby-ex
 Puma starting in cluster mode...  * Version 3.4.0 (ruby 2.0.0-p645), codename: Owl Bowl Brawl  * Min threads: 0, max threads: 16  * Environment: production  * Process workers: 2  * Phased restart available  * Listening on tcp://0.0.0.0:8080  Use Ctrl-C to stop  - Worker 0 (pid: 32) booted, phase: 0  - Worker 1 (pid: 35) booted, phase: 0
To see the flow of execution, you can have a look at:
$ oc get events
This can be helpful if an error occured.
Now that the application has been deployed on OpenShift, we need to look up the IP address that has been assigned. For this we use:
$ oc get svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE ruby-ex 172.30.91.160 <none> 8080/TCP 21h
Now we can open the application as
OpenShift allows you to run prebuilt images or applications based on source.
The Source-to-image tooling makes it possible to create reproducible images for
deployment of applications based on source. This tool itself is very helpful
and is certainly something I will be using, even outside the use of OpenShift.
There is no need to create or modify a
Dockerfile, which means that the
developer can focus on the development process.
If you want to know more about the automated builds, please have a look at the README of the Ruby example. In future articles more detailed descriptions about these topics will certainly be given. I hope this has been helpful. Please consider leaving feedback or tweet this article.