Running A Simple Java Application CI/CD with Jenkins and Openshift

So basically im trying to create a simple CI/CD using Jenkins which runs on top of Openshift. It will do a very simple thing, fetching code from Github, and deploy it automatically to Openshift platform.

For this example, im using my previous Github repository which located at https://github.com/edwin/hello-world. It’s a very simple spring boot app, open an API and shows “hello world”.

But first, lets prepare our Jenkins instance on Openshift.

Once done, we can see Jenkins Dashboard.

And add Maven to Jenkins, on Manage jenkins > Global Tool Configuration

For this example, i want to deploy the app on a different Openshift project (eee project) compare to Jenkins which located on Fuse project. Therefore i need to create a service account specifially for Jenkins to deploy.

Create a simple pipeline item on Jenkins,

Which are triggered by a Poll SCM,

And after that, we can create a simple pipeline script for building the code. Changing project location to “eee”, and deploy it accordingly.

def gitRepo="https://github.com/edwin/hello-world.git"
def branch="master"

pipeline {
  agent any
  tools {
    maven 'M3'
  }
  stages {
    stage('Preparing'){
        steps{
            git branch: branch, url: gitRepo
        }
      }
    stage('Build and Deploy') {    
        steps {
            sh 'oc project eee'
            sh 'mvn -B clean fabric8:deploy'
        }
    }
  }
}

Simple isnt it? ;)

Google+

How to Deploy Source Code from Local Folder to Openshift Using S2I Build

First lets create a simple PHP code, and name it index.php

<?php
echo "hello world";
?>

We want to deploy it on top of PHP 7 images, and make it online on Openshift Platform.

So how to do it basically consist of 3 steps.
1. First we need to create a new binary build, using preferred image stream as its base image

oc new-build --name=my-php --image-stream=php:7.0 --binary=true

2. Next is start building image using sourcecode’s directory

oc start-build my-php --from-dir=.

3. Last is create application using previously built image

oc new-app my-php --name=my-php

So simple right :)

Google+

Backup All Openshift Template and Restore it to Another Openshift Instance

Previously i have to move a lot of Openshift template from one instance to another instance. So instead of copying a template one by one, why not just dump the whole template and import it to the new instance.

Below is the screenshot of source Openshift where we want to export the template from.

 
oc get -n openshift -o yaml --export templates > mytemplate.yaml

Below is the screenshot of the target Openshift,

oc apply -f mytemplate.yaml

This is the end result,

Google+

Creating A Simple Openshift Template

An Openshift Template is, as its name, a template on creating an application deployment. We can define url, imagestream location, service, and other things. We’ll start on a very simple json template which will took a specific image from docker hub, and deploy it to Openshift and generating URL on the fly automatically.

{
  "kind": "Template",
  "apiVersion": "v1",
  "metadata": {
    "name": "create-quarkus-template",
    "annotations": {
      "description": "This example shows how to create a simple template in openshift 3.11",
      "tags": "Quarkus"
    }
  },
  "objects": [
    {
      "kind": "Service",
      "apiVersion": "v1",
      "metadata": {
        "name": "my-quarkus"
      },
      "spec": {
        "ports": [
          {
            "name": "web",
            "protocol": "TCP",
            "port": 8080,
            "targetPort": 8080,
            "nodePort": 0
          }
        ],
        "selector": {
          "name": "my-quarkus"
        },
        "type": "ClusterIP",
        "sessionAffinity": "None"
      },
      "status": {
        "loadBalancer": {}
      }
    },
    {
        "kind": "Route",
        "apiVersion": "v1",
        "metadata": {
          "name": "my-quarkus"
        },
        "spec": {
          "to": {
            "kind": "Service",
            "name": "my-quarkus"
          },
          "tls": {
            "termination": "edge"
          }
        }
    },
    {
      "kind": "ImageStream",
      "apiVersion": "v1",
      "metadata": {
        "name": "my-quarkus"
      },
      "spec": {
        "dockerImageRepository": "edwinkun/my-quarkus"
      },
      "status": {
        "dockerImageRepository": ""
      }
    },
    {
        "kind": "DeploymentConfig",
        "apiVersion": "v1",
        "metadata": {
          "name": "my-quarkus",
          "annotations": {
            "template.alpha.openshift.io/wait-for-ready": "true"
          }
        },
        "spec": {
          "strategy": {
            "type": "Rolling",
            "rollingParams": {
              "updatePeriodSeconds": 1,
              "intervalSeconds": 1,
              "timeoutSeconds": 120,
              "pre": {
                "failurePolicy": "Abort",
                "execNewPod": {
                  "command": [
                    "/bin/true"
                  ],
                  "env": [
                  ],
                  "containerName": "my-quarkus"
                }
              },
              "post": {
                "failurePolicy": "Ignore",
                "execNewPod": {
                  "command": [
                    "/bin/true"
                  ],
                  "env": [
                  ],
                  "containerName": "my-quarkus"
                }
              }
            },
            "resources": {}
          },
          "triggers": [
            {
              "type": "ImageChange",
              "imageChangeParams": {
                "automatic": true,
                "containerNames": [
                  "my-quarkus"
                ],
                "from": {
                  "kind": "ImageStreamTag",
                  "name": "my-quarkus:latest"
                }
              }
            },
            {
              "type": "ConfigChange"
            }
          ],
          "replicas": 3,
          "selector": {
            "name": "my-quarkus"
          },
          "template": {
            "metadata": {
              "labels": {
                "name": "my-quarkus"
              }
            },
            "spec": {
              "containers": [
                {
                  "name": "my-quarkus",
                  "image": "my-quarkus",
                  "ports": [
                    {
                      "containerPort": 8080,
                      "protocol": "TCP"
                    }
                  ],
                  "env": [
                  ],
                  "resources": {},
                  "terminationMessagePath": "/dev/termination-log",
                  "imagePullPolicy": "IfNotPresent",
                  "securityContext": {
                    "capabilities": {},
                    "privileged": false
                  }
                }
              ],
              "restartPolicy": "Always",
              "dnsPolicy": "ClusterFirst"
            }
          }
        },
        "status": {}
      }
  ],
  "labels": {
    "template": "my-quarkus-dockerbuild"
  }
}
Google+

Creating a Simple Spring Boot @Cacheable Cache using JBoss DataGrid on top of Openshift

Creating a Simple Spring Boot @Cacheable Cache using JBoss DataGrid on top of Openshift

Several days ago, one of my team member were asking me on how to connect Spring Boot to JBoss Datagrid as its primary cache server. Since we are using Openshift, im using Openshift template “Red Hat JBoss Data Grid 7.2 (Ephemeral, no https)” as base image deployment.

First we need to create instance of Datagrid on Openshift,

Create our cache name,

And finally, we can see our JBoss Datagrid endpoint here, and fyi we are using HotRod protocol to connect to JDG so our endpoint name should be “jdg-datagrid-app-01-hotrod” with port “11333”.

And start our project by creating a pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.edw</groupId>
    <artifactId>TestingJDGCacheable</artifactId>
    <version>1.0</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>



        <dependency>
            <groupId>org.infinispan</groupId>
            <artifactId>infinispan-client-hotrod</artifactId>
            <version>8.4.0.Final-redhat-2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>


    </dependencies>

    <profiles>
        <profile>
            <id>openshift</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>io.fabric8</groupId>
                        <artifactId>fabric8-maven-plugin</artifactId>
                        <version>3.5.28</version>
                        <executions>
                            <execution>
                                <id>fmp</id>
                                <phase>package</phase>
                                <goals>
                                    <goal>resource</goal>
                                    <goal>build</goal>
                                </goals>
                            </execution>
                        </executions>
                        <configuration>
                            <generator>
                                <config>
                                    <spring-boot>
                                        <fromMode>isTag</fromMode>
                                        <from>redhat-openjdk18-openshift:1.2</from>
                                    </spring-boot>
                                </config>
                            </generator>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>

    <repositories>
        <repository>
            <id>jboss</id>
            <url>https://repository.jboss.org/nexus/content/groups/public-jboss/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>redhat-techpreview</id>
            <name>Red Hat Tech Preview</name>
            <url>https://maven.repository.redhat.com/techpreview/all/</url>
            <layout>default</layout>
            <releases>
                <enabled>true</enabled>
                <updatePolicy>never</updatePolicy>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>redhat-ga</id>
            <name>Red Hat GA</name>
            <url>https://maven.repository.redhat.com/ga/</url>
            <layout>default</layout>
            <releases>
                <enabled>true</enabled>
                <updatePolicy>never</updatePolicy>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>jboss-plugins</id>
            <url>https://repository.jboss.org/nexus/content/groups/public-jboss/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
        <pluginRepository>
            <id>redhat-techpreview</id>
            <url>https://maven.repository.redhat.com/techpreview/all/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
        <pluginRepository>
            <id>redhat-ga</id>
            <url>https://maven.repository.redhat.com/ga/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

After that, we can create our Spring Boot project, and start with a main java class,

@SpringBootApplication
@EnableCaching
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Register your JBoss Datagrid cache

@Configuration
public class CacheConfig {
    @Bean
    public RemoteCacheManager remoteCacheManager() {
        ConfigurationBuilder builder = new ConfigurationBuilder();
        builder.addServers("jdg-datagrid-app-01-hotrod:11333");
        return new RemoteCacheManager(builder.build());
    }
}

And a simple controller where our cache will be used, as on below code we are using “bakerooo” cache.

@RestController
public class IndexController {
    @GetMapping("/")
    @Cacheable("bakerooo")
    public Long getNow() {
        return System.currentTimeMillis();
    }
}

We can deploy our code by using maven’s fabric8 plugin,

mvn clean package fabric8:deploy

And test it by using a simple curl command.
Feel free to ask question, and you can download the full code at my github repo here.

Google+