This repository contains the Java MicroProfile implementation of the Dessert Service which is a part of microservice-based reference application called What's For Dinner that can be found in https://github.com/ibm-cloud-architecture/refarch-cloudnative-wfd
- Introduction
- How it works
- API Endpoints
- Implementation
- Features and App details
- Building the app
- Running the app and stopping it
- DevOps Strategy
- References
This project demonstrates the implementation of Dessert Microservice. The dessert microservice retrieves the list of desserts from its data store.
- Based on MicroProfile.
- Integrated with the MicroService Builder.
- Deployment options for local, Docker Container-based runtimes, Minikube environment and ICP/BMX.
Dessert Microservice serves What's For Dinner, Microservice-based reference application. Though it is a part of a bigger application, Dessert service is itself an application in turn that gets the data from data store. This service reads the data and returns it through a REST service.
GET /WfdDessert/rest/health/ # Health check of the service
GET /WfdDessert/rest/dessert/ # Returns the desserts available
For Liberty, there is nice tool called Liberty Accelerator that generates a simple project based upon your configuration. Using this, you can build and deploy to Liberty either using the Maven or Gradle build.
Just check the options of your choice and click Generate project. You can either Download it as a zip or you can create git project.
Once you are done with this, you will have a sample microprofile based application that you can deploy on Liberty.
If you are using Liberty accelerator, look for the generated POM. It may contain unwanted dependencies. Please remove accordingly.
For our application, the following are the required dependencies which are the part of auto-generated POM. Please remove the rest of the dependencies.
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-client</artifactId>
<version>3.1.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.0.4</version>
<scope>test</scope>
</dependency>
Using Liberty Accelerator is your choice. You can also create the entire project manually, but using Liberty Accelerator will make things easier.
MicroProfile is an open platform that optimizes the Enterprise Java for microservices architecture. In this application, we are using MicroProfile 1.2. This includes
- MicroProfile 1.0 (JAX-RS 2.0, CDI 1.2, and JSON-P 1.0)
- MicroProfile 1.1 (MicroProfile 1.0, MicroProfile Config 1.0.)
- MicroProfile Config 1.1 (supercedes MicroProfile Config 1.0), MicroProfile Fault Tolerance 1.0, MicroProfile Health Check 1.0, MicroProfile Metrics 1.0, MicroProfile JWT Authentication 1.0.
You can make use of this feature by including this dependency in Maven.
<dependency>
<groupId>org.eclipse.microprofile</groupId>
<artifactId>microprofile</artifactId>
<version>1.2</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
You should also include a feature in server.xml.
<server description="Sample Liberty server">
<featureManager>
<feature>microprofile-1.2</feature>
</featureManager>
<httpEndpoint httpPort="${default.http.port}" httpsPort="${default.https.port}"
id="defaultHttpEndpoint" host="*" />
</server>
- Java SE 8 - Used Java Programming language
- CDI 1.2 - Used CDI for typesafe dependency injection
import javax.inject.Inject;
public class DessertResource {
@Inject
Config config;
}
- JAX-RS 2.0.1 - JAX-RS is used for providing both standard client and server APIs for RESTful communication by MicroProfile applications.
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/rest")
public class DessertApplication extends Application {
}
import javax.ws.rs.Path;
@Path("dessert")
public class AppetizerResource {
}
- Eclipse MicroProfile Config 1.1 - Configuration data comes from different sources like system properties, system environment variables, .properties etc. These values may change dynamically. Using this feature, helps us to pick up configured values immediately after they got changed.
The config values are sorted according to their ordinal. We can override the lower importance values from outside. The config sources by default, below is the order of importance.
- System.getProperties()
- System.getenv()
- all META-INF/microprofile-config.properties files on the ClassPath.
In our sample application, we obtained the configuration programatically. Below is the code snippet that shows it.
import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
public class AppetizerResource {
@GET
public Response getAllProperties(){
Config config = ConfigProvider.getConfig();
Dessert local = new Dessert();
local.setMenu(Arrays.asList(config.getValue("menu", String.class)));
local.setOrder(Integer.parseInt(config.getValue("order", String.class)));
local.setType(config.getValue("type", String.class));
return Response.ok(local, MediaType.APPLICATION_JSON).build();
}
}
To build the application, we used maven build. Maven is a project management tool that is based on the Project Object Model (POM). Typically, people use Maven for project builds, dependencies, and documentation. Maven simplifies the project build. In this task, you use Maven to build the project.
-
Clone this repository.
git clone https://github.com/ibm-cloud-architecture/refarch-cloudnative-wfd-dessert.git
-
Checkout MicroProfile branch.
git checkout microprofile
-
cd refarch-cloudnative-wfd-dessert/
-
Run this command. This command builds the project and installs it.
mvn install
If this runs successfully, you will be able to see the below messages.
[INFO] --- maven-failsafe-plugin:2.18.1:verify (verify-results) @ WfdDessert ---
[INFO] Failsafe report directory: /Users/user@ibm.com/PurpleCompute/Microprofile/WhatsForDinner/refarch-cloudnative-wfd-dessert/target/test-reports/it
[INFO]
[INFO] --- maven-install-plugin:2.4:install (default-install) @ WfdDessert ---
[INFO] Installing /Users/user@ibm.com/PurpleCompute/Microprofile/WhatsForDinner/refarch-cloudnative-wfd-dessert/target/WfdDessert-1.0-SNAPSHOT.war to /Users/user@ibm.com/.m2/repository/projects/WfdDessert/1.0-SNAPSHOT/WfdDessert-1.0-SNAPSHOT.war
[INFO] Installing /Users/user@ibm.com/PurpleCompute/Microprofile/WhatsForDinner/refarch-cloudnative-wfd-dessert/pom.xml to /Users/user@ibm.com/.m2/repository/projects/WfdDessert/1.0-SNAPSHOT/WfdDessert-1.0-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 19.873 s
[INFO] Finished at: 2017-11-02T14:55:52-05:00
[INFO] Final Memory: 19M/304M
[INFO] ------------------------------------------------------------------------
- Locally in JVM
To run the What's For Dinner application locally in JVM, please complete the Building the app section.
- Locally in Containers
To run the What's For Dinner application locally in container, you need Docker to be locally present in your system.
- Locally in Minikube
To run the What's For Dinner application locally on your laptop on a Kubernetes-based environment such as Minikube (which is meant to be a small development environment) we first need to get few tools installed:
- Kubectl (Kubernetes CLI) - Follow the instructions here to install it on your platform.
- Helm (Kubernetes package manager) - Follow the instructions here to install it on your platform.
Finally, we must create a Kubernetes Cluster. As already said before, we are going to use Minikube:
- Minikube - Create a single node virtual cluster on your workstation. Follow the instructions here to get Minikube installed on your workstation.
We not only recommend to complete the three Minikube installation steps on the link above but also read the Running Kubernetes Locally via Minikube page for getting more familiar with Minikube. We can learn there interesting things such as reusing our Docker daemon, getting the Minikube's ip or opening the Minikube's dashboard for GUI interaction with out Kubernetes Cluster.
- Remotely in ICP
To run the What's For Dinner application on IBM Cloud Private, we first need to get few tools installed:
-
Kubectl (Kubernetes CLI) - Follow the instructions here to install it on your platform.
-
IBM Cloud Private. You can find the detailed installation instructions here.
Along with these, you also need a JSON processor utility.
- In our sample, we used Microservice Builder as our Devops strategy. To ensure continuous delivery and deployment, you need a continuous integration pipeline and Microservice Builder serves this purpose so very well. In order to take advantage of this, you need to setup the Microservice Builder pipeline. To find instructions on how to set your Microservice Builder pipeline up, click here.
-
Now start your server.
mvn liberty:start-server
You will see the below.
[INFO] Starting server defaultServer.
[INFO] Server defaultServer started with process ID 41243.
[INFO] Waiting up to 30 seconds for server confirmation: CWWKF0011I to be found in /Users/user@ibm.com/PurpleCompute/Microprofile/WhatsForDinner/refarch-cloudnative-wfd-dessert/target/liberty/wlp/usr/servers/defaultServer/logs/messages.log
[INFO] CWWKM2010I: Searching for CWWKF0011I in /Users/user@ibm.com/PurpleCompute/Microprofile/WhatsForDinner/refarch-cloudnative-wfd-dessert/target/liberty/wlp/usr/servers/defaultServer/logs/messages.log. This search will timeout after 30 seconds.
[INFO] CWWKM2015I: Match number: 1 is [11/2/17 15:01:40:925 CDT] 00000019 com.ibm.ws.kernel.feature.internal.FeatureManager A CWWKF0011I: The server defaultServer is ready to run a smarter planet..
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 14.749 s
[INFO] Finished at: 2017-11-02T15:01:40-05:00
[INFO] Final Memory: 9M/309M
[INFO] ------------------------------------------------------------------------
- Now, go to your browser and access the REST endpoint at
http://localhost:9080/WfdDessert/rest/dessert
.
Access URL : http://<HOST>:<PORT>/<WAR_CONTEXT>/<APPLICATION_PATH>/<ENDPOINT>
In our sample application, you can get the details of the above URL as follows.
- Since, we are running the application locally on our system, the HOST will be
localhost
. - You can get the PORT and WAR_CONTEXT from the
<properties> </properties>
section of our POM.
<app.name>WfdDessert</app.name>
<testServerHttpPort>9080</testServerHttpPort>
<testServerHttpsPort>9443</testServerHttpsPort>
<warContext>${app.name}</warContext>
So, PORT will be 9080
and WAR_CONTEXT will be WfdDessert
.
- APPLICATION_PATH can be found in DessertApplication.java
@ApplicationPath("/rest")
In our sample, the APPLICATION_PATH will be rest
.
- Finally you can find the dessert endpoint at DessertResource.java
@Path("dessert")
So, ENDPOINT to access the rest api that exposes the list of desserts is dessert
.
Also, there is one more endpoint defined at HealthEndpoint.java
@Path("health")
To access the health api, replace the ENDPOINT with health
. This endpoint gives the health of your application. To check this, use http://localhost:9080/WfdDessert/rest/health.
-
If you are done accessing the application, you can stop your server using the following command.
mvn liberty:stop-server
Once you do this, you see the below messages.
[INFO] CWWKM2001I: Invoke command is [/Users/user@ibm.com/PurpleCompute/Microprofile/WhatsForDinner/refarch-cloudnative-wfd-dessert/target/liberty/wlp/bin/server, stop, defaultServer].
[INFO] objc[45406]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/bin/java (0x1013de4c0) and /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/libinstrument.dylib (0x1014d84e0). One of the two will be used. Which one is undefined.
[INFO] Stopping server defaultServer.
[INFO] Server defaultServer stopped.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.988 s
[INFO] Finished at: 2017-11-02T15:15:06-05:00
[INFO] Final Memory: 9M/309M
[INFO] ------------------------------------------------------------------------
To run the application in docker, we first need to define a Docker file.
We are using Docker to containerize the application. With Docker, you can pack, ship, and run applications on a portable, lightweight container that can run anywhere virtually.
FROM websphere-liberty:microProfile
MAINTAINER IBM Java engineering at IBM Cloud
COPY /target/liberty/wlp/usr/servers/defaultServer /config/
COPY target/liberty/wlp/usr/shared /opt/ibm/wlp/usr/shared/
RUN wget -t 10 -x -nd -P /opt/ibm/wlp/usr https://repo1.maven.org/maven2/net/wasdev/wlp/tracer/liberty-opentracing-zipkintracer/1.0/liberty-opentracing-zipkintracer-1.0-sample.zip && cd /opt/ibm/wlp/usr && unzip liberty-opentracing-zipkintracer-1.0-sample.zip && rm liberty-opentracing-zipkintracer-1.0-sample.zip
# Install required features if not present
RUN installUtility install --acceptLicense defaultServer
CMD ["/opt/ibm/wlp/bin/server", "run", "defaultServer"]
- The
FROM
instruction sets the base image. You're setting the base image towebsphere-liberty:microProfile
. - The
MAINTAINER
instruction sets the Author field. Here it isIBM Java engineering at IBM Cloud
. - The
COPY
instruction copies directories and files from a specified source to a destination in the container file system.- You're copying the
/target/liberty/wlp/usr/servers/defaultServer
to theconfig
directory in the container. - You're replacing the contents of
/opt/ibm/wlp/usr/shared/
with the contents oftarget/liberty/wlp/usr/shared
.
- You're copying the
- The
RUN
instruction runs the commands.- The first instruction gets the Opentracing Zipkin feature and installs it in your server.
- The second instruction is a precondition to install all the utilities in the server.xml file. You can use the RUN command to install the utilities on the base image.
- The
CMD
instruction provides defaults for an executing container.
- Build the docker image.
docker build -t wfd-dessert:microprofile .
Once this is done, you will see something similar to the below messages.
Successfully built 8f9eccaa2bde
Successfully tagged wfd-dessert:microprofile
You can see the docker images by using this command.
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
wfd-dessert microprofile 8f9eccaa2bde 16 seconds ago 377MB
- Run the docker image.
docker run -p 9080:9080 --name dessert -t wfd-dessert:microprofile
When it is done, you will see the following output.
[AUDIT ] CWWKZ0058I: Monitoring dropins for applications.
[AUDIT ] CWWKT0016I: Web application available (default_host): http://71ce09bd69c6:9080/health/
[AUDIT ] CWWKT0016I: Web application available (default_host): http://71ce09bd69c6:9080/jwt/
[AUDIT ] CWWKT0016I: Web application available (default_host): http://71ce09bd69c6:9080/ibm/api/
[AUDIT ] CWWKT0016I: Web application available (default_host): http://71ce09bd69c6:9080/metrics/
[AUDIT ] CWWKT0016I: Web application available (default_host): http://71ce09bd69c6:9080/WfdDessert/
[AUDIT ] CWWKZ0001I: Application WfdDessert-1.0-SNAPSHOT started in 1.107 seconds.
[AUDIT ] CWWKF0012I: The server installed the following features: [microProfile-1.2, mpFaultTolerance-1.0, servlet-3.1, ssl-1.0, jndi-1.0, mpHealth-1.0, appSecurity-2.0, jsonp-1.0, mpConfig-1.1, jaxrs-2.0, jaxrsClient-2.0, concurrent-1.0, jwt-1.0, mpMetrics-1.0, mpJwt-1.0, json-1.0, cdi-1.2, distributedMap-1.0].
[AUDIT ] CWWKF0011I: The server defaultServer is ready to run a smarter planet.
- Now, view the REST endpoint at
http://localhost:9080/WfdDessert/rest/dessert
.
Access URL : http://<HOST>:<PORT>/<WAR_CONTEXT>/<APPLICATION_PATH>/<ENDPOINT>
-
Once you make sure the application is working as expected, you can come out of the process. You can do this by pressing Ctrl+C on the command line where the server was started.
-
You can also remove the container if desired. This can be done in the following way.
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
71ce09bd69c6 wfd-dessert:microprofile "/opt/ibm/wlp/bin/..." About a minute ago Up About a minute 0.0.0.0:9080->9080/tcp, 9443/tcp dessert
Grab the container id.
- Do
docker stop <CONTAINER ID>
In this case it will be,docker stop 71ce09bd69c6
- Do
docker rm <CONTAINER ID>
In this case it will be,docker rm 71ce09bd69c6
- Start your minikube. Run the below command.
minikube start
You will see output similar to this.
Setting up certs...
Connecting to cluster...
Setting up kubeconfig...
Starting cluster components...
Kubectl is now configured to use the cluster.
- To install Tiller which is a server side component of Helm, initialize helm. Run the below command.
helm init
If it is successful, you will see the below output.
$HELM_HOME has been configured at /Users/user@ibm.com/.helm.
Tiller (the helm server side component) has been installed into your Kubernetes Cluster.
Happy Helming!
- Check if your tiller is available. Run the below command.
kubectl get deployment tiller-deploy --namespace kube-system
If it available, you can see the availability as below.
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
tiller-deploy 1 1 1 1 1m
- Run the below command to add IBM helm repository
helm repo add ibm-charts https://raw.githubusercontent.com/IBM/charts/master/repo/stable/
If added, you will see the below message.
"ibm-charts" has been added to your repositories
- Build the docker image.
Before building the docker image, set the docker environment.
- Run the below command.
minikube docker-env
You will see the output similar to this.
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.100:2376"
export DOCKER_CERT_PATH="/Users/user@ibm.com/.minikube/certs"
export DOCKER_API_VERSION="1.23"
# Run this command to configure your shell:
# eval $(minikube docker-env)
- For configuring your shell, run the below command.
eval $(minikube docker-env)
- Now run the docker build.
docker build -t wfddessert:v1.0.0 .
If it is a success, you will see the below output.
Successfully built 9612f94ae9dc
Successfully tagged wfddessert:v1.0.0
- Run the helm chart as below.
helm install --name=wfddessert chart/wfddessert
Yow will see message like below.
==> v1beta1/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
wfddessert-deployment 1 1 1 0 1s
Please wait till your deployment is ready. To verify run the same command and you should see the availability.
==> v1beta1/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
wfddessert-deployment 1 1 1 1 1s
- You can access the application at
http://<MinikubeIP>:<PORT>/<WAR_CONTEXT>/<APPLICATION_PATH>/<ENDPOINT>
. To get the access url.
- To get the IP, Run this command.
minikube ip
You will see something like below.
192.168.99.100
- To get the port, run this command.
kubectl get service wfddessert-service
You will see something like below.
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
wfddessert-service 10.0.0.31 <nodes> 9080:31352/TCP,9443:31477/TCP 1m
In the above case, the access url will be http://192.168.99.100:31352/WfdDessert/rest/dessert
.
IBM Private Cloud is has all the advantages of public cloud but is dedicated to single organization. You can have your own security requirements and customize the environment as well. Basically it has tight security and gives you more control along with scalability and easy to deploy options. You can run it externally or behind the firewall of your organization.
Basically this is an on-premise platform.
- Includes docker container manager
- Kubernetes based container orchestrator
- Graphical user interface
You can find the detailed installation instructions for IBM Cloud Private here
Before running the application, make sure you added the docker registry secret.
- Install the jq command line JSON processor utility.
yum install -y jq
or
apt install -y jq
-
log in to the IBM Cloud Private. Login as admin user.
-
Go to admin > Configure Client.
-
Grab the kubectl configuration commands.
-
Run those commands at your end.
-
Create docker-registry secret admin.registrykey. This allows the pipeline to access the Docker registry.
kubectl create secret docker-registry admin.registrykey --docker-server=https://mycluster.icp:8500 --docker-username=admin --docker-password=admin --docker-email=null
- Now update the service account with the image pull secret.
kubectl get serviceaccounts default -o json |jq 'del(.metadata.resourceVersion)' |jq 'setpath(["imagePullSecrets"];[{"name":"admin.registrykey"}])' |kubectl replace serviceaccount default -f -
Once you have all this, you are ready to deploy your microservice to Microservice builder on IBM Cloud private.
- Now you have your microservice builder pipeline configured.
- Push the project to the repository that is monitored by your micro service builder pipeline.
- It will automatically pick the project, build it and deploy it to IBM cloud private.
To access the sample application, go to IBM Cloud Private dashboard.
- Go to Workload > Services > wfdui and click on it.
- You can see the service like below.
Click on the http link there. You will be redirected to the UI.
We opted Microservice Builder as our continuos delivery pipeline. It helps us to maintain the application end to end from development to production supporting continuous delivery. It helps us to develop and deploy microservice based applications. Using the pre-integrated Devops pipeline, developers can rapidly build innovative services and deploy them easily.
Microservice Builder runs on a Jenkins pipeline. Basically Jenkins runs in a docker container and it is deployed on Kubernetes using helm. This jenkins should be integrated with the Github. The repository to which you push the code should be integrated to Microservice Builder pipeline through Github. Then only Microservice Builder will be able to pick your code.
Microservice builder has an option to deploy with IBM Cloud Private. You can set IBM Private Cloud with Microservice Builder pipeline to deploy the microservices.
From IBM cloud private dashboard, you can access the MSB pipeline from your services. The jenkins pipeline is as follows.
By clicking on the name of your organization, you can find all the MSB enabled repositories here.
By clicking on the refarch-cloudnative-wfd-dessert, you can see the below screen.
If you see a blue ball there, your service is successfully built and running fine. If it red, it means you have some problems with it.
Whenever you do some changes and push the code to this repository, MSB build queue will initiate the process.
Once this is done, Jenkins slave will be called.
Then the Jenkins slave will pick up the build and initiate the process.
Then the build will begin and starts running.
Finally your service gets deployed once the build is done.
To access your service, go to IBM Cloud Private dashboard.
- Go to Workload > Services > wfddessert-service and click on it.
- You can see the service like below.
Click on the http link there. You will be redirected to the Server page. Append /WfdDessert/rest/dessert to the url and you will be able to see the Dessert service.