Home > Deployment > One deployment for all environments

One deployment for all environments

January 18th, 2010 Leave a comment Go to comments

Deploy the package

This set of instructions should be reasonably straightforward. Always have the same deployment technique throughout all environments. In this case, I am explaining a strategy that which uses MSBuild to trigger installations and upgrades. This simple tenet that can be hard to follow.

Often we also need manual intervention, or simply need to break up the process. To make a process manual we should wrap a commandline with a runner process (eg a bat or cmd file). This means that manual processes are still scripted rather than GUI-based. Moving from isolated scripts to automation is simply the process of chaining scripts together.

The basic checkout-and-compile for packaging and then download-and-deploy for installation sequence should be used across the local, build, test and production environments.

A basic deploy/install process

From commmandline:

msbuild /t:Install

This command will invoke the following lifecycle (this is found in build.tasks):

<Target Name="Install" DependsOnTargets="Package;Extract;Deploy"/>

We have already seen that packaging creates a zip file with <Target Name="Package" DependsOnTargets="Version;Clean;Publish;Zip"/>. The install then takes that package unzips it and then deploys. The idea here is that all it does it replicate what the user would do manually. The deploying is often quite straightforward but timeconsuming. In the sample, the main deployment is to an IIS. All of the third-party libraries have tasks for integration points and it worthwhile looking at them all. Personally, I am using extension pack at the moment.

So I am just said, the script works as though it is a person. Here’s where some complexity lies in the scripts. There are two part of the deployment scripts.

  1. the Deploy target is the worker for doing a deployment (that lives in the build.tasks)
  2. the deployment scripts that are bundles in the package and do the work (eg deploy.proj)

Deploy target as worker

Let’s have a look at the targets for the worker task. Before you look at it, let’s just remember that if I did this manually I would simply get copy of the package, unzip and then double click on the bat file that invokes msbuild. This is the download-and-deploy philosophy.

Here are two targets: Extract and Deploy. A quick explanation that I hope really isn’t needed. Extract first creates a directory to put the files in it doesn’t exist and then does the extraction via an extensionpack Zip task. Deploy goes and runs the deploy.bat file that invokes msbuild.

<Target Name="Extract">
   <MakeDir Directories="$(ExtractPath)" Condition = "!Exists('$(ExtractPath)')"/>
   <MSBuild.ExtensionPack.Compression.Zip TaskAction="Extract" ExtractPath="$(ExtractPath)" ZipFileName="$(ReleaseZipFile)"/>

 <Target Name="Deploy">
   <Exec Command="$(ExtractPath)\deploy.bat $(ExtractPath)" ContinueOnError="false" />

Deployment that actually installs

Now we’ll look at the deployment process once a package has been extracted more fully. Again, it doesn’t get any more complex in practice; there is just more of it. Let’s pickup from the worker process. It has just “clicked” on deploy.bat which effectively is the same as doing an msbuild command (for now let’s stay simple). It has now invoked deploy.proj which does the work. It now goes through the motions to install the site with the DeployWebsite target. If you’ve installed on IIS this process is familiar. If not, it’s damn fine documentation! You can see that you need to create Application Pools, Http Bindings and add Applications.

  <Target Name="DeployWebsite" DependsOnTargets="CopyWebSite">
    <Message Text="Deploying site version: $(Version) for environment $(Environment)"/>
    <CallTarget Targets="CreateAppPool"/>
    <CallTarget Targets="CreateWebsite"/>
    <CallTarget Targets="CreateBindingHttp"/>
    <CallTarget Targets="CreateBindingHttps" Condition="'$(Environment)'!='Test'"/>
    <CallTarget Targets="AddApplication"/>
    <CallTarget Targets="ModifyWebsite" Condition="'$(Environment)'!='Test'"/>
    <CallTarget Targets="SetupDirectoryBrowsing" Condition="'$(Environment)'=='Test'"/>
    <CallTarget Targets="StartWebsite"/>

While we have this deployment in mind, I’ll add a couple of notes on this deployment. It has two modes of deployment: test and non-test. The test deployment doesn’t run https and it does have a multi-site structure which we use directory browsing for moving between sites. This is a bigger topic of hot-swapping sites that I might get back to.

A quick summary is that it is each to deploy a package in your own environment by scripting tasks you might normally do with a point-and-click, or drag-until-you-drop, approach. This is an important start. Now you need do the same process on the build server (or build agent).

Build Server deploy: allowing it to push out a deployment

The build server should be no different. But it often is. It would ideally not be running as a interactive user and this can cause problems. In windows, there aren’t many good solutions. We don’t have ssh generally available that would make life easy. Running everything under Network Service or Local System is a poor solution that we often resort to.

Having read this entry you might asking yourself, how do we deal with the database? I’ll deal with that next because it cuts across the important issue of first-time installs and redeployments/upgrades.

Categories: Deployment Tags:
  1. No comments yet.
  1. No trackbacks yet.