Project Kudu: Git deployment for all!

July 6, 2012 - 9 minute read -

What is Project Kudu? Quite simply, it’s the new Continuous Delivery and Deployment hotness in the .NET world. I’m frankly amazed more people haven’t yet jumped on this, because this has the potential to revolutionise how people do deployments internally and externally. Project Kudu is the framework underlying the Git deployment feature of the new Azure Websites, but you can use it separately from Azure, and, best of all, it’s open-sourced under the Apache 2.0 licence!

My previous post focussed on deploying to Azure with Git. What I didn’t mention there was that this was making direct use of Project Kudu under the covers, and that you can get the same features in your own environments! This post will describe how to get Kudu running locally and some ideas on integrating it into your CI process for continous deployment.

Project Kudu is primarily developed by two Microsofties, David Ebbo and David Fowler, with solid open-source credentials in the .NET world: David Ebbo is also part of the core NuGet team, and David Fowler put together another awesome bit of tech, SignalR. The platform they’ve built for Kudu is pretty solid, smartly leveraging IIS management functionality provided through the Microsoft.Web.Administration package.

Unfortunately, it’s a little rough around the edges. Clearly it has been built with Azure in mind, and there are a lot of customisations that have been built on top of Kudu to build Azure, not least much of the Azure UI: Kudu’s own UI is best described as “minimal”. Interesting to see it’s been built with Twitter Bootstrap, though. However, the biggest issue with Kudu currently is the lack of documentation on getting it up and running: the wiki is almost entirely Azure-oriented, and the Getting Started page can be summarised as “get the source code, open it in Visual Studio running as an Administrator, and hit F5”. I will contribute the relevant bits of this blog post back to the project’s wiki, once I’ve worked out how to do so!

Setting up a Kudu environment

So, the initial stages are as simple as the wiki describes. You do have to be careful to run Visual Studio as an Administrator, however, as all the clever stuff it does in talking to IIS requires administrative privileges. Running Kudu through Visual Studio will give you something to play with, but it won’t work for production deployments, obviously. This is where things start getting a little bit trickier.

There is a Kudu.Setup.sln in the Git repository, which purports to contain a WiX project for building an MSI for Kudu. Unfortunately, it seems unfinished: I built the MSI, ran it and nothing happened at all as far as I could see. No UI popped up or anything. I quickly decided to go for a manual deployment instead.

Looking at the output generated by the command-line build (run the build.cmd file included in the repository), I noticed that there were two components generated. The first was the Kudu front-end, an ASP.NET MVC web app; the second was Kudu’s back-end service, which implements Git’s Smart (HTTP) Protocol and handles the back-end git operations and site deployment. Remember in my last post how I said that Azure builds an MSDeploy package and deploys it to your site, so you can take advantage of the configuration file transforms and other MSDeploy goodness? That’s all handled by Kudu!

I set up a virtual machine to deploy Kudu onto; thankfully, it doesn’t require much: IIS 7.0 or greater, ASP.NET 4.0, and Git installed in C:\Program Files (x86)\Git\bin, so it was really easy to get the VM configured. The first two of these can be installed and configured by the Web Platform Installer, which makes it simpler still!

First, I created an AppPool for Kudu’s website to run in. I did this because Kudu has to run as an administrator, and I didn’t want to go changing the default AppPools.

Right-click the Application Pools node in the tree and choose Add Application Pool Give the new Application Pool a name, and set it to run under ASP.NET 4.0 in Integrated mode

Now set the AppPool user identity to an administrative user. I just set the AppPool user identity to be that of the local Administrator user on the machine, but this is a BAD THING™ so please create a user in the administrators group specifically for the Kudu AppPool!

Select the new Application Pool in the list, and click Advanced Settings Change the AppPool Identity to an administrative user

Next, I copied the two build artifacts to directories under inetpub and created a Web Application in the Default Web Site pointing to the location I had copied the front-end to:

Right-click the Default Web Site node in the tree and choose Add Application Fill out the application alias (name), select the AppPool that we created earlier, and set the physical path to the appropriate location for your Kudu binaries.

I now had a website I could hit. Unfortunately, there’s a mismatch between the Kudu config file, and the artifacts churned out by the build: Kudu’s web.config file contains a directive for locating the Kudu back-end service, which defaults to ..\Kudu.Services.Web, whilst the artifact is output to ..\KuduService. You can update the config file or rename the directory as suits your own tastes. Whilst there, I also noticed that the web.config defines a path to store all the sites deployed; I decided to create this directory as well, just in case.

Screenshot showing the AppSettings for setting the Service site location and the location for deploying sites locally.

UPDATE: David Fowler pinged me on Twitter to say that Windows Authentication shouldn’t be required. After a bit of investigation, I found that he is of course correct. I think the error was caused by an unrelated configuration setting: it took me a while to get IIS set up properly on my local machine whilst writing this post. As such, you can skip these steps describing how to enable Windows Authentication.

When I went to the URL, the first thing I got was an error. By default, Kudu expects to use Windows Authentication, which I hadn't configured. I decided to enable it at the server level so that other websites could take advantage of it; this turned out to be a prudent choice when I later noticed that Kudu creates a new site in IIS for each application it manages. I also had to disable Anonymous authentication for the Kudu application.

Click the node in the tree with the same name as your computer, then double-click Authentication Right-click Windows Authentication and choose Enable

We now have a working Kudu environment within which we can create applications for deployment. By clicking the Admin link in the top right corner, we can verify that it has picked up the back-end service site correctly:

Kudu's "Settings" page lists the physical locations of the Service site and the applications directory

Provided you see that nice green “ok” label, you’re good to go and create your first application! Go ahead and click “Create Application”. This is where the fun starts!

Simply fill out the name of the application and click "Create application"!

After you create the application, you’ll be given a Git URL to which you can push your repository. You’ll notice that the generated URLs all point to localhost.

Kudu Application Settings: your generated URLs for Git deployment and viewing the deployed application, and a big red button to delete the application

You can fix this on a per-application basis by going into the IIS Manager and altering the bindings for the created sites, but there doesn’t seem to be a way at the moment to correct this for all sites; even setting the binding on Kudu site itself doesn’t have the hoped-for effect.

Select the site in the tree and click Bindings in the Action pane Select the default bindings in the list and click Edit Set the Host name to the fully-qualified domain name of the machine

As yet we have no deployments to the application, so the list of deployments is empty. However, with a git remote add staging [generated Git URL] followed by a git push staging master, we can now easily deploy our application to our staging site. (You can of course call your git remote something different from “staging” to suit your situation.) With the first push done, we now have a deployment listed:

Our first deployment: a green "Success" stamp, and a tick

I was a little disappointed to find that the list of deployments doesn’t automatically refresh the way it does in the Azure portal. It’s another one of those customisations built on top of Kudu that I mentioned earlier. I suspect with a bit of SignalR or something it wouldn’t be too hard to put together a pull request adding this feature…

Kudu and TeamCity

So, we’ve brought the fun; now let’s bring the awesome. You can easily wire this into TeamCity.

Before I get onto how I set up Continuous Delivery using Kudu for a project at work, I should note that we’re using the Git-Flow branching model on this repository; this is where the develop and master branches mentioned below come from. Git-Flow is outside the scope of this blog post, so hit the link to read more.

Here’s the TeamCity configuration I used to create our build pipeline from source code to deployment:

  1. Create a build configuration to build your application and run the unit and integration tests. Configure this as suits your application.

  2. Create a build configuration to deploy your application to your Kudu environment and run your acceptance tests: 1. Create a build step for the deployment. I used a PowerShell build step, but this could also be a command-line build step or similar. The PowerShell script I used was git push [generated Git URL] develop:master. Tough, innit? We push the local develop branch to master on Kudu here, because develop has the most up-to-date changes in this branching model, but Kudu only supports deploying the master branch. 2. Create a build step for running your acceptance tests. Configure this as suits your application and tests. 3. Trigger this build using a Finish Build trigger on your build + test configuration. Be sure to only run this build on successful builds from the build + test configuration.
  3. Create a build configuration to update your master branch. Again, I used the PowerShell runner. This script is a bit more involved, but still quite trivial:

    git fetch origin

    # check out the master branch, creating it off origin/master if it doesn’t # already exist git checkout -B master origin/master

    # fast-forward merge develop into master. Under git-flow, this should always # be a fast-forward git merge –ff develop

    git push [writeable URL for repository] master

Again, be sure to trigger this build using a Finish Build trigger on the deploy and acceptance test build, selecting successful builds only.

The `try..finally { exit }` wrapping the script is required to ensure that the build completes; without it, PowerShell doesn't properly report an exit code, TeamCity has no way of knowing its finished, and so the build hangs. Useful…

This turned out to be due to the fact that msysgit installs both a .cmd and .exe on Windows, and the .cmd version is called by default to delegate to git.exe. It was the @ sign in my git URL that was causing the build to hang, as cmd interprets this as a special character. Don’t use try..finally { exit }, as this will result in green builds even when the build fails!

I was annoyed that I had to split out the last step to update the master branch into a separate build configuration, but there is no way in TeamCity 7.0 and earlier to skip remaining build steps within a configuration after that configuration fails. Thankfully, JetBrains are resolving this in v7.1, due for release in a few weeks.

It’s worth noting that you could easily extend this to support Continuous Deployment (to production) if needed.

I’ve really enjoyed playing around with Kudu, and it is going to quickly become one of my go-to tools for continuous integration and delivery. What do you make of it?