Here at Wanari, we use Play Framework for many of our projects and maintain products on our own servers. Not too long ago, a client of ours requested to move such product to Azure Cloud. After a bit of research we found 3 options:

  1. We create a Virtual Machine on which we arrange the environment we use on our own servers. The advantage of this is that automatic installation would barely change at all. A big drawback though is that we would need to maintain one more machine.
  2. Another option is that we install the product as an App Service. The advantage is losing the maintenance of the machine, plus installation is easy: WAR file to be copied. Its drawback is that only with an external tool can we compile Play! into a WAR file. Moreover, if we were to start with different configurations we would have to compile it over and over again. If you are interested, here is a writing on this.
  3. The third solution – the one we chose – is somewhere between the two extremes above. Cloud Service gives us a machine with private access, where maintenance is not our task, though we can run our own applications. Its only drawback is that installation is a bit uneasy. There is a plugin (Azure Toolkit for Eclipse) with which you can easily install it through Eclipse (here’s a tutorial if you’re interested). But once it comes to automation, it doesn’t get through. However the plugin contains the necessary Ant tasks, but unfortunately we cannot run them even when allowed a long time.

This is how we’ve come to write this very own powershell script for installation. This post is about how we’ve solved the problem of installing a Play! 2.x application onto Azure Cloud Sevice via Jenkins.

text

What are we going to do?

There are three main tasks we need to take care of:

The starting point

We have the source of a Play! project in a git repository – this is what we want to put to Azure

We have a Jenkins server with the following:

We have a Windows machine that acts as a Jenkins slave and has:

We also have an Azure account

Preparations

In Azure, we’ll need:

The Cloud service is where our app will run and we need the Storage (account) for the deploy process (the service will be copying the needed files from here).

Compiling a Play! application

This Jenkins job will do the following:

Creating the Jenkins job:

Jenkins > New Item> Freestyle project

General > Execute concurrent builds if necessary

Secure Code Management > Git

Build > Add build step > Build using sbt

Build > Add build step > Execute shell

unzip -p target/universal/exampleproject-1.0-SNAPSHOT.zip exampleproject-1.0-SNAPSHOT/bin/exampleproject.bat > run.bat
sed -i '51s/.*//' run.bat
sed -i '130s/.*/set "APP_CLASSPATH=%APP_LIB_DIR%\\..\\conf\\;%APP_LIB_DIR%\\\*"/' run.bat
mkdir -p exampleproject-1.0-SNAPSHOT/bin
mv run.bat exampleproject-1.0-SNAPSHOT/bin/exampleproject.bat
zip -r target/universal/exampleproject-1.0-SNAPSHOT.zip exampleproject-1.0-SNAPSHOT/bin/exampleproject.bat

Note: if you’re interested in why you need this correction, you can read about it in an older post of Martin Sawicki.

Creating a CloudServicePackage (CSPKG)

In order for you to run anything in Azure’s system, you need to pack it in a .cspkg file. Not only your program, but various other configuration files are also in the .cspkg file. In order to make this file, you need a few things. Not to have to spend too much time on this, I’ve made a powershell script that does most of the work for us. If you are interested in the details of what this is, read more here.

Creating the necessary files:

Download the script (AzureCSPKGFilesGenerator_20161026_wanari.zip) and generate the files for your own project:

./AzureCSPKGFilesGenerator.ps1 `
-out "exampleproject.zip" `
-storageName "exampleprojectstorage" `
-storageAccessKey "lZ*********zA==" `
-projectName "exampleproject" `
-projectVersion "1.0-SNAPSHOT" `
-vmsize "ExtraSmall" `
-workerRoleName "ExampleRole" `
-zulu "zulu8.15.0.1-jdk8.0.92-win_x64"

We need a publishsettings file in order to give our script access to Azure. If we go to this page, it can be downloaded automatically (for now, don’t bother with the text on the page). Unpack the generated ZIP somewhere and change the credentials.publishsettings file to the one we just downloaded. Then, upload the whole thing to a separate repository so that Jenkins will be able to use it.

Now to the Jenkins job that will do the following:

Creating the Jenkins job:

Jenkins > New Item> Freestyle project

General > Restrict where this project can be run

Secure Code Management > Git

Build > Add build step > Copy artifacts from another project

Build > Add build step > Windows PowerShell

& "c:\Program Files\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\cspack.exe" ServiceDefinition.csdef /out:WindowsAzurePackage.cspkg

(The cspack.exe will be installed with the Azure SDK, find the exact route to this and set it here.)

Deploy to Azure from Jenkins

The deployment will be done by a script that I’ve written according to a post by Barni. Let’s download (AzureDeploy-v2_20161026_wanari.zip) our ZIP and copy it into the Jenkins slave from where we would like to do the deployment (this also has to be a machine with Windows & the Azure SDK installed).

The Jenkins job will the the following:

Creating the Jenkins job:

Jenkins > New Item> Freestyle project

General > Restrict where this project can be run

Build > Add build step > Copy artifacts from another project

Build > Add build step > Copy artifacts from another project

Build > Add build step > Copy artifacts from another project

Build > Add build step > Windows PowerShell

D:\Jenkins\scripts\AzureDeploy-v2.ps1 `
-publishSettings "$ENV:WORKSPACE\credentials.publishsettings" `
-subscription "Microsoft Partner Network" `
-storageName "exampleprojectstorage" `
-cloudServiceName "example" `
-cloudServiceConfig "$ENV:WORKSPACE\ServiceConfiguration.cscfg" `
-cloudServicePackage "$ENV:WORKSPACE\WindowsAzurePackage.cspkg" `
-deploymentLabel "Example deployment label build: $ENV:BUILD_NUMBER" `
-Production

Linking the Jenkins jobs

Deployment would be all done by starting these three Jenkins jobs one after another (given that we did everything correctly). But to truly deploy the new version with one click, we need to make these jobs notify each other when they are done.

Edit the first job, for me it’s called ‘ExampleProject-pack’:

Post-build Actions > Add post-build action > Build other projects

Then edit the second job (for me it’s ExampleProject-cspkg):

Post-build Actions > Add post-build action > Build other projects

Finally, to make it look real good, install the Build Pipeline Plugin to Jenkins and produce one:

Jenkins > New Item> Build Pipeline View

Select Initial Job: the name of the first job (for me it’s ExampleProject-pack)

The editing order doesn’t matter, but the logical structure does. Don’t mess up your jobs. – the ed.

After all this, clicking Run will start the entire process.

When the deployment script is done & has signaled “DEPLOY SUCCESSFUL” it doesn’t mean that it actually started in Azure. You can follow the Role’s condition on the portal, when it’s changed to “Running” then it’s done. Sometimes this takes 5 minutes, other times it takes 20 minutes, be patient.

Conclusions

This is what became the base of the process we nowadays use for our automatic installations. We further extended this in order to match various internal expectations (for example: included build numbers in the configuration files and now we create a separate configured compilation for the various systems (QA, UAT, PROD)), but this is another story it’s perhaps better explored in another blog post if you guys are interested…

If you have any ideas, recommendations or notes regarding this post or the scripts, don’t keep them to yourself!

member photo

Ksisu is a Scala backend dev at Wanari. His curious attitude and attention to detail are quite remarkable!

Latest post by Kristóf Horváth

Deploying a Play! app to Azure via Jenkins