Last month I blogged about automated deployment of ASP.Net websites and ended by saying I was investigating Octopus Deploy. To be sure, Octopus is a great tool. It is very sophisticated but as often happens, it didn’t quite match what I wanted.
As a quick refresher of the last post, I have a process with each of my applications where there is a Psake script which compiles, tests, runs database updates, and packages the output. Each developer can pull from source control and have a working environment, database and all, in one click. Database change management is handled by my AliaSQL database change management tool which creates a local database on SQL Express from repeatable and reliable DDL and DML scripts. TeamCity runs the same Psake script with a few parameters such as database server, packages the artifacts, and publishes the code out to a testing server.
User Acceptance Testing and Going to Production
It is great that the CI server outputs to a testing server for verification but how to you get the newly minted code to the UAT and Production environments? I definitely don’t want the CI server to just blindly publish every build to production!
You have some options. You can hand off the build artifact to the Ops team, publish from Visual Studio, create another build configuration in TeamCity that copies the code to the next environment, use Web Deploy, or some custom batch file or PowerShell script, or worst of all, manually copy files from folder to folder and manually make database schema changes. Tools like Octopus are made to take the pain and inconsistency out of the process. Until recently, I used a batch file with robocopy to publish to production and obviously needed something better.
I should start by listing my assumptions, ideas, and constraints.
- Developers can commit code to any branch
- Developers don’t have access to Production
- Connection strings to anything other than local SQL Express are not checked in to source control (see previous point)
- The Ops team has access to production
- I have about 35 active projects
- Each project is self contained in source control with all necessary database scripts and possibly some test data to make it work without dependencies on a shared database server.
- For some projects, having the code go to the test environment for verification is enough to allow it to go to production. Other projects require steps from developer testing, user testing, automated testing and load testing before going to production.
- Many projects can get deployed several times per day.
- Database change management is a requirement
- TeamCity (via Psake) creates artifacts that contain the compiled website and database scripts similar to the screenshot below.
I spent some time with Octopus Deploy It works well and is very configurable. You have to generate nuget packages for each of your projects. The website would be a package and the database scripts would be another. It requires installing a small service on each target server which I didn’t really like. There are is a concept of environments and roles where you deploy the website files to the servers in a particular role and deploy the database changes to another server. I think the deployment server should be running these things and not the production web server. Its not a huge deal but it didn’t make me comfortable. Finally, I felt there was a lot of ceremony around creating a deployment. If I managed one or 2 large projects, all this structure would be great but with 35 projects and a bunch of environments it was just too much. I should point out that Octopus is a light year ahead of what I have done and if you haven’t, you should give it a try.
The DTMF Deployment Tool
I wanted something low ceremony that was simple and reliable. I started with this set of requirements.In effect, I wanted a web based way to run my old sync batch files with some logging and a request/approval process. The name comes from Dual Tone Multi Frequency which is a signaling protocol for the phone system. I just happened to be explaining DTMF to my daughter when I started this project so I decided to use the name.
I started off by prototyping out a way to run the steps in the old batch file via C#. (take app offline, copy files, run config transforms, run database updates, bring app online) After a few days work DTMF was born. Here is what it does.
- The app pool running DTMF needs privileged access to the target environments
- Developers can request publishing of build from one environment to another.
- The UI shows the version number running on target environment and the version to be deployed along with last publish date
- Each project can have zero or more target databases and zero or more target servers
- Support for synchronizing files, running config transforms, running database change scripts.
- Support for custom PowerShell to be executed
- Allows rollback to a previous version of the application (though the database can’t be rolled back)
- TeamCity integration to make sure the current project isn’t currently building
- HipChat integration to notify a room when sync request are made and when syncs are ran
- Ability to send emails to the Ops team when sync requests are made
- SignalR usage to show real time output of the PowerShell running on the server
- Detailed logging of each deployment
- Entire system is file based with no database. Configurations are simple XML files.
Developers request screen
Operations sync screen
A deployment in action
- Ability to publish any arbitrary version. DTMF can deploy the latest build and rollback to the the last build deployed to the target environment only.
- There is no concept of promoting between environments, just a build output source and a target environment. I handle this with branches where the stable Production repository publishes to production. New work is done in a branch off of the Development repository and when it is ready for testing it is merged up to the root Development repository. Once testing is complete, it gets merged with the stable Production branch. There is no quick way to get code from the Development branch onto Production.
- Probably some feature you need
This project is currently managing all of my internal deployments. It is very simple to add new projects, I have a dashboard to see what versions are running where, along with a request/approval process. Let me know what you think in the comments. The code is is up on GitHub at https://github.com/ericdc1/DTMF