openshift Posts

Run as a Root User on Openshift

Sometimes my docker images got permission issue when deployed to Openshift, due to Openshift gives a random userid as enforced by its default security policy. In order to “bypass” those constrain and run my image as root, i run below command,

oc adm policy add-scc-to-user anyuid -z default -n project-name
Google+

Deploying A Simple Hello World App using OpenLiberty S2I to Openshift

For this example im using OpenLiberty version 19.0.0.6, and install corresponding image to my Openshift registry using below command,

oc import-image openliberty/open-liberty-s2i:19.0.0.6

Can check our list of images on our imagestream by using this command,

oc get is

Next is creating a simple hello-world webapps, with below pom

<?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>

    <groupId>hello-world-servlet</groupId>
    <artifactId>com.edw</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <sourceDirectory>src/main/java</sourceDirectory>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                    <webXml>src\main\webapp\WEB-INF\web.xml</webXml>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

And web.xml,

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
        PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
    <display-name>My Web Application</display-name>

    <servlet>
        <servlet-name>helloServlet</servlet-name>
        <servlet-class>com.edw.MyServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>helloServlet</servlet-name>
        <url-pattern>/hello.servlet</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>/hello.jsp</welcome-file>
    </welcome-file-list>
    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>
</web-app>

A simple JSP file,

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Hello World</title>
</head>
<body>
Hello World
</body>
</html>

And a simple java file,

package com.edw;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyServlet  extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException {
        response.getWriter().println("Hello");
    }
}

And a simple server.xml file,

<?xml version="1.0" encoding="UTF-8"?>
<server description="OpenLiberty Server">
    <httpEndpoint id="defaultHttpEndpoint" host="*" httpPort="9080" httpsPort="9443"/>
    <webApplication location="com.edw-1.0-SNAPSHOT.war"/>
</server>

After project is properly setup, we can do a simple mvn build,

mvn clean package

And push our application to Openshift, run below command on the root of your project location

oc new-build --name=my-openliberty-full --image-stream=open-liberty-s2i:19.0.0.6 --binary=true

oc start-build my-openliberty-full --from-dir=.

oc new-app my-openliberty-full --name=my-openliberty-full

We can access our newly created app directly thru browser,

Google+

Fixing Error “null username” when Integrating RedHat Single Sign On to Active Directory

Previously never had any issue when integrating RedHat SSO (Keycloak) to LDAP, but now got a very weird issue because now im trying to connecting RHSSO to Microsoft Active Directory instead of standard LDAP.

One biggest difference is that ActiveDirectory is using “sAMAccountName” field for user primarykey mapping, and somehow RHSSO is always get null value when trying to synchronize with existing user. Below is the complete stacktrace.

11:59:45,031 ERROR [org.keycloak.storage.ldap.LDAPStorageProviderFactory] (default task-122) Failed during import user from LDAP: 
org.keycloak.models.ModelException: User returned from LDAP has null username! 
Check configuration of your LDAP mappings. Mapped username LDAP attribute: sAMAccountName, 
user DN: CN=XXX,OU=User,OU=HO,DC=llll,DC=co,DC=id, attributes from LDAP: 
{whenChanged=[20191016020643.0Z], whenCreated=[20170105023800.0Z], mail=[xxx@lll.co.id], givenName=[cccc], sn=[dddd], cn=[ccccc dddd], userAccountControl=[512], pwdLastSet=[132156652033202194]}
	at org.keycloak.storage.ldap.LDAPUtils.getUsername(LDAPUtils.java:113)
	at org.keycloak.storage.ldap.LDAPStorageProviderFactory$3.run(LDAPStorageProviderFactory.java:542)
	at org.keycloak.models.utils.KeycloakModelUtils.runJobInTransaction(KeycloakModelUtils.java:227)
	at org.keycloak.storage.ldap.LDAPStorageProviderFactory.importLdapUsers(LDAPStorageProviderFactory.java:535)
	at org.keycloak.storage.ldap.LDAPStorageProviderFactory.syncImpl(LDAPStorageProviderFactory.java:490)
	at org.keycloak.storage.ldap.LDAPStorageProviderFactory.sync(LDAPStorageProviderFactory.java:428)
	at org.keycloak.services.managers.UserStorageSyncManager$2$1.call(UserStorageSyncManager.java:107)
	at org.keycloak.services.managers.UserStorageSyncManager$2$1.call(UserStorageSyncManager.java:102)
	at org.keycloak.cluster.infinispan.InfinispanClusterProvider.executeIfNotExecuted(InfinispanClusterProvider.java:78)
	at org.keycloak.services.managers.UserStorageSyncManager$2.run(UserStorageSyncManager.java:102)
	at org.keycloak.models.utils.KeycloakModelUtils.runJobInTransaction(KeycloakModelUtils.java:227)
	at org.keycloak.services.managers.UserStorageSyncManager.syncAllUsers(UserStorageSyncManager.java:92)
	at org.keycloak.services.resources.admin.UserStorageProviderResource.syncUsers(UserStorageProviderResource.java:142)
	at sun.reflect.GeneratedMethodAccessor891.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)

It turns out that i have to mapping “sAMAccountName” field to username. Can find the complete screenshot below,

Cheers (^)

Google+

Creating a Simple Openshift Pipeline for NodeJS 10 Apps with Jenkins Slave

Jenkins pipeline build have a slave mechanism, where it will spawn a new pod based on a specific image and will build on top of it. Slave mechanism have several benefits compared to traditional build, and one of the benefit is it can build with a different environment compared to jenkins master’s environment.

So, lets start with a simple docker file. We’ll create an imagestream using it, and will be used as a slave image. Basically it will use jenkins-slave-base-rhel7 as base image, and will install nodejs 10 on top of it.

oc new-build -D $'
FROM registry.access.redhat.com/openshift3/jenkins-slave-base-rhel7:v3.11
\n
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
\n
ENV NVM_DIR=/home/jenkins/.nvm \ NODE_VERSION=10.16.0
\n
RUN . "$NVM_DIR/nvm.sh" && nvm install ${NODE_VERSION} && nvm use v${NODE_VERSION} && nvm alias default v${NODE_VERSION}
\n
ENV PATH="/home/jenkins/.nvm/versions/node/v${NODE_VERSION}/bin/:${PATH}"
\n
RUN node --version && npm --version
\n
USER 1001' --name=new-jenkins-slave-node10-rhel7

And you can see the imagestream on Openshift,

Next step is, creating a Jenkins ephemeral on Openshift and creating new Jenkins slave with our newly created image.

oc new-app jenkins-persistent --param ENABLE_OAUTH=true --param MEMORY_LIMIT=2Gi --param VOLUME_CAPACITY=4Gi --param DISABLE_ADMINISTRATIVE_MONITORS=true -e OPENSHIFT_JENKINS_JVM_ARCH=i386  

For creating new slave, we can login to Jenkins page, open manage Jenkins menu, and go to Configure System menu, press Add Pod Template button.

Once successfully add new pod, we can start build our pipeline. Select New Item menu, add select Pipeline after that.Add put below code on Pipeline script,

def gitRepo="https://github.com/ariemay/node-test-app.git"
def branch="master"

node('new-jenkins-slave-node10-rhel7') {
    stage('test npm') {
        sh("node --version")
        sh("npm --version")
        sh("oc whoami")
    }
    stage ('pull code') {
        git branch: branch, url: gitRepo
    }
    stage ('build') {
        sh("npm install")
        sh("npm run build")
    }
    stage('check and prepare') {
        sh("cd /tmp")
        sh("pwd")
        sh("ls -alrth")
    }
    stage ('deploy') {
        try {
            sh("oc delete bc hello-react")
        } catch (Exception e) {
            sh("echo \"fail deleting bc \"")
        }
        try {
            sh("oc delete is hello-react")
        } catch (Exception e) {
            sh("echo \"fail deleting is \"")
        }
        try {
            sh("oc delete svc hello-react")
        } catch (Exception e) {
            sh("echo \"fail deleting svc \"")
        }
        try {
            sh("oc delete route hello-react")
        } catch (Exception e) {
            sh("echo \"fail deleting route \"")
        }
        sh("oc new-build --binary=true --name=hello-react --image-stream=nginx-112-rhel7")
        sh("oc start-build hello-react --from-dir=build --follow --wait" )

        try {
            sh("oc new-app  hello-react --name=hello-react" )
        } catch (Exception e) {
            sh("echo \"fail creating new-app, dc exists \"")
        }

        sh("oc expose svc/hello-react --name=hello-react")
    }
}

Press Build Now in order to see the build result,

We can see the url for result pod, and click it to see the built webpage.

So simple right?

Google+

Create A Simple Canary Deployment on Openshift

Openshift support multiple ways of deployements, such as traditional, canary and blue/green deployment. On this blog, im trying to create a simple canary deployment in order to see how can we leverage Openshift routing in deploy partially within a timeframe to reduce unwanted risks.

First we create two simple hello world app, one on top of PHP, and another one is on top of Java. We call my-blue and my-green. The goal of this scenario is to partially moving traffic from my-blue to my-green seamlessly.

oc new-app registry.access.redhat.com/redhat-openjdk-18/openjdk18-openshift~https://github.com/edwin/hello-world --name=my-blue
oc new-app php:7.0~https://github.com/edwin/php-helloworld --name=my-green

First is giving a 100percent traffic to my-blue microservice.

oc expose svc/my-blue --name=my-bluegreen

Then gradually reduce it to 75 percent,

oc set route-backends my-bluegreen my-blue=75 my-green=25 

And 15 percent,

oc set route-backends my-bluegreen my-blue=15 my-green=85 

Until the end is 100 percent of traffic goes to my-green.

oc set route-backends my-bluegreen my-green=100 

We can test the url output with below curl command

curl http://your-openshift-url
Google+