This post was originally written by Josef Strzibny in this blog:

Build your Ruby application’s Docker image in just one line of code without writing any Dockerfile! You only need source-to-image tool (s2i, formally sti) and Docker.

S2i is a program that can build your application image on top of s2i images. OpenShift uses s2i images to run your applications (be it Ruby, Python, Perl, …) so I want to show you how can you take advantage of them for building your own Ruby application.

But why do I call them OpenShift or SCL images? Let’s see why we call them differently even thought they are the same images:

  • S2i enabled: They come with s2i scripts so you can build your images on top of them with the s2i tool
  • Software Collections based: The components used to build these images are coming as software collections
  • OpenShift’s: These images are community variant of images that run your applications in OpenShift

Before we start we will need to get the source-to-image (s2i) tool itself. This tool will help us to automate the build of our application image. At the moment s2i is not part of Fedora (but it will), so, we will have to build it from the source (which means you can use similar steps to build it on other systems as well).


Let’s install the dependencies: golang for building s2i, docker for running our containers, and which utility if missing as it does on Fedora Cloud Vagrant boxes.

<span class="pln">$ sudo dnf install </span><span class="pun">-</span><span class="pln">y golang docker which</span>


Now set GOPATH to $HOME directory:

<span class="pln">$ </span><span class="kwd">export</span><span class="pln"> GOPATH</span><span class="pun">=</span><span class="pln">$HOME</span>

You should skip that if you already have Go installed on your system.


Then we are ready to get the sources for s2i:

<span class="pln">$ go </span><span class="kwd">get</span><span class="pln"> github</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">openshift</span><span class="pun">/</span><span class="pln">source</span><span class="pun">-</span><span class="pln">to</span><span class="pun">-</span><span class="pln">image</span>

src/ and pkg/ directories should show up in our home directory.


Afterwards we can build the s2i tool:

$ cd ${GOPATH}/src/
$ hack
++ Building go targets for linux/amd64: cmd/s2i
++ Placing binaries


Now /home/vagrant/src/ is path to our s2i binary. We can either move it on $PATH (ideally to /usr/local/bin since we will use root user to run Docker), or reference the full path.

<span class="pln">sudo cp $</span><span class="pun">{</span><span class="pln">GOPATH</span><span class="pun">}/</span><span class="pln">src</span><span class="pun">/</span><span class="pln">github</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">openshift</span><span class="pun">/</span><span class="pln">source</span><span class="pun">-</span><span class="pln">to</span><span class="pun">-</span><span class="pln">image</span><span class="pun">/</span><span class="pln">_output</span><span class="pun">/</span><span class="kwd">local</span><span class="pun">/</span><span class="pln">go</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">s2i </span><span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="kwd">local</span><span class="pun">/</span><span class="pln">bin</span>


Having s2i in place, we can create our minimal Sinatra application:

$ cd $HOME && mkdir app && cd app

$ cat app/app.rb
require 'sinatra'
get('/') { 'this is a simple app' }

$ cat
require './app'

$ cat Gemfile

gem 'sinatra'

This is an incredibly basic application, but we can have here any rack-based application full of different dependencies in the Gemfile.

S2i images feature assemble script which comes with the image that installs application sources as well as dependencies (using Bundler) and compiles assets if necessary. This all happens during the build of the application image on top of the s2i image.

That means we need to specify a rack dependency in the Gemfile (here we satisfy that by mentioning Sinatra).

You can also see that I am including Puma as an application server. This is intentional as these images comes with a special support for Puma. Here is the default config used for Puma:

environment ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'production'
0, 16

If Puma is not present, the final image will just run rackup command as you can see in the run script.

So, let’s build the application image for our Sinatra application based on the OpenShift s2i Ruby 2.2 image:

# systemctl start docker
# cd $HOME
# s2i build file:///$PWD openshift/ruby-22-centos7 ruby-sample-app
09:56:47.747754 14138 sti.go:426] ---> Installing application source ...
09:56:47.754513 14138 sti.go:426] ---> Building your Ruby application from source ...
09:56:47.754954 14138 sti.go:426] ---> Running 'bundle install ' ...
09:56:51.378159 14138 sti.go:426] Fetching gem metadata from
09:56:51.466697 14138 sti.go:426] Resolving dependencies...
09:56:53.725077 14138 sti.go:426] Installing puma 2.14.0
09:56:55.087663 14138 sti.go:426] Installing rack 1.6.4
09:56:56.281768 14138 sti.go:426] Installing rack-protection 1.5.3
09:56:57.552063 14138 sti.go:426] Installing tilt 2.0.1
09:56:58.875198 14138 sti.go:426] Installing sinatra 1.4.6
09:56:58.875692 14138 sti.go:426] Using bundler 1.7.8
09:56:58.876630 14138 sti.go:426] Your bundle is complete!
09:56:58.876758 14138 sti.go:426] It was installed into ./bundle
09:56:58.895426 14138 sti.go:426] ---> Cleaning up unused ruby gems ...

As you can see, s2i takes a few arguments. First we reference the sources of our application, it expects a git repository, so make it one.

Then it needs the s2i image. ruby-22-centos7 is the community version of OpenShift’s Ruby 2.2 image.

Finally the name for our new application image.


You can even reference a remote git repository of your application with a specific app directory, e.g. --context-dir=2.0/test/puma-test-app/ for an example Puma test app from the sti-ruby git repository.

Once it is done, our new application image will appear among other Docker containers:

# docker images
-sample-app latest cf8462aa4e1f 6 minutes ago 403.2 MB

Feel free to run it with docker run:

# sudo docker run -p 8080:8080 ruby-sample-app
Puma starting in single mode...
* Version 2.14.0 (ruby 2.2.2-p95), codename: Fuchsia Friday
* Min threads: 0, max threads: 16
* Environment: production
* Listening on tcp://
Use Ctrl-C to stop

And check that the app is working:

# docker ps
c27f50d1493e ruby
-sample-app:latest "container-entrypoin About a minute ago
Up About a minute>8080/tcp lonely_payne
# curl
this is a simple app

First we check that our container is running and then we simply try to get the output from the Sinatra application.

It seems to work! source-to-image together with source-to-image enabled images made that pretty simple and we didn’t have to write our own Dockerfile at all.

Things to remember

As I covered only the basic concepts, I recommend you to read more about source-to-image and the configuration of OpenShift’s Ruby image on their respective GitHub pages.

There are also few other things to know and remember.

These images are actually based on the community released Software Collections running CentOS. OpenShift itself uses the official and supported Red Hat Software Collections based on RHEL.

rh-ruby22 and nodejs010 software collections are already enabled in the images so it does not even feel like you are using them:

# sudo docker run ruby-sample-app ruby -v
2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]

But you can see the scl_enable script that get’s sourced here.

The Dockerfile for the Ruby image is pretty straight forward:

  • Installs few basic packages rh-ruby22 rh-ruby22-ruby-devel rh-ruby22-rubygem-rake v8314 rh-ruby22-rubygem-bundler nodejs010
  • Creates /opt/app-root as an application root.
  • Sets the user with id 1001 to own this root and copies in the s2i scripts I talked about, for assembling and running the image.
  • It can compile C extensions since it's based on base-centos7 image that installs various -devel packages.

And that’s pretty much it. Feel free to ask questions if you have any.


Josef Strzibny
Developer Experience Software Engineer at Red Hat

Full Article

To read more about this post, see the full article at


OpenShift Container Platform, OpenShift Dedicated

< Back to the blog