Release Management with OpenShift: Under the hood

If you think about Release Management with OpenShift, you’re automatically thinking about Jenkins. With Jenkins you can easily setup a Release Pipeline for your App(s) and Jenkins is tightly integrated into OpenShift. There are a lot of Demos out there which are describing the best practices of using it. And OpenShift becomes more and more *ready* to use it easily.

But what if you’re not able to use Jenkins? Or what if you don’t want to use Jenkins? Or what if you are just curious and want to understand how you would do Release Management without Jenkins? Just via CLI or via API? — Then you’d need to understand the basic concepts of OpenShift’s project handling, namespaces, tagging, Image Handling etc.

In this article, I’d like to explain those topics and would like to give examples of how you’d do a release management.

The main Application is called simple-openshift-sinatra-sti and you can find it on GitHub. It is a very simple Ruby Application, which does nothing more than returning a text if you visit the URL. It does not contain a backend and does also not contain or rely on any database. Except for database handling, the concepts I am going to describe here are always the same.

Creating the Development Project
$ oc new-project dev
Now using project "dev" on server "https://127.0.0.1:8443".

You can add applications to this project with the ‘new-app’ command. For example, try:

$ oc new-app centos/ruby-22-centos7~https://github.com/openshift/ruby-ex.git

to build a new example application in Ruby.

This creates a new project called ‚dev‘, accessible by the current user and all others who have the same role. We are now going to create the app called ‚Sinatra‘ and thus we’re going to start the source to image process in OpenShift.

$ oc new-app ruby~https://github.com/wpernath/simple-openshift-sinatra-sti.git --name=sinatra
--> Found image f158f35 (2 weeks old) in image stream "openshift/ruby" under tag "2.3" for "ruby"

    Ruby 2.3
    --------
    Ruby 2.3 available as docker container is a base platform for building and running various Ruby 2.3 applications and frameworks. Ruby is the interpreted scripting language for quick and easy object-oriented programming. It has many features to process text files and to do system management tasks (as in Perl). It is simple, straight-forward, and extensible.
    Tags: builder, ruby, ruby23, rh-ruby23
    * A source build using source code from https://github.com/wpernath/simple-openshift-sinatra-sti.git will be created
      * The resulting image will be pushed to image stream "sinatra:latest"
      * Use 'start-build' to trigger a new build
    * This image will be deployed in deployment config "sinatra"
    * Port 8080/tcp will be load balanced by service "sinatra"
      * Other containers can access this service through the hostname "sinatra"

--> Creating resources ...
    imagestream "sinatra" created
    buildconfig "sinatra" created
    deploymentconfig "sinatra" created
    service "sinatra" created
--> Success

    Build scheduled, use 'oc logs -f bc/sinatra' to track its progress.
    Run 'oc status' to view your app.

Basically, source to image means to OpenShift: Give me any source code of any language I understand, and I am going to compile it and build a runtime container out of it. OpenShift comes with Java (maven), PHP, Ruby, JavaScript… builders, but can easily be enhanced by providing a custom source to image builder. For example have a look here to create a GoLang builder: https://github.com/amsokol/openshift-golang-template

With the above command, I have initialized this process, which you can follow by having a look at the Overview-Page of the OpenShift Web-UI:

fullsizeoutput_308f

Behind the hoods, you’d see a builder pod being started, which is – well – generated to build the image and start the pod with your application. In our case it is called ‚Sinatra‘. Go and point your browser to the following URL and you should be able to see your application: http://sinatra-dev.apps.127.0.0.1.nip.io/

So what has happened now? — OpenShift has created the application based on the provided GitHub URL. It has compiled the App, has created a runtime container and has started the pod with your application. You can now scale your app up and down and you can of course also start develop and change the source code of the app. Once you’ve committed something back to GitHub, just issue a rebuild and let OpenShift handle everything else:

$ oc start-build bc/sinatra
build "sinatra-2" started

With

$ oc logs -f bc/sinatra
Cloning "https://github.com/wpernath/simple-openshift-sinatra-sti.git" ...
Commit:05d5221c770d245838cd7fcb89988a35b9310051 (Update app.rb)
Author:Wanja Pernath <w.pernath@gmx.de>
Date:Sat Sep 16 12:01:23 2017 +0200
---> Installing application source ...
---> Building your Ruby application from source ...
---> Running 'bundle install  --without development:test' ...
Fetching gem metadata from https://rubygems.org/...........
Fetching version metadata from https://rubygems.org/..
Resolving dependencies...
Installing rack 1.6.8
Installing rack-protection 1.5.3
Installing tilt 2.0.8
Installing sinatra 1.4.6

You can follow the build process.

Creating the Test-Project #1

After a while you should be at a stage, where you want others to look at your work. You would also like to continue with tweaking your code. So you don’t want your testers to use your dev environment to test.

Let’s create a test project for your users:

$ oc new-project test1
Now using project "test1" on server "https://127.0.0.1:8443".

There are a few ways of making sure, your users are able to test your work. The easiest way for you as a developer might be to tag your git repository and let OpenShift use the tagged version to build the app. This would be realized by doing something like this:

$ oc new-app ruby~https://github.com/wpernath/simple-openshift-sinatra-sti.git#branch_name —name=sinatra

This would tell OpenShift to use the tagged version of your source code with the name ‚branch_name‘. You could do that. But it would have a lot of disadvantages.

  • How to easily roll back your work?
  • I am personally not a fan of recompiling my work on every stage

I am a fan of reusing what is proven to run on the stage before. If I already have a running environment, just take it and let it run on the next stage.

OpenShift helps you with this approach as well. Just tag your Image, give it a name, and let the deployment configuration of the test (or prod) project use that image. Whenever the image is changed, please redeploy as necessary.

$ oc tag dev/sinatra:latest dev/sinatra:testing
Tag sinatra:testing set to dev/sinatra@sha256:51538639435eb446260a3fc833b7bb6c35d09dfb0a9253830b3b7c82e376992d.

Now we have created a tagged version of our image and called it ‚testing‘. Let’s have a look at the image streams now:

$ oc describe is sinatra
Name: sinatra
Namespace: dev
Created: 35 minutes ago
Labels: app=sinatra
Annotations: openshift.io/generated-by=OpenShiftWebConsole
Docker Pull Spec: 172.30.1.1:5000/dev/sinatra
Image Lookup: local=false
Unique Images: 2
Tags: 2

latest
  pushed image
  * 172.30.1.1:5000/dev/sinatra@sha256:51538639435eb446260a3fc833b7bb6c35d09dfb0a9253830b3b7c82e376992d
      24 minutes ago

    172.30.1.1:5000/dev/sinatra@sha256:d037788a23e4b127c61eeec5c349f4174273a489a846ff575b9a5c8920078493
      31 minutes ago

testing
  tagged from sinatra@sha256:51538639435eb446260a3fc833b7bb6c35d09dfb0a9253830b3b7c82e376992d
  * 172.30.1.1:5000/dev/sinatra@sha256:51538639435eb446260a3fc833b7bb6c35d09dfb0a9253830b3b7c82e376992d
      21 seconds ago

As you can see, there are various versions of the Image in our dev project. The latest one is always tagged with the name ‚latest‘. This is done by OpenShift automatically. And whenever the image behind that tag has been changed, OpenShift will automatically redeploy your application. This happens everytime, you’re issuing a new build.

While we now have tagged the ‚latest‘ image in Dev with another name called testing, we can use this for creating our app in the test project.

$ oc new-app dev/sinatra:testing

This would tell OpenShift to use the image from the dev project with the tag ‚testing‘. Fortunately, the project concept of OpenShift doesn’t allow any project to just pull images from any other project. You have to explicitly allow this by giving the new project ‚image-puller‘ rights:

$ oc policy add-role-to-group system:image-puller system:serviceaccounts:test1 -n dev
role "system:image-puller" added: "system:serviceaccounts:test1"

This is the way to do it. Now you can execute the command above and OpenShift will start a deployment automatically.

After a while, your test1 project is ready to go. But you need to configure a Route for the application first:

$ oc expose service sinatra
route "sinatra" exposed

You can now access your app in stage Test1 via http://sinatra-test1.apps.127.0.0.1.nip.io/

This is the URL you can give your testers to test your application. At any time, you have a new version to test, you simply do a

$ oc tag dev/sinatra:latest dev/sinatra:testing

fullsizeoutput_3090

Creating the Test Project #2: The recommended way

Now let’s have a look at the disadvantages of the above method and let’s discuss a better way of bringing your apps to the next stage.

Just imagine that you’re in a real world environment, where you have a very important app which needs to be documented and also needs to be staged to a production environment. You simply don’t know right now which version of your app is running in which stage. Also, you can’t really easily roll back your application in case of an issue.

$ oc project test1
$ oc get is
No resources found.

Why? Because, there are no images or ImageStreams found in your test1 project. All you did is telling OpenShift to use the tagged version of the Image in the dev project. So you’re sharing the information with the dev project. But in real world scenarios, you want to have a deployment history in all your stages. So we have to change that now.

$ oc new-project test2
$ oc tag dev/sinatra:latest test2/sinatra:release1_test
Tag sinatra:release1_test set to dev/sinatra@sha256:51538639435eb446260a3fc833b7bb6c35d09dfb0a9253830b3b7c82e376992d.

$ oc tag test2/sinatra:release1_test test2/sinatra:latest
Tag sinatra:latest set to test2/sinatra@sha256:51538639435eb446260a3fc833b7bb6c35d09dfb0a9253830b3b7c82e376992d.

Now we have created a ‚copy‘ of the image (and the ImageStream) of sinatra:latest into our test2 project. Which means, if we now want to have a look at the ImageStream of Sinatra in our test2 project, we will see resources:

$ oc get is
NAME      DOCKER REPO                     TAGS                   UPDATED
sinatra   172.30.1.1:5000/test2/sinatra   latest,release1_test   6 minutes ago

The second oc tag command above makes sure, that we always have a ‚latest‘ image. And this is also the image we want to use for app deployment

$ oc describe is sinatra
Name: sinatra
Namespace: test2
Created: 7 minutes ago
Labels: <none>
Annotations: <none>
Docker Pull Spec: 172.30.1.1:5000/test2/sinatra
Image Lookup: local=false
Unique Images: 1
Tags: 2

latest
  tagged from sinatra@sha256:51538639435eb446260a3fc833b7bb6c35d09dfb0a9253830b3b7c82e376992d
  * 172.30.1.1:5000/test2/sinatra@sha256:51538639435eb446260a3fc833b7bb6c35d09dfb0a9253830b3b7c82e376992d
      6 minutes ago

release1_test
  tagged from dev/sinatra@sha256:51538639435eb446260a3fc833b7bb6c35d09dfb0a9253830b3b7c82e376992d
  * 172.30.1.1:5000/test2/sinatra@sha256:51538639435eb446260a3fc833b7bb6c35d09dfb0a9253830b3b7c82e376992d
      7 minutes ago

$ oc new-app test2/sinatra:latest
--> Found image c6aacd3 (2 hours old) in image stream "test2/sinatra" under tag "latest" for "test2/sinatra:latest"
    Ruby 2.3
    --------
    Ruby 2.3 available as docker container is a base platform for building and running various Ruby 2.3 applications and frameworks. Ruby is the interpreted scripting language for quick and easy object-oriented programming. It has many features to process text files and to do system management tasks (as in Perl). It is simple, straight-forward, and extensible.
    Tags: builder, ruby, ruby23, rh-ruby23
    * This image will be deployed in deployment config "sinatra"
    * Port 8080/tcp will be load balanced by service "sinatra"
    * Other containers can access this service through the hostname "sinatra"

--> Creating resources ...
    deploymentconfig "sinatra" created
    service "sinatra" created
--> Success
    Run 'oc status' to view your app.

fullsizeoutput_3091

Whenever you’re now going to release a new version for your testers (or for any other stage), you simply do an:

$ oc tag dev/sinatra:latest test2/sinatra:release2_test

To ‚copy‘ that working image from the last stage to the next stage (dev to test in this case) and then

$ oc tag test2/sinatra:release2_test test2/sinatra:latest

And then OpenShift starts redeploying the newly tagged image in your test stage. An

fullsizeoutput_3092

$ oc describe is sinatra
Name: sinatra
Namespace: test2
Created: 43 hours ago
Labels: <none>
Annotations: <none>
Docker Pull Spec: 172.30.1.1:5000/test2/sinatra
Image Lookup: local=false
Unique Images: 2
Tags: 3

latest
  tagged from sinatra@sha256:4d6955c20e614f61ded2b4361a3e72a5891681f073ac16314753b44d56c4ea01
  * 172.30.1.1:5000/test2/sinatra@sha256:4d6955c20e614f61ded2b4361a3e72a5891681f073ac16314753b44d56c4ea01
      46 seconds ago

    172.30.1.1:5000/test2/sinatra@sha256:51538639435eb446260a3fc833b7bb6c35d09dfb0a9253830b3b7c82e376992d
      43 hours ago

release1_test
  tagged from dev/sinatra@sha256:51538639435eb446260a3fc833b7bb6c35d09dfb0a9253830b3b7c82e376992d
  * 172.30.1.1:5000/test2/sinatra@sha256:51538639435eb446260a3fc833b7bb6c35d09dfb0a9253830b3b7c82e376992d
      43 hours ago

release2_test
  tagged from dev/sinatra@sha256:4d6955c20e614f61ded2b4361a3e72a5891681f073ac16314753b44d56c4ea01
  * 172.30.1.1:5000/test2/sinatra@sha256:4d6955c20e614f61ded2b4361a3e72a5891681f073ac16314753b44d56c4ea01
      About a minute ago
Summary

OpenShift allows to you to easily do CI/CD with any of your project. It is tightly integrated with Jenkins, but could easily be used outside of Jenkins as described in this article.

OpenShift also integrates in any IT process, as it allows you to have a full deployment history AND you’re always able to simply roll back your deployment in case of an emergency.

Thank you for reading.

 

%d bloggers like this: