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:
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 <[email protected]> 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
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.
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
$ 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.