This is an update that builds upon the previous posts about how We do Deployments.
The development environment is simple
The previous posts built upon our remote deployments. These examples were pretty trivial and not realistic, for the fact that in our development, testing, and staging environments we deploy an entire application to a single server. That includes a web application, database migrations, batch jobs, ect..
A production environment needs Roles
All production environments I have deployed to have at least two roles. Usually a Web Server and a Database Server. In many cases we would have a web farm which is a number of web servers with identical configurations that have a hardware device that sits in front of them (Load Balancer). This type of environment requires that your database migrations need to only run on the database server. It is possible to update the database from a webserver deploy but this means that you may need to pass through a sql connection string with sql authentication. I do not like that option because in production I prefer to have service accounts (windows accounts) act as the credentials to authenticate to the database server. By doing this it allows me to have a consistent deployment where security always works. But, using Windows authentication becomes troublesome if your production environment is all not part of a windows domain. I have found that more often than not, in hosting environments, the servers are usually built as standalone servers. This causes a problem with trying to deploy your database changes through your web server. MSDeploy does not propagate the clients windows credentials to other network connections when it runs.
My work around was to introduce a concept of deployment Roles. This helps clean up the deployment to make it simpler. A side benefit, is that the deployments to each role become more efficient. Lets explore the Roles:
I created to Roles:
- Web – This includes the webserver / web application code. Configuration files are updated to point to the production database instance at deployment time.
- Database – This includes running the database migrations and optionally supports additional data loads. The additional data loads are used to load code tables and other look up data that is not configurable in the application.
So how does this change the previous examples?
First I have a call to my deploy script for each Role, here is an example of setting this up in CruiseControl.Net
The first call updates the webserver but includes the database server address so that the deployment will update the appropriate connection strings in the config files. This call runs the Web role.
The second call updates the database server, and runs the database role.
The role is actually passed to the script through the deploy.cmdargs parameter. Since this is a string the role is just being passed through in the calls to MsDeploy. Notice my script to call msdeploy does not change, or reference an additional parameter.
Now my actual deployment script just needs to branch its install logic based on a parameter value of web or database. It is pretty simple. I will show a nant example, but I have already started to move these types of scripts to powershell. There are many reasons for that, but ultimately I think of powershell as being the default scripting language for the servers that we are using. Since the there are built in support for IIS and Sql Server in powershell it only makes sense to use this tool over other scripting tools.
Here is my new build file for deploying roles.
I know I have breezed over how these scripts are wired together, but I hope that the concept still makes sense. I will update the Code Camp Server project with these files as well as the powershell versions of them soon.