Tuesday, April 23, 2019

Red Hat Decision Manager on Heroku

Introduction


Salesforce is a very popular CRM and if you use it most likely you have developed quite sophisticated workflows on it. Most importantly you may have the need to automate complex logic as well as allow non-technical users to configure this logic by themselves without waiting for a programmer to implement it. If this is the case business rules are definitely the right approach. Having business rules in Salesforce is a critical requirement. 

What about using Drools, the popular open source rule engine? Or Red Hat Decision Manager, the supported version of Drools? Any third party business rules engine will need to get input data from Salesforce through some of the available API's. The issue is that there are limits on the number of such calls as well as a cost.

There is a solution to this problem. Salesforce acquired Heroku in 2010. Heroku offers a cloud application development platform. If you are a Salesforce customer and develop applications on Heroku you can take advantage of an add-on called Heroku Connect. This add-on synchronizes Salesforce data with a Postgres database running on the Heroku platform without suffering the limitations or cost mentioned earlier. Clearly Salesforce wants to motivate developers to use Heroku as the platform for serious Salesforce applications.

The solution is now clear: run the KIE Server, Drools business rules and business process run time, on Heroku, and leverage the Heroku Connect Postgres database to read data to process from it as well as to write the output of business rules execution to it.

The question is then how do you get the KIE Server to run on Heroku? Not only that but how can you run Red Hat Decision Manager as a licensed Red Hat customer on Heroku and still get support? Customers can create custom container images with a Red Hat product and still get a reasonable level of support for that product as long as they follow certain rules when customizing the Red Hat official container image for that product. The Red Hat official container image is intended to be deployed on Red Hat Openshift and that is the platform where it receives full support. Heroku is definitely not a supported platform. For Red Hat granting you an exception and give reasonable commercial support in this case is critical that the amount of customization required to get Red Hat Decision Manager KIE Server run on Heroku is absolutely minimal.

Bear in mind that the Heroku platform compared with Red Hat Openshift for example has quite a few critical limitations.

Heroku applications are normally deployed and execute in a container technology called Dyno. This technology is not compatible with OCI container images such as the ones used by Docker or Openshift. An OCI container runs on Heroku on top of a Dyno. The problem is that a Dyno cannot have persistent volume. If a Heroku developer needs persistent volume he has to use a Postgres database available on Heroku. This pretty much rule out deploying Business Central on Heroku because a persistent volume is needed by this application. Business Central will have to run somewhere else where persistent volume is available and deploy the KIE container generated from the business rules project to a KIE Server running on Heroku. In fact one could simply add the business rules executable artifact to the KIE Server image during a custom build and then deploy it with the KIE Container already there. To keep it as simple as possible you will not do that in this exercise.

Another Heroku requirement is that the HTTP port where the KIE Server listens to must be defined as the environmant variable PORT. None of the other ports exposed by JBoss EAP can be exposed because there is only one PORT variable available.

With this limitations in mind you can now proceed with the exercise.

Of course I cannot promise that such a procedure will deploy a Red Hat Decision Manager KIE Server on Heroku that Red Hat will support. The only modification being the HTTP port one can hope that an exception can be made.

Deployment Exercise


Login to the Red Hat Container Registry with docker and pull the latest Red Hat Decision Manager KIE Server container image (version 7.3 at the time of this writing). Run the image and test that it is fine by requesting the server information through the KIE Server REST API. Make sure that you are using the port mapped to 8080 by docker and that you are authenticating to the server with the default credentials.

> docker login registry.access.redhat.com
Username:
Password:
Login Succeeded
> docker pull registry.access.redhat.com/rhdm-7/rhdm73-kieserver-openshift
Using default tag: latest
latest: Pulling from rhdm-7/rhdm73-kieserver-openshift
da59b306fcf5: Pull complete
e23b0afac3fa: Pull complete
e03525c718c9: Pull complete
Digest: sha256:beb8b7bf681be5e94133da9f38e9c3c14c75509a375cc18eb56ae643b4711de7
Status: Downloaded newer image for registry.access.redhat.com/rhdm-7/rhdm73-kieserver-openshift:latest
> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry.access.redhat.com/rhdm-7/rhdm73-kieserver-openshift latest ec749fcd647d 4 weeks ago 858MB
> docker run \
> -e KIE_SERVER_USER=kieserver -e KIE_SERVER_PWD=kieserver1! \
> -dP registry.access.redhat.com/rhdm-7/rhdm73-kieserver-openshift
820b3763e6034ace04872cd2bcd5217a21b7c3a10dc25fe9356b9524208bb79c
> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
820b3763e603 registry.access.redhat.com/rhdm-7/rhdm73-kieserver-openshift "/opt/eap/bin/opensh…" 20 seconds ago Up 18 seconds 0.0.0.0:32770->8080/tcp, 0.0.0.0:32769->8443/tcp, 0.0.0.0:32768->8778/tcp agitated_hofstadter
> curl --user kieserver:kieserver1! -X GET "http://localhost:32770/services/rest/server" -H "accept: application/json"
{
"type" : "SUCCESS",
"msg" : "Kie Server info",
"result" : {
"kie-server-info" : {
"id" : "820b3763e603",
"version" : "7.18.0.Final-redhat-00002",
"name" : "820b3763e603",
"location" : "http://820b3763e603:8080/services/rest/server",
"capabilities" : [ "KieServer", "BRM", "BRP", "DMN", "Swagger" ],
"messages" : [ {
"severity" : "INFO",
"timestamp" : {
"java.util.Date" : 1555860082480
},
"content" : [ "Server KieServerInfo{serverId='820b3763e603', version='7.18.0.Final-redhat-00002', name='820b3763e603', location='http://820b3763e603:8080/services/rest/server', capabilities=[KieServer, BRM, BRP, DMN, Swagger]', messages=null', mode=DEVELOPMENT}started successfully at Sun Apr 21 15:21:22 UTC 2019" ]
} ],
"mode" : "DEVELOPMENT"
}
}
}
view raw gistfile1.txt hosted with ❤ by GitHub

The Red Hat official container images are intended for deployment on OpenShift. The container CMD is /opt/eap/bin/openshift-launch.sh. If you login to the container and view this script you will see that it starts the JBoss EAP server with a configuration file called standalone-openshift.xml. Copy this JBoss EAP configuration file from the container to the local directory.

> docker cp agitated_hofstadter:/opt/eap/standalone/configuration/standalone-openshift.xml
view raw gistfile1.txt hosted with ❤ by GitHub

The HTTP port is bound in the socket-binding-group section in several places.

<socket-binding-group name="standard-sockets" default-interface="public" port-offset="0">
<socket-binding name="management-http" interface="management" port="${jboss.management.http.port:9990}"/>
<socket-binding name="management-https" interface="management" port="${jboss.management.https.port:9993}"/>
<socket-binding name="ajp" interface="bindall" port="${jboss.ajp.port:8009}"/>
<socket-binding name="http" interface="bindall" port="${jboss.http.port:8080}"/>
<socket-binding name="https" interface="bindall" port="${jboss.https.port:8443}"/>
<socket-binding name="jgroups-mping" interface="private" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45700"/>
<socket-binding name="jgroups-tcp" interface="private" port="7600"/>
<socket-binding name="jgroups-udp" interface="private" port="55200" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45688"/>
<socket-binding name="modcluster" multicast-address="${jboss.modcluster.multicast.address:224.0.1.105}" multicast-port="23364"/>
<outbound-socket-binding name="http-messaging">
<remote-destination host="${jboss.messaging.host:localhost}" port="${jboss.http.port:8080}"/>
</outbound-socket-binding>
<socket-binding name="messaging" port="5445"/><socket-binding name="messaging-throughput" port="5455"/>
<!-- ##AMQ_MESSAGING_SOCKET_BINDING## -->
<socket-binding name="txn-recovery-environment" port="4712"/>
<socket-binding name="txn-status-manager" port="4713"/>
<outbound-socket-binding name="mail-smtp">
<remote-destination host="localhost" port="25"/>
</outbound-socket-binding>
</socket-binding-group>
view raw gistfile1.txt hosted with ❤ by GitHub

You just need to replace it with the environment variable PORT as expected by Heroku.

> sed -i 's/{jboss.http.port:8080}/{env.PORT}/g' standalone-openshift.xml
view raw gistfile1.txt hosted with ❤ by GitHub

Now create a .dockerignore file with this content:

.git
README.md
.DS_Store
view raw gistfile1.txt hosted with ❤ by GitHub

as well as a Dockerfile such as this:

# Base image
FROM registry.access.redhat.com/rhdm-7/rhdm73-kieserver-openshift
# set server access credentials
ENV KIE_SERVER_USER=kieserver
ENV KIE_SERVER_PWD=kieserver1!
# Customize EAP configuration file
RUN sed -i 's/{jboss.http.port:8080}/{env.PORT}/g' /opt/eap/standalone/configuration/standalone-openshift.xml
# Update permissions on the customized file
USER root
RUN chown jboss:root /opt/eap/standalone/configuration/standalone-openshift.xml
# Run as user jboss
USER jboss
view raw gistfile1.txt hosted with ❤ by GitHub

Setting the server user credentials in the Dockerfile should not be necessary since it should be possible to pass them as arguments during build but it does not seem to be working. More about this in a moment. Now login to the Heroku CLI and then to the Heroku container registry. Create the Heroku app and then run the container:push command which builds the image and push it to the registry. According to the documentation one should be able to set environment variables in the image during build with --arg VAR1=val1,VAR2=val2 but it did not work for me. Once the image is in the registry the container:release command makes it available and you can test that the KIE server is indeed running on Heroku.

> heroku login -i
heroku: Enter your login credentials
Email [myself@gcompany.com]:
Password: ************
Logged in as myself@company.com
> heroku container:login
Login Succeeded
> heroku create
Creating app... done, ⬢ obscure-beyond-63219
https://obscure-beyond-63219.herokuapp.com/ | https://git.heroku.com/obscure-beyond-63219.git
> heroku container:push web -a obscure-beyond-63219
=== Building web (/home/ec2-user/Demos/rhdm7-kieserver-heroku/Dockerfile)
Sending build context to Docker daemon 102.4kB
Step 1/7 : FROM registry.access.redhat.com/rhdm-7/rhdm73-kieserver-openshift
---> ec749fcd647d
Step 2/7 : ENV KIE_SERVER_USER=kieserver
---> Running in 8f9cc2d8c21e
Removing intermediate container 8f9cc2d8c21e
---> 82cbe036498f
Step 3/7 : ENV KIE_SERVER_PWD=kieserver1!
---> Running in bf0206978a16
Removing intermediate container bf0206978a16
---> 7f94b011ee66
Step 4/7 : RUN sed -i 's/{jboss.http.port:8080}/{env.PORT}/g' /opt/eap/standalone/configuration/standalone-openshift.xml
---> Running in 7aabf976c1da
Removing intermediate container 7aabf976c1da
---> 3cfadd3379b8
Step 5/7 : USER root
---> Running in ff6f12fb3847
Removing intermediate container ff6f12fb3847
---> 9677ba2dc325
Step 6/7 : RUN chown jboss:root /opt/eap/standalone/configuration/standalone-openshift.xml /opt/eap/bin/openshift-launch.sh
---> Running in aeac5b7f3def
Removing intermediate container aeac5b7f3def
---> 925b9a2e5568
Step 7/7 : USER jboss
---> Running in 7f664b2f6a3c
Removing intermediate container 7f664b2f6a3c
---> d0d5eb8bf845
Successfully built d0d5eb8bf845
Successfully tagged registry.heroku.com/obscure-beyond-63219/web:latest
=== Pushing web (/home/ec2-user/Demos/rhdm7-kieserver-heroku/Dockerfile)
The push refers to repository [registry.heroku.com/obscure-beyond-63219/web]
5a2ef3642b91: Pushed
fd5703fc51cc: Pushed
203ea9c9ab69: Pushed
26e309bebfcf: Pushed
9a7a22f11b72: Pushed
latest: digest: sha256:14548e8e6ce48b092c8fba3d3fe7e77c38c452ae205b7b76de5456326f8374e1 size: 1366
Your image has been successfully pushed. You can now release it with the 'container:release' command.
> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry.heroku.com/obscure-beyond-63219/web latest d0d5eb8bf845 About a minute ago 858MB
registry.access.redhat.com/rhdm-7/rhdm73-kieserver-openshift latest ec749fcd647d 4 weeks ago 858MB
> heroku container:release web -a obscure-beyond-63219
Releasing images web to obscure-beyond-63219... done
> curl --user kieserver -X GET "https://obscure-beyond-63219.herokuapp.com/services/rest/server" -H "accept: application/json"
Enter host password for user 'kieserver':
{
"type" : "SUCCESS",
"msg" : "Kie Server info",
"result" : {
"kie-server-info" : {
"id" : "9b3ee6dc-38b8",
"version" : "7.18.0.Final-redhat-00002",
"name" : "9b3ee6dc-38b8",
"location" : "http://9b3ee6dc-38b8-4572-a59b-59d33d405d7d:8080/services/rest/server",
"capabilities" : [ "KieServer", "BRM", "BRP", "DMN", "Swagger" ],
"messages" : [ {
"severity" : "INFO",
"timestamp" : {
"java.util.Date" : 1555885405405
},
"content" : [ "Server KieServerInfo{serverId='9b3ee6dc-38b8', version='7.18.0.Final-redhat-00002', name='9b3ee6dc-38b8', location='http://9b3ee6dc-38b8-4572-a59b-59d33d405d7d:8080/services/rest/server', capabilities=[KieServer, BRM, BRP, DMN, Swagger]', messages=null', mode=DEVELOPMENT}started successfully at Sun Apr 21 22:23:25 UTC 2019" ]
} ],
"mode" : "DEVELOPMENT"
}
}
}
view raw gistfile1.txt hosted with ❤ by GitHub

No comments:

Post a Comment