Tuesday, October 5, 2010

How to build a one click deployment job with Hudson

While there are many solutions available for automated deployment, none of them seemed quite right for our needs. After one failed attempt at a homegrown solution our team went back to the drawing board and specified our requirements:

The ideal solution had to be:

  • Easy to Use - with an audience ranging from developers to business analysts the solution needed to be intuitive and easy to explain.
  • Modular - Things change if we changed app server or SCM we wanted only minimal changes to the tool. This also useful for testing parts of the process in isolation.
  • Not tied to the build tool or process of the deployable. Once I've built the artifact, I don't want anything to do with its build config - that's right I don't want to look at its pom or build.xml. When working with multiple teams with differing build approaches, this is a must.
  • One stop shop - We want the ability to deploy any of our artifacts from one place.
  • No Magic - The worst thing that can happen with an automated approach is that when it fails no-one knows why. We wanted know what was happening during all steps of the process.
  • Auditable - We needed to know who deployed what, to where and when
  • Secure - Can I restrict who deploys what to where?
  • Simple - We're lazy and code costs - the solution should contain as little custom code as possible.
  • Repeatable - The tool should deploy any artifact to anywhere but some deployments are used over and over again e.g. latest snapshot to the systest environment. Repeating these builds should be simple.

As with most things there is no silver bullet but the approach below worked very well for us.

Step 1. Build a simple solution you can call from the command line

Build the a bare minimum solution that works from the command line. Don't think about GUI's, security or anything else. Do think about what the minimum set of inputs are. e.g. enough to identify the deployable and the target server, no more and no less. For us this consisted of three very simple Groovy scripts:

  • The first simply took the artifact id and version, constructed the correct url to our Maven Repository and downloaded the correct deployable. 
  • The second script pushed the deployable to the remote server. 
  • The third took the deployable and ran the actual deployment to the app server. 
Each step was extremely simple, logged exactly what it was doing and could be tested in isolation. We then wrapped the three scripts in one master script that called each in turn. Through this approach we now had the means to deploy any artifacts in our maven repository to any of our servers. By using a command line compatible approach you leave your options wide open for calling the job from almost anywhere. Tools to help with this step come included with most Application servers or see Cargo for a catch all solution.

Step 2. Add the command line solution as a parameterised job in Hudson

Hudson already provides great security and auditing abilities and it seemed like a natural fit. We used a parametrised build to pass the necessary parameters to the scripts: http://wiki.hudson-ci.org/display/HUDSON/Parameterized+Build

We used drop-down fields for target servers and group id's leaving the artifact id and version as free text fields. Turning on Hudson security ensures an audit trail and if necessary the job can be locked down to certain users only. Hudson also gives you a simple gui that anyone can use.

Step 3. Enhance the Hudson Job with a Groovy Post Build step.

Secret sauce... While you now have a fully working solution there are some things that can be improved. I had promised one click deployments and also the Hudson gui lacks in some areas -To improve this use the Hudson Groovy Post build plugin: http://wiki.hudson-ci.org/display/HUDSON/Groovy+Postbuild+Plugin

Configure a post build step to add a badge to each build detailing what was deployed, by whom and to where. Then you using the passed in parameters you can construct a hudson url that will repeat the same deployment job again. e.g. http://myhudson-server/job/myDeploymentJob/buildWithParameters?Artifact=website2&Version=1.5-SNAPSHOT&TargetServer=SystemTestBox4 Add this url to the build badge too. By creating bookmarks with this url you now have truly "one click" deployments. These url's can also be easily sent non-technical users - e.g. by providing to the test team they can pull down the latest build for testing whenever is convenient.

Conclusion:

After a lot of thought, I feel we have come up with a solution that ticks all the boxes. It works well for us and after over 1000 deployments to both test and production systems I'm happy to say it's a huge success. Good luck with your approach and let me know how it goes in the comments.