domingo, 11 de agosto de 2013

Running Websockets on OpenShift




WebSocket is a pretty new and important technology in which it is possible to send message frames from server to clients without opening multiple HTTP connections. Although it is has been proven to be a solid and consolidated specification, running websockets in the existing cloud platforms is still a pain in the ass. The main cloud players do not provide enough support for WebSocket protocol due to the lack of application servers’ readiness and due to other issues related to the routing layer.

Knowing those difficulties, I’ve decide to post the steps to help eager people to use Red Hat OpenShift PaaS to run a websocket apps in the cloud. So, let's start from the beginning.


  • First of all, you must sign up in the OpenShift web site
  • Then you must add a new application
    • Pick Do-It-Yourself (DIY) cartridge
      • This will allow you to use a “pure Linux server” to do whatever you would like to do. In the specific case of this post, we are going to install an embedded web application in order to provide the required support for websockets.
    • Once DIY cartridge have been selected, you must fill out the application name and click on ‘Create Application’ button
    • Finally, do a ‘git clone’ according instructions

At this point, we have already prepared our Linux server on the cloud to install our application according our needs. Now, let’s make the required changes in the working copy we have just cloned from OpenShift master repository.

The changes are:
  • Update the shell script file which will be used by OpenShift to start our app
    • File: .openshift/action_hoooks/start 
    • Content: 

#!/bin/bash
# The logic to start up your application should be put in this
# script. The application will work only if it binds to
# $OPENSHIFT_DIY_IP:8080


echo "Starting WebSocketExample............. $OPENSHIFT_DIY_IP:$OPENSHIFT_DIY_PORT"
nohup java -jar $OPENSHIFT_REPO_DIR/diy/WebSocketExample.war > $OPENSHIFT_DIY_DIR/logs/server.log 2>&1 &
echo "Started WebSocketExample............. $OPENSHIFT_DIY_IP:$OPENSHIFT_DIY_PORT"
  • Update the shell script file which will be used by OpenShift to stop your app
    • File: .openshift/action_hoooks/stop 
    • Content:

#!/bin/bash
source $OPENSHIFT_CARTRIDGE_SDK_BASH


echo "Stopping WebSocketExample............."
if [ -z "$(ps -ef | grep WebSocketExample.war | grep -v grep)" ]
then
   client_result "WebSocketExample Application is already stopped"
else
echo "Killing WebSocketExample............."
   kill `ps -ef | grep WebSocketExample.war | grep -v grep | awk '{ print $2 }'` > /dev/null 2>&1
fi
echo "Stopped WebSocketExample............."
  • Add the embedded jetty application in the ‘Do It Yourself’ directory
    • Directory: diy
      • In this example, we have used the ‘WebSocketExample.war’ app name in order to match out our start/stop scripts.
      • Important note about the embedded jetty application file: 
        • There are some peculiaridades in the implementation of the class com.embedded.JettyStarter (shown below in red) which must be changed in order to bind the embedded app to the right IP and PORT number in the OpenShift platform. 
        • Content:

public class JettyStarter {
       public static void main(String[] args) throws Exception{
               ProtectionDomain domain = JettyStarter.class.getProtectionDomain();
               URL location = domain.getCodeSource().getLocation();
       
               // create a web app and configure it to the root context of the server
               WebAppContext webapp = new WebAppContext();
               webapp.setDescriptor("WEB-INF/web.xml");
               webapp.setConfigurations(new Configuration[]{ new AnnotationConfiguration()
        , new WebXmlConfiguration(), new WebInfConfiguration(), new MetaInfConfiguration()        
        //, new FragmentConfiguration(), new EnvConfiguration(), new PlusConfiguration()
                });
               webapp.setContextPath("/");
               webapp.setWar(location.toExternalForm());
       
               // starts the embedded server and bind it to openshift variables        
               String host = System.getenv("OPENSHIFT_DIY_IP");
               String port = System.getenv("OPENSHIFT_DIY_PORT");
               System.out.println(host + ":" + port);
               InetSocketAddress sa = new InetSocketAddress(getByName(host), valueOf(port));
               Server server = new Server(sa);


               server.setHandler(webapp);        
               server.start();
               server.join();
       }
}

After script files have been configured and the embedded application has been put in the ‘diy’ directory, you must commit and push changes back to the master repository.
  • The commands are:
    • git commit -m 'My changes'
    • git push
  • As soon as the push finishes, the stop/start scripts will run
    • If you notice it didn’t run accordingly, remote access your openshift server and check if everything is ok. Remember: it is Red Hat Linux, so you should be ok checking your stuff.
    • Try to check if start/stop scripts have execution permission (not sure why, but I have this issue in some experiments).
      • ls -lt $OPENSHIFT_REPO_DIR/.openshift/action_hooks/
    Finally, are done. \o/
      Access 'ws://[YOUR APP].rhcloud.com:8000/example' using your favorite WebSocket tool and check it by yourself.
        Don't have a WebSocket tool?  Take a look on ‘Advanced REST client’ for Chrome

        The openshift configuration used in this example can be found here.
          Thanks for reading