The key to a good development environment almost always comes down to how long it takes for changes you make to take effect. With any compiled language, there is often a lot of setup work involved to optimize deployment speed. Thankfully, one of the promises of containers is it allows for patterns to be standardized and repackaged as reusable images that do a lot of the heavy lifting for you.
In the case of OpenShift, we offer JBoss images for EAP and JWS which have the deployment scanner and exploded war class reloading configurable by simply setting an environment variable. The other critical component necessary to make iterative development possible is
oc rsync. OpenShift's support for rsync means that any framework (not exclusive to java) that supports dynamic reload can be utilized with container development. This is applicable to local scenarios using
oc cluster up or the CDK as well with remote development with OpenShift Online, Dedicated, or Container Platform.
Syncing War Files
Let's start with a simple example:
git clone https://github.com/danmcp/openshift-jee-sample.git
sudo oc cluster up --version=latest # Any OpenShift environment will work
oc login # as developer:developer
oc new-app registry.access.redhat.com/jboss-eap-7/eap70-openshift~https://github.com/danmcp/openshift-jee-sample.git
oc expose service/openshift-jee-sample
# Browse to the web console and log in as developer:developer
# Select My Project and click on the url for openshift-jee-sample in the upper right
# You should see the index.html page
# Now add /HelloWorld to the end of the url and you should see the output
# of the HelloWorld Servlet
mvn package -P openshift # Or build ROOT.war however you wish
oc get pods # To get the name of the running pod you will sync to
oc rsync --include="ROOT.war" --exclude="*" target/ <pod_name>:/deployments/ --no-perms=true --watch # Replace <pod_name> with the value from the previous step
oc rsync left running, every change to ROOT.war will automatically be synced and reloaded within a few seconds.
Syncing Class Files
For various reasons such as a large war file, slow network connection, or slow build times, you might prefer to only push class files. Such a workflow can be accommodated as well. Here is an example (picking up where the previous example left off):
oc set env dc/openshift-jee-sample AUTO_DEPLOY_EXPLODED=true
oc get pods # To get the name of the new running pod you will sync to. You might have to wait a few seconds for the new pod to be deployed.
mvn compile war:exploded -P development # Or build your class files however you wish
oc rsync target/SampleApp.war/ <pod_name>:/deployments/SampleApp.war --watch # Replace <pod_name> with the value from the previous step
# Go to /SampleApp/HelloWorld in your browser to see the sample app
As with the war example, each change you make to a class file will cause the app to reload within a few seconds.
[video width="1920" height="1080" webm="https://blog.openshift.com/wp-content/uploads/rsync_classes.webm"][/video]
I have to give a warning associated with individual class reloading that there is a chance of picking up partial changes. So you should never use exploded war class reloading in a non-development scenario. An easy workaround to the partial class reload problem is to touch and sync a <your_war>.war.dodeploy file (as a sibling file to <your_war>.war folder) and
cp that file to force a reload. In that case you do not set the AUTO_DEPLOY_EXPLODED=true environment variable.
No doubt there are even better ways to setup your environment to take advantage of these features. Hopefully I've explained enough to show what's possible and you'll be able find the best configuration for your application.
The ultimate benefit of using this mechanism is that it lets you use a standardized environment from development to production. And being able to easily deploy, scale, and iteratively develop an application with the speed of local development and the complexity of your production environment is near priceless.