Deploying a Spring IBM Graph Application to Bluemix Kubernetes

Share this post:

In this blog post, I’ll describe the process of connecting an IBM Graph service on Bluemix with a Spring application.  Then we’ll deploy that application to a Bluemix Kubernetes cluster, using Kubernetes secrets to securely pass configuration credentials.

Prerequisites

Before you begin, you’ll need to have the following installed and configured on your PATH:

I will also assume that you are logged into the Bluemix CLI and the Bluemix Container Registry CLI.  You should also have a Kubernetes cluster created in Bluemix, and configured with the Kubernetes CLI.

Setting up project

Setup Maven

In the directory you’ve chosen to use for this project, create a pom.xml file with the following contents:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://bit.ly/2vBpaJm" xmlns:xsi="http://bit.ly/2uCbrop" xsi:schemaLocation="http://bit.ly/2vBpaJm http://bit.ly/2vBgMJV">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>spring-data-ibmgraph</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.ibm.graph</groupId>
            <artifactId>graphclient</artifactId>
            <version>0.1.0</version>
        </dependency>
        <dependency>
            <groupId>io.fabric8</groupId>
            <artifactId>spring-cloud-starter-kubernetes</artifactId>
            <version>0.1.6</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>io.fabric8</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <extensions>true</extensions>
                <configuration>
                    <images>
                        <image>
                            <name>http://bit.ly/2uBX1oi;
                            <build>
                                <from>java:8</from>
                                <entryPoint>
                                    <exec>
                                        <arg>java</arg>
                                        <arg>-jar</arg>
                                        <arg>-Dspring.cloud.kubernetes.secrets.paths=/etc/secret</arg>
                                        <arg>/${project.build.finalName}.jar</arg>
                                    </exec>
                                </entryPoint>
                                <assembly>
                                    <targetDir>/</targetDir>
                                    <mode>dir</mode>
                                    <descriptorRef>artifact</descriptorRef>
                                </assembly>
                            </build>
                        </image>
                    </images>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Create IBM Graph service

Now we will create an instance of IBM Graph.  Open the Bluemix catalog and find IBM Graph under Services and Data & Analytics.  If you need to change the configuration, do so now.  I will keep the default settings for my application.  When you’re ready, click Create.

Once your service has been created, you should see a button to open the IBM Graph interface.  Press this button and you will be taken to another page.

With your IBM Graph interface open, click Samples on the left side of the interface.  Find the Music Festival sample, then click Load to bring this data into your graph.  We will use this data to demonstrate that our Spring application is able to connect to the IBM Graph service and execute Gremlin queries.

Building the application

Create basic application files

The first file we create will be Application.java. This file will be very familiar if you have worked with Spring before.  Create Application.java with the following contents:

package example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableAutoConfiguration
@ComponentScan(lazyInit = true)
public class Application {

    public static void main(String[] args) {
        System.setProperty("kubernetes.master", "168.1.8.195:27993");

        SpringApplication.run(Application.class, args);
    }
}

In the first line of the main method, you will need to insert the IP address of your Kubernetes master. You can find this information with the following command:

$ kubectl cluster-info

Another thing to notice is we have enabled lazyInit in the @ComponentScan annotation. This will delay the instantiation of our graph client bean until we reference it, rather than having it be instantiated eagerly with the other beans. Otherwise, our configuration values would be requested before they are available.

Configure IBMGraphClient bean

Spring Data does not include support for IBM Graph, so we will use the java-graph client to connect to our service.  First we will configure a Spring bean to simplify the instantiation and configuration of the graph client. Create an IBMGraphClientConfig.java file with the following contents:

package example;

import com.ibm.graph.client.IBMGraphClient;
import com.ibm.graph.client.exception.GraphClientException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class IBMGraphClientConfig {

    @Value("${ibmgraph.apiurl}")
    String apiurl;
    @Value("${ibmgraph.username}")
    String username;
    @Value("${ibmgraph.password}")
    String password;

    @Bean
    public IBMGraphClient ibmGraphClient () throws GraphClientException {
        return new IBMGraphClient(apiurl, username, password);
    }
}

This file will allow us to use the @Autowired annotation with our IBMGraphClient. Next we will see how this all works in a REST controller!

Create a controller

Now we’ll create a simple REST controller that executes a Gremlin query and returns the JSON response from our IBM Graph.  Create a MainController.java file with the following contents:

package example;

import com.ibm.graph.client.exception.GraphClientException;
import com.ibm.graph.client.exception.GraphException;
import com.ibm.graph.client.response.ResultSet;
import org.apache.wink.json4j.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MainController {

    @Autowired @Lazy
    private IBMGraphClient graphClient;

    @RequestMapping("/gremlin")
    public @ResponseBody JSONObject gremlin() throws GraphClientException, GraphException {
        ResultSet r = graphClient.executeGremlin("def gt = graph.traversal();" +
                        "gt.V().hasLabel(\"attendee\").has(\"name\", \"Jane Doe\")" +
                        ".out(\"bought_ticket\").values(\"name\");");

        return r.getResponse();
    }
}

Notice that we must use the @Lazy annotation when we inject an instance of IBMGraphClient to use here.  We enabled this annotation earlier, but now we are specifying where we actually want to apply it.

If you want to try out any additional Gremlin queries, such as the ones provided in the IBM Graph tutorial, you can setup a few more endpoints similarly to how I have shown.

Deploying to Bluemix Kubernetes

Build application Docker image

In the pom.xml file I provided at the beginning of this blog post, I included a plugin for working with Docker images.  I will use that plugin to build my image and push it to my private Bluemix registry, but if you chose not to include that plugin you can do this manually.

Use the following command to package your application, build it into a Docker image, and push to your private registry:

$ mvn package docker:build docker:push

Note: For this to work, you must have replaced NAMESPACE in the pom.xml file with your own Bluemix namespace.  For help on creating a Bluemix namespace, see the Bluemix instructions.

Create deployment files

Now we let’s create a couple YAML files to deploy to our Kubernetes cluster.  We will need a file to create our secret (containing the IBM Graph configuration), our application pod, and a service.

First, create a secret.yaml file with the following contents:

apiVersion: v1
kind: Secret
metadata:
  name: ibmgraph-secret
type: Opaque
data:
  ibmgraph.apiurl: BASE64_ENCODED_APIURL
  ibmgraph.username: BASE64_ENCODED_USERNAME
  ibmgraph.password: BASE64_ENCODED_PASSWORD

You will need to produce the base64-encoded strings of your IBM Graph credentials and replace the values I indicated. You can find the credentials in your IBM Graph service on Bluemix under the Service credentials tab.  You can use the following command to produce the base64-encoded string:

$ echo -n "VALUE_TO_ENCODE" | base64
BASE64_ENCODED_VALUE

The resulting string is the value you should put in the secret.yaml file created above. Be sure to encode your apiURL, username, and password from Bluemix.

Next create a pod-service.yaml file with the following contents:

apiVersion: v1
kind: Service
metadata:
  name: spring-data-service
  namespace: default
spec:
  type: NodePort
  ports:
    - port: 8080
  selector:
    name: spring-data-ibmgraph

---
apiVersion: v1
kind: Pod
metadata:
  name: spring-data-ibmgraph
  labels:
    name: spring-data-ibmgraph
spec:
  containers:
    - name: spring-data-ibmgraph
      image: http://bit.ly/2vBEPIV
      ports:
        - containerPort: 8080
      volumeMounts:
        - name : ibmgraph-secret-vol
          mountPath : /etc/secret
          readOnly : true
  volumes:
    - name : ibmgraph-secret-vol
      secret :
        secretName: ibmgraph-secret

This deployment file is fairly straightforward. The service defined exposes the default Spring application port (8080) as a NodePort. In the pod created, we mount a volume corresponding to the secret created in the secret.yaml file. This will make the credentials encoded in the secrets available to the application container.

Deploy to cluster

Now we are ready to run our Spring application on our Bluemix Kubernetes cluster!  Create a proxy connection to your cluster with the following command:

$ kubectl proxy

Then navigate to the Kubernetes dashboard at: 127.0.0.1:8001/ui.

From the dashboard, click CREATE in the top-right corner, then select the Upload a YAML or JSON file option, and choose your secret.yaml file.  Upload this file with the UPLOAD button.  Then follow the same procedure with your pod-service.yaml file.

Once your pod has finished starting up, you can visit your app at the public node IP and the port exposed by your service.  To find the public node IP, click Nodes on the left sidebar and use the name of the node that your pod is running on (there should only be one node if you are using a Lite cluster plan).  To find the service NodePort, click Services on the left sidebar and find the port number (in the range 30000-32767) associated with the “spring-data-service” service.

Using these values, assemble the URL and visit your app at the <code>/gremlin</code> endpoint.  For my cluster, this would be:

$ curl http://bit.ly/2uCvXFH
{"result":{"data":["Bad Bad Not Good","Grimes","Joey Badass","Kendrick Lamar","Freddie Gibbs","St. Lucia","The Kills","Declan McKenna","Bad Bad Not Good","Freddie Gibbs","Grimes","Kendrick Lamar","Declan McKenna","Joey Badass","St. Lucia","The Kills","Bad Bad Not Good","Freddie Gibbs","Grimes","St. Lucia","Joey Badass","Declan McKenna","Kendrick Lamar","The Kills"],"meta":{}},"requestId":"57ecb797-7ace-4aff-98a4-43ec7858ef51","status":{"code":200,"attributes":{},"message":""}}

Conclusion

We have now created a Spring application that interfaces with a Bluemix IBM Graph service and deployed it to Bluemix Kubernetes.  This service had one REST endpoint, which executed a predefined Gremlin query.  Using the concepts from this blog post, you can now expand the functionality with other queries specific to your needs.

#bluemix,#hybridcloud,#ibm,#awvi

Bluemix

via Bluemix Blog https://ibm.co/2pQcNaA

July 18, 2017 at 11:36AM