Over the years I’ve found that build and deployment is one the most important, yet often overlooked aspects of software development. While NAnt\MSBuild has given the .Net platform automated builds, it’s XML based. People then took this approach and applied it to deploying ASP.net applications.
I find this really interesting. If you speak to any developer about XML configuration they will run to the hills – yet it’s OK for build\deployment? Without a reliable and flexible way to deploy, the entire development line is blocked and the team will struggle to push new features out.
A while ago, I gave some support to Derick Bailey with albacore to help solve the “build” problem. I then wanted to look at the deployment problem. Having perviously manage near 200 line XML deployment files I could relate directly to the problem. I’ve found it near impossible to change settings or configure new servers when the script is that long and complex. There must be a better way.
After playing around with some different approaches I’ve created a prototype called Dolphin Deploy (based on the Albacore name) available on github at http://www.github.com/benhall/DolphinDeploy. A simple, yet complete, example of how to deploy an MVC application is at http://github.com/BenHall/DolphinDeployExample.
Dolphin Deploy
Dolphin Deploy is a DSL for defining your deployment scripts.
The aim is to allow you to configure multiple different environments with different servers to deployment ASP.net applications. By supporting different servers in each environment, you can easily configure additional load balanced servers and have flexibility in terms of the file system structure which was one of the key issues we faced with XML.
For example, below is a very simple script which will deploy an ASP.net MVC application, zipped in a file called MvcExample1.zip in the directory example.
environment do
desc “Example MVC Deployment”
configured_as :mvc
env :live do
name “MvcExample1″
host “MvcExample1.com”
deploy File.join(Dir.pwd, “/example/MvcExample1.zip”)
to “webserver0001″, “C:/inetpub/wwwroot/MvcExample1/”, “127.0.0.1”
end
end
This will deploy the website into C:\inetpub\wwwroot\MvcExample1\, automatically tagging it with a release number to support rollback scenarios. The final directory would be C:\inetpub\wwwroot\MvcExample1\MvcExample1-01, incrementing the tag for each deployment. If you need to rollback, you simply point IIS back to the previous directory – at some point this will be automated. Within IIS, the site will be called MvcExample1 and have the host header MvcExample1.com.
In terms of support, Dolphin Deploy works with both IIS6 and IIS7. The script will detect the version of the server being deployed to and use the implementation appropriate. At the heart of this implementation is IronRuby.
IronRuby
The reason for using IronRuby is very simple. It wouldn’t have been possible to have the dynamic nature of Ruby, combined with interacting with IIS without it. IronRuby allows Dolphin to interact with IIS via existing C# libraries such as DirectoryServices and Microsoft.Web.Administration. By not re-inventing the wheel I was able to iterate more quickly on the important aspects, such as the DSL. While it still needs work, I think it has potential.
The DSL is executed at runtime by IronRuby. This allows Ruby methods, such as File.join and Dir.pwd, to be used directly in the configuration file allowing for more flexibility that allows for more complex examples as shown below.
Below specifies two environments, local which has a single server while test with two servers which need deploying to.
Both have a list of subdomains which need to be configured, instead of duplicating the list we can have it as a variable. Within the after block, we can loop around each of the items and call the method extra_header to assign the additional host header on a particular port (9999).
In a similar way, we can call the method virtual_directory to create a virtual directory, or shell out to the cmd and write to Deployment.txt file.
headers = [‘subdomain1′, ‘subdomain2′, ‘subdomain3′]
environment do
desc “Example MVC Deployment”
configured_as :mvc
env :local do
name “MvcExample1″
host “MvcExample1.local”
deploy File.join(Dir.pwd, “/example/MvcExample1.zip”)
to “localhost”, “C:/inetpub/wwwroot/MvcExample1/”, “127.0.0.1”
after do
headers.each {|entry| extra_header(“9999:#{entry}.local.header”)}
virtual_directory “Test”, “Content”
end
end
env :test do
name “MvcExample1″
host “MvcExample1.test”
deploy File.join(Dir.pwd, “/example/MvcExample1.zip”)
to “testserver0001″, “C:/inetpub/wwwroot/MvcExample1/”, “127.0.0.1”
to “testserver0002″, “D:/apps/MvcExample1/”, “127.0.0.1”
after do
headers.each {|entry| extra_header(“9999:#{entry}.test.header”)}
virtual_directory “Test”, “Content”
cmd “echo Hello World ” + Time.now.to_s + ” >> C:/temp/deployment.txt”
end
end
end
To execute and use the framework, you simple need to download the gem and reference a rake task.
The gem is available from http://rubygems.org/gems/dolphindeploy. Within your rake file, require ‘dolphindeploy’ and require ‘dolphindeploy_rake’, this will then give you the additional tasks.
The syntax, executed via IronRuby, is:
ir -S rake dolphin:deploy[env,server]
For example to deploy to the test environment for server testserver0001, you would need to execute:
ir -S rake dolphin:deploy[test,testserver0001]
The only thing it expects is that the deploy.conf containing the DSL script above will be in the same directory as your rakefile.
The project includes other functionality, such as dynamically adding sections to the DSL to perform custom tasks, or deleting old builds. Until I document this functionality via blog posts, the best place to look would be the specs.
A minor comment, at the moment the script needs to be executed on the server itself (SSH \ Powershell for example). You also need to be administrator (and have evaluted permissions on Windows 7). After all, this is a prototype, so please don’t use it on production until it’s had a little bit more testing
If you would like to help, please, please do! Grab me on Twitter while the code is available at http://github.com/BenHall/DolphinDeploy