Chapter 17. Deployment techniques – ASP.NET MVC 2 in Action

Chapter 17. Deployment techniques

This chapter covers

  • Leaning on continuous integration
  • Creating push-button deployments
  • Automating remote server deployments

On launch night, tensions are high because the smallest mistake could bring your website down. To eliminate the human mistakes that inevitably occur, we’d like to automate as much as possible. Ideally, we could simply push a button, and our website would be updated in moments.

Each deployment environment is slightly different, because connection strings, configuration settings, and server environments can vary. By introducing change management into our automated deployment process, we can ensure that we install the correct application with the correct environment settings.

In this chapter, you’ll learn how to simplify deployment through an XCOPY deployment strategy. You’ll also learn how to automate deployment with build automation tools and take advantage of configuration management to automate configuration changes to the various deployment environments. After utilizing these techniques on a local machine, the next logical step is to add remote deployment capabilities. We’ll look at using the Web Deploy tool to take an existing local deployment and give it remote server capabilities.

Regardless of the deployment environment, any good deployment strategy requires the use of continuous integration.

17.1. Employing continuous integration

Working in an environment without an automated integration process can be hectic and nerve-wracking. “It works on my machine” doesn’t suffice in a deployment scenario, so we need a set of practices to ensure that our code always works and is always ready to deploy.

To achieve continuous integration, Martin Fowler laid out a set of practices to adhere to:

  • Maintain a single source repository (use source control).
  • Automate the build.
  • Make your build self-testing.
  • Make sure everyone commits every day.
  • Every commit should build the mainline on an integration machine.
  • Keep the build fast.
  • Test in a clone of a production environment.
  • Make it easy for anyone to get the latest executable.
  • Ensure everyone can see what’s happening.
  • Automate deployment.

You can read Fowler’s explanation of each of these points in his “Continuous Integration” article (http://mng.bz/cHVo). We won’t cover all the continuous integration practices in this book—as entire books have been written on this topic.

In addition to adhering to these practices, the “check-in dance” ensures that no one inadvertently breaks the build. These are the check-in dance steps:

1.  

Run the local build.

2.  

Announce to the team you’re integrating (for large changes).

3.  

Pull down the latest version of the mainline. Merge any conflicts.

4.  

Run the local build.

5.  

If successful, commit the changes, providing a descriptive comment.

6.  

Wait for the server build to be successful.

7.  

If the build fails, drop everything and fix it.

Depending on the development environment, there are several continuous integration server tools and technologies you can employ. One popular continuous integration stack includes

  • Subversion (SVN) for source control
  • NAnt for build automation
  • NUnit for testing
  • CruiseControl.NET for the continuous integration server

Which tool we use doesn’t matter as much as the practices the tools enforce, although we’d like our tools to introduce as little friction as possible into the development environment. If we have to wait for a slow or unreliable source control server, our practices are less likely to be followed. Whichever build technology we decide to use, the result of each build should be a single deployment file, checked in to source control at the end of a successful server build.

To enable push-button XCOPY deployments, we’ll look next at some key NAnt features.

17.2. Enabling push-button XCOPY deployments

In an intranet environment, XCOPY deployments can be as simple as setting up a network share on the deployed machine. In other situations, the deployment file, whether it’s an installer or self-contained zip file, must be copied over manually or pulled down from source control. Regardless, if the files can be pushed from a network share, or pulled manually on the server, our deployment package will include the following:

  • The complete application
  • The build tool, if used (NAnt in our example)
  • A deployment script
  • A batch or PowerShell file to kick the off process

Our automated continuous integration build creates and checks in this deployment package. When we have a deployment package in source control, we can deploy any version of our application as needed. With a tool like CruiseControl.NET, it’s possible to automate the deployment of the latest version of the application as needed.

NAnt, along with its sister project NAntContrib, provides dozens of tasks out of the box that you can compile together to create a single deployment script. These tasks include the following:

  • Source control tasks
  • IIS tasks
  • File and directory tasks, for creating, deleting, and copying
  • Zip tasks
  • XML manipulation tasks

With a manual process in place, we can start automating one step at a time with NAnt tasks, until the entire deployment process is automated. Many teams already employ a build process in the form of a Microsoft Word document or wiki entry, detailing the manual steps. It’s only a matter of finding the corresponding NAnt task for each manual task, and the deployment is automated. If no NAnt task exists for a particular operation, NAnt provides the exec task, which can execute anything that can execute on the command line.

These are the key NAnt tasks for deployments:

  • unzip—Used to unzip the deployment package originally checked in to source control. If this is a manual pull of the deployment package, we can unzip the package manually.
  • copy—Used to copy the complete application to the correct deployed directory, performing an XCOPY deployment in one automated task.
  • exec—Used for a variety of scenarios, such as restarting IIS, stopping and starting services, and registering assemblies.
  • xmlpoke—Used to manage deployment configurations by manipulating key configuration files, such as the Web.config file.

In the next section, we’ll examine how to manage multiple deployment configurations with NAnt and xmlpoke.

17.3. Managing environment configurations

Development teams often deploy their applications in multiple environments. For any given project, there are at least two environments—production and development—and many teams integrate to one or more test environments before releasing to production. Among these different environments, the deployment must change. Some environments require merely a connection string change; others require debug flags, configuration values, email addresses, and more. In an automated deployment, the deployment script must take into account the various environment settings. Notably, it must know what environment it’s deploying to, and what changes it must make to the application to match that environment.

With NAnt, managing all these environment configurations is straightforward. Deployments are kicked off with a batch file, which merely starts NAnt. The deployment package zip file contains the following:

  • NAnt\
  • website\
  • database\
  • deployment.build
  • Dev.bat
  • CommonDeploy.bat

The NAnt folder contains the entire runtime distribution of NAnt. We include the distribution to avoid an environmental setup step on every server to which we deploy. The website folder contains the complete application that we XCOPY deploy to the correct folder on the server. The deployment.build is the NAnt build script that contains the complete deployment script. The Dev.bat file is a bootstrapper file that calls CommonDeploy.bat.

In listing 17.1, the bootstrapper file Dev.bat overrides the deploy directory and connection string properties by setting environment variables, and then calls the CommonDeploy.bat script. Fill in the TODO placeholders when you implement the script for yourself.

Listing 17.1. Setting the environment configuration in Dev.bat

In the Dev.bat file, we set up the environment variables for the environment configuration values (some of which still need to be filled in). With one CommonDeploy.bat batch file that runs off environment variables, we can create additional bootstrapper batch files for each target environment. The end of the Dev.bat batch script calls into the CommonDeploy.bat script (shown in listing 17.2) which provides a common bootstrapper file on top of NAnt.

Listing 17.2. Bootstrapper CommonDeploy.bat file overriding NAnt properties

The command in listing 17.2 is in a CommonDeploy.bat file, and it calls NAnt using environment variables set up by a previous environment-specific batch file (Dev.bat in our case). The -D command-line switches for NAnt allow us to override properties with the correct deployed values.

Because our deployment database will most likely require a different connection string than our local configuration, we need to use NAnt to override this value during deployment. A portion of the deployment.build file is in listing 17.3.

Listing 17.3. Deployment.build NAnt script with the deploy target

The first items to notice in this NAnt script are the XML attribute values in the format ${some.value.here}. These are NAnt properties, whose values were defined earlier through our bootstrapper file. When the CommonDeploy.bat file executes, the command-line switches set these property values with the appropriate environmental settings. Finally, the deploy target performs the actual deployment. A NAnt target is a named group of tasks, similar to a method in C#.

17.4. Enabling remote server deployments with Web Deploy

After getting a deployment script that can set up your application and database, the next step is to take on the challenge of pushing deployments to multiple servers. The key takeaway is that by automating the task of deployment, you can eliminate all the manual steps that are prone to errors.

To eliminate the need to log on to servers one by one, an additional technology is needed. This is where Web Deploy (formerly named MSDeploy) comes into play. You can download it from www.iis.net/expand/webdeploy. This tool provides a host of features and functions, but the features most important for our deployment approach are

  • The ability to sync files over HTTP
  • The ability to execute a remote command

These features support both enterprise and hosted environments, and the scripts can be used for both preproduction environments and production environments.

Typically, for web applications, there will be a development server that hosts the web application and database on the same machine. The quality assurance (QA) environment may be set up the same way. Then, in the staging and production environments, more servers come into play. There may be a separate database server, multiple web servers, and even an application server. Automating a deployment to multiple machines can become complex quickly. To reduce the complexity, Web Deploy can be used to sync files to multiple machines and execute the deployment script on each server. It can also run remotely so that deployments execute the same way that they would in the development environment.

Listing 17.4 shows the command-line arguments used to copy deployment files from a build server to a web server and then run the deployment.

Listing 17.4. Using Web Deploy to remotely execute a deployment

First, msdeploy.exe is called with the sync verb specifying a source directory on the local machine . This command copies all the files inside the deploymentFiles directory (C:\installs) to the remote server (in this case, the computer with the IP address 192.168.1.34).

Next, msdeploy.exe is called with the sync verb, but this time the runCommand argument is specified . This means that Web Deploy will execute the batch file at c:\installs\dev.bat on the remote server in the same way you’d run it if you logged in via remote desktop.

Using a technology like Web Deploy can greatly simplify a complex deployment. By running each command locally on each server in the deployment, scripts will run consistently from the development environment through the production environment. The real advantage is that the calls to msdeploy.exe can be scripted, which means that a multiserver deployment can be totally automated and repeatable. Scripting this type of deployment also means that from a single machine you can monitor a deployment and see the results of each script consolidated on your desktop.

17.5. Summary

When we configure our environment, we must devise a reliable deployment strategy to ensure that the right application is deployed with the correct configuration. At the heart of a solid deployment strategy is continuous integration, which includes practices such as automated deployments and self-testing builds.

With free, widely used open source tools such as CruiseControl.NET, NAnt, NUnit, and others, we can create an automated build and deployment server. By packaging NAnt, a build script, and a bootstrap batch file, we can harness the flexibility and power of NAnt to deploy and configure our application to multiple environments, up to and including production. Layering on the Web Deploy tool reduces the friction of copying and executing the build scripts across multiple servers, so we can have a totally automated solution that’s repeatable and reliable.