Showing posts with label deployment. Show all posts
Showing posts with label deployment. Show all posts

Thursday, 30 October 2014

Vaadin & Spring Boot & WebSockets & OpenShift & Java8

Spring Boot is around for a while and because Vaadin caught my interest lately, plus Spring4Vaadin appeared, I gave it a spin. To make it more challenging, I decided to use Java 8 and deploy it on OpenShift. All the code is hosted on GitHub

Application is simple chat with OAuth2 sign in using Facebook/Google/GitHub/LinkedIn/Disqus. High-tech is way it broadcasts chat messages to chat participants using server push which in turn uses WebSocket mechanism.

Some informations about Spring Boot and OpenShift are part of the Spring Boot Documentation and some more in this blog post.

I've created DIY gear using OpenShift application console but same can be done using rhc app create vinbudin -t diy-0.1. Application code was already on GitHub and to get it running on OpenShift, following steps must be performed.

1. Add git upstream repository (openshift remote)

git clone git@github.com:anthavio/vinbudin.git
git remote add openshift ssh://your_uuid@vinbudin-yourdomain.rhcloud.com/~/git/vinbudin.git/

2. Add OpenShift build hooks

Build hooks in .openshift/action_hooks are shell scripts that are executed when you push something into OpenShift remote repository. Typically they stop application, run maven/ant/sbt to build application and start it again.

3. Push to the openshift

That's it. When you execute following command, you will see build hooks executed and project will be built and deployed on your openshift gear.

git push openshift master

You can still git push origin master to GitHub repository without invoking build on OpenShift

Maven 3.2.3 and Java 8 on OpenShift

OpenShift gears (28 Oct 2014) have only Java 1.7.0_71 and Maven 3.0.5. If you want to use different, most probably newer versions, just download and unpack them in .openshift/action_hooks/deploy into ${OPENSHIFT_DATA_DIR}

WebSockets on OpenShift

Situation seems to be same as two years ago when this blog post was written. You still have to access port 8000 to get WebSockets working.

Thanks to Vaadin/Atmosphere push implementation which automaticaly downgrade to long-polling when websockets mechanism is unavailable, user experience is not affected, but observing messages exchanged between browser and server, you will easily spot the problem.

Open Chrome Developer Tool Network tab and navigate to http://vinbudin-openshift.anthavio.net/ui

Request URL:ws://vinbudin-openshift.anthavio.net/ui/PUSH/?v-uiId=0&v-csrfToken=731062c6-712d-4320-a92c-3742fe3b4451&X-Atmosphere-tracking-id=0&X-Atmosphere-Framework=2.1.5.vaadin4-jquery&X-Atmosphere-Transport=websocket&X-Atmosphere-TrackMessageSize=true&X-Cache-Date=0&Content-Type=application/json;%20charset=UTF-8&X-atmo-protocol=true
Request Method:GET
Status Code:501 Not Implemented

WebSocket upgrade request was rejected. Ouch!

Now doing same, but with port 8000 in url - http://vinbudin-openshift.anthavio.net:8000/ui

Request URL:ws://vinbudin-openshift.anthavio.net:8000/ui/PUSH/?v-uiId=0&v-csrfToken=731062c6-712d-4320-a92c-3742fe3b4451&X-Atmosphere-tracking-id=0&X-Atmosphere-Framework=2.1.5.vaadin4-jquery&X-Atmosphere-Transport=websocket&X-Atmosphere-TrackMessageSize=true&X-Cache-Date=0&Content-Type=application/json;%20charset=UTF-8&X-atmo-protocol=true
Request Method:GET
Status Code:101 Switching Protocols

WebSocket upgrade request was accepted and protocol was switched. Hurray!

Happy Vaadin & Spring Boot & OpenShift websocketing!

Wednesday, 23 April 2014

Java cloud hosted continuous integration services

Last year I resigned to maintain my own VPS hosted CI server with Git Repos, Jenkins, Sonar, Maven repository, LDAP, etc... and moved source code repositories to GitHub. I'm uploading build artifacts into Sonatype OSSRH in case of libraries and with web applications deployments, I'm still experimenting with Openshift and some other services. But I also lost possibility do build and deploy project on demand. Fortunately many cloud hosted CI services popped up last year or two.

CircleCI

Predefined, not very extensive toolset for Java projects is avaliable. It has recognized my pom.xml automaticaly without any configuration. Uses circle.yml configuration file. It is does not have free plan (only trial), cheapest Solo plan is for $19/month.

Travis-CI

Java is quite well supported. It is cofigured using .travis.yml. There is free (unlimited) plan and also quite expensive paid plans

Codeship

Neat interface, but you are allowed to use only few preinstalled java tools. Free plan is limited to 50 builds per month, while Basic plan will cost you $49 per month.

drone.io

Simplistic with basic java support. Free unlimited plan.

Cloudbees DEV@Cloud

Jenkins in the cloud with all it's awesomeness. You can choose pretty much any Java, Maven or Gradle version you can imagine plus zillions of Jenkins plugins. Pricing is trickier here because billing is build time based and offering includes application hosting (you might not be interested in). Free plan includes 100 build minutes and there is also FOSS plan. Starter plan with 40 hours of build per month will cost you $60 + $17 = $77 per month

Another Cloudbees service is BuildHive where you will get unlimited number of builds, but you will use shared and slower Jenkins instance with very limited configuration and only for GitHub repositories.

Test drive with Phanbedder

I have recently built little library named Phanbedder and blogged about it few days ago. While very tiny in java code size, it is pretty unusual because it launches separate processes of bundeled PhantomJS native binary during the tests. This makes it perfect candidate for testing cloud CI services.

Good news is that every above mentioned service managed to compile and test it using mvn clean test -Denforcer.skip=true command. I use maven-enforcer-plugin to enforce Java 6 to be used for compilation. But because many of CIs offers only Java 7, I had to switch enforcer off...

Trickier part is execution of mvn deploy. I'm uploading maven snapshot artifacts into Sonatype OSSRH and also release versions later into Maven central. For snapshot deployment into Sonatype OSS Nexus, username and password must be provided to make maven-deploy-plugin work, otherwise...

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-deploy-plugin:2.8.1:deploy (default-deploy) on project phanbedder-1.9.7: Failed to deploy artifacts: Could not transfer artifact net.anthavio:phanbedder-1.9.7:jar:1.0.1-20140422.184656-7 from/to sonatype-oss-snapshots (https://oss.sonatype.org/content/repositories/snapshots): Failed to transfer file: https://oss.sonatype.org/content/repositories/snapshots/net/anthavio/phanbedder-1.9.7/1.0.1-SNAPSHOT/phanbedder-1.9.7-1.0.1-20140422.184656-7.jar. Return code is: 401, ReasonPhrase: Unauthorized. -> [Help 1]

Normaly, deployment credentials are stored inside your personal maven settings.xml, but obviously this file is not present on cloud CI server. Workarounds exists for Travis-ci. Cloudbees DEV@Cloud has most elegant solution, but I guess no deployment with undisclosed credentials can be done from BuildHive and others.

Now, here goes links to public success build logs for Travis-CI, drone.io, BuildHive and DEV@Cloud. Sadly CircleCI and Codeship does not seem to support public projects.

Mentioned CI services can be webhook triggered, provide integrated browser testing and deployment into popular cloud hosting services like Heroku or Google App Engine. They evolve pretty quickly as they add more integrations as I write... Listing and comparing features here is not worth the effort so check documentation pages.

Everybody has different needs. All my projects are open source hobby projects so I guess I'll go with webhook triggered snapshot builds on BuildHive or I might use Travis-CI to have it with snapshot deployments.

For Maven central release deployment builds, I see only one option - Cloudbees DEV@Cloud. In some next blog post, I'll describe how fully automatic deployment can be achieved using Cloudbees DEV@Cloud, maven-release-plugin and Sonatype OSSRH.

Happy cloud hosted CI builds!

Thursday, 10 April 2014

RPM upgrade and embedded Jetty

Java web application I'm working on recently (let's name it lobster) is embedding and packaging Jetty inside itself. This makes application artifact more self-contained and independent, because it does not require preinstalled and preconfigured server.

To simplify application deployment even more, it is packaged as RPM file, which is uploaded into Nexus serving as Yum repository.

Deployment then is simple matter of executing sudo yum install lobster and thanks to RPM scriptlets, server is automaticaly restarted as a part or installation.

Everything went nice and smoothly, until second release. When yum update happend, we have found how amazingly wierd thing RPM upgrade is.

sudo yum update lobster execution completed, but application failed to start and logfile contained strange exceptions
Caused by: java.io.FileNotFoundException: /opt/lobster/lib/lobster-core-0.4.0.jar (No such file or directory)
 at java.util.zip.ZipFile.open(Native Method) ~[na:1.7.0_40]
 at java.util.zip.ZipFile.(ZipFile.java:215) ~[na:1.7.0_40]
 at java.util.zip.ZipFile.(ZipFile.java:145) ~[na:1.7.0_40]
 at java.util.jar.JarFile.(JarFile.java:153) ~[na:1.7.0_40]
 at java.util.jar.JarFile.(JarFile.java:90) ~[na:1.7.0_40]
 at sun.net.www.protocol.jar.URLJarFile.(URLJarFile.java:93) ~[na:1.7.0_40]
 at sun.net.www.protocol.jar.URLJarFile.getJarFile(URLJarFile.java:69) ~[na:1.7.0_40]
 at sun.net.www.protocol.jar.JarFileFactory.get(JarFileFactory.java:99) ~[na:1.7.0_40]
 at sun.net.www.protocol.jar.JarURLConnection.connect(JarURLConnection.java:122) ~[na:1.7.0_40]
 at sun.net.www.protocol.jar.JarURLConnection.getJarFile(JarURLConnection.java:89) ~[na:1.7.0_40]

What was wierd even more, that it was lobster version 0.5.0 installation and 0.4.0 stated in stacktrace, actualy was previous version!

To make story short, after some googling I've found RPM upgrade sequence.

  1. execute new version %pre [ $1 >= 2 ]
  2. unpack new version files (both old and new are now mixed together)
  3. execute new version %post [ $1 >= 2 ]
  4. execute old version %preun [ $1 == 1 ]
  5. remove old files (only new and unchanged stays)
  6. execute old verion %postun [ $1 == 1 ]

Important is, that between step 2 and 5, mixture of old and new version jar files is present in installation directory! Attempt to start server java process in %post or %preun scriptlet can only result in disaster same as we experienced. Old version jars will be deleted right after scriptlet execution.

Here comes working install/upgrade/uninstall solution

%pre scriptlet

#!/bin/sh
# rpm %pre scriptlet
#
# parameter $1 means
# $1 == 1 ~ initial installation
# $1 >= 2 ~ version upgrade
# never executed for uninstall

echo "rpm: pre-install $1"

# failsafe commands - can't break anything

# make sure that user exist
id -u lobster &>/dev/null || useradd lobster

# make sure that application is not runnig
if [ -f /etc/init.d/lobster ]; then
 /sbin/service lobster stop
fi

%post scriptlet

Important is NOT to start application on rpm upgrade
#!/bin/sh
# rpm %post scriptlet
#
# parameter $1 means
# $1 == 1 ~ initial installation
# $1 >= 2 ~ version upgrade
# never executed for uninstall

echo "rpm: post-install $1"

# initial install
if [ "$1" -eq "1" ]; then
 /sbin/chkconfig --add lobster
 /sbin/service lobster start
fi

%preun scriptlet

#!/bin/sh
# rpm %preun scriptlet
#
# parameter $1 means
# $1 == 0 ~ uninstall last
# $1 == 1 ~ version upgrade
# never executed for first install

echo "rpm: pre-uninstall $1"

# uninstall last
if [ "$1" -eq "0" ]; then
 /sbin/service lobster stop
 /sbin/chkconfig --del lobster
fi

%postun scriptlet

Here is right place to start application on rpm upgrade
#!/bin/sh
# rpm %postun scriptlet
#
# parameter $1 means
# $1 == 0 ~ uninstall last
# $1 == 1 ~ version upgrade
# never executed for first install

# console output is surpressed for postun% !
echo "rpm: post-uninstall $1"

# upgrade
if [ "$1" -ge "1" ]; then
 /sbin/service lobster start
fi

Useful RPM scriptlet documentation is in Fedora Wiki also how to integrate with SysV Init Scripts

Happy RPM deployments!