I’m going to tell you the story about automating deployment of large and complex Sitecore project in a real-world.
It all began with a 15-pages document describing website update procedure. There was a huge number of tweaks to website configuration files, machine.config file.
Some were really quick, the other ones could take up to half an hour, for example, creating DB backups, restoring them according to the manual, etc.
And the chance of mistake was so high, that it was rather expected to forget something like uncommenting
Overall, it could easily take 5-6 hours to deploy the solution to production, without even brief testing.
Taking it all into account, the goal to automate it seemed to be impossible. How do we backup and restore right databases into the proper locations, set attributes, uncomment web.config sections, automate IIS?
The answer was so close all the time – PowerShell.
By the end of the story, you’ll see how we’ve managed to reduce documentation size to just one page (saying “Click button X”, “Click Button Y”), completely remove manual steps and reduce total deployment time (to both Content Management and multiple Content Delivery servers) to something about 1 hour, with no website downtime.
So, here’s the brief process overview. From build server to Testing and Production environment - without delays and completely automatically
During the release, new site (let’s call it Staging) is created and configured, while the Production site is running. If everything works well, Staging is simply switched to Production (in just a second), so we get no downtime at all. The other side of this solution is that Content Editors cannot edit content after we’ve created backups of Production, and not yet released Staging.
PowerShell can automate nearly anything. Not your daily job… yet, but all the stuff you can express in documentation.
Deployment process can be split into the different phases:
- Extract files, prepare folders structure, etc.
- Update configuration files, setup security
- Backup old databases, create new ones and restore from backups
- Create Application Pool, Website in IIS and configure their values
- Start the website, install item update packages, rebuild indexes, etc.
- Copy data to one or more Content Delivery servers
- Switch the Staging and Production websites
Extract files
Fairly simple, first, you may also need to download the files for build server:
- $ client = new-object System.Net.WebClient
- $ client.DownloadFile($url, $location)
- $shell_app=new-object -com shell.application
- $zip_file = $shell_app.namespace($archiveFile)
- $destination = $shell_app.namespace($targetFolder)
- $destination.Copyhere($zip_file.items(), 0x14)
Configuration files
You may need to update web.config, here’s how to set Data folder:
- $webConfigPath = $webConfigTemplatePath.Substring(0, $webConfigTemplatePath.LastIndexOf('.'))
- $webConfig = [xml](get-content $webConfigPath)
- $webConfig.configuration.SelectSingleNode("sitecore/sc.variable[@name='dataFolder']").SetAttribute("value", $dataFolder)
- $webConfig.Save($webConfigPath)
- $sampleConfigPath = "$webroot\website\App_Config\Include\Sitecore.Sample.config"
- $sampleConfig = [xml](get-content $sampleConfigPath)
- $sampleConfig.configuration.sitecore.SelectSingleNode("settings/setting[@name=SampleSetting]").SetAttribute("value", "true")
- $sampleConfig.Save($sampleConfigPath)
Backup Databases
No Sitecore-specific tasks here, I’ll just show how to back up the database
- $dbBackup = new-Object ("Microsoft.SqlServer.Management.Smo.Backup")
- $dbRestore = new-object ("Microsoft.SqlServer.Management.Smo.Restore")
- $dbBackup.Database = $d.Name
- $backupFile = $backupFolder + "\" + $dbName + ".bak"
- Write-Host "Backup file:" $backupFile
- $dbBackup.Devices.AddDevice($backupFile, "File")
- $dbBackup.Action="Database"
- $dbBackup.Initialize = $TRUE
- $dbBackup.PercentCompleteNotification = 10
- $dbBackup.SqlBackup($server)
Create Application Pool, Website, etc.
You can create new Application Pool like this
- $serverManager = New-Object Microsoft.Web.Administration.ServerManager;
- $appPool = $serverManager.ApplicationPools.Add($sitename);
- $appPool.ManagedRuntimeVersion = “v4.0”
- $appPool.ProcessModel.username = [string]($user)
- $appPool.ProcessModel.password = [string]($password)
- $appPool.ProcessModel.identityType = "SpecificUser"
- $appPool.ProcessModel.IdleTimeout = [TimeSpan] "0.00:00:00"
Then create a site
- $webSite = $serverManager.Sites.Add($sitename, "http", ":80:www.mysite.net ", $webroot + "\website");
- $webSite.Applications[0].ApplicationPoolName = $sitename;
And commit the changes
- $serverManager.CommitChanges();
Install package, rebuild indexes, and the stuff
The easiest way to implement it is to write some utility pages and just execute web request from PowerShell.
- $pageUrl = "http://mysite.net/Util/RebuildIndex.aspx”
- $pageRequest = [system.net.WebRequest]::Create($pageUrl)
- $pageRequest.Timeout = 1200000
- $pageRequest.GetResponse()
Switch the Staging site to Production
First you may need to stop both sites
- Stop-WebSite -Name $liveSiteName
- Stop-WebSite -Name $stagingSiteName
- New-WebBinding -Name $ stagingSiteName -Port 80 -IPAddress * -HostHeader $liveWebsiteUrl -Protocol "http"
- Start-WebSite -Name $preliveSiteName
If you have any questions regarding the blog post - please let me know by leaving your comment, or via Twitter - @adoprog.
We use MSBuild and Jenkins CI to configure automated build/deploy. I suppose PS would work as well but MSBuild is a language designed for build/deploy work.
ReplyDeleteThe nice thing about PowerShell is that you can do everything with it. Update every single setting in IIS, work with databases just like you're using SQL Management Studio, etc.
ReplyDeleteIt becomes important when you need scalability across the servers, when the site is tightly integrated with lots of additional security / content providers and internal services.
And at the same time, syntax is clear to C# developers. We used to have nAnt scripts before, and I see great difference.
Nice post. We currently use MSBuild for our deployment automation but increasingly I'm swayed to use either PowerShell in it's place or take the plunge with OctopusDeploy.
ReplyDeleteSitecore Rocks makes very effective use of PowerShell scripts to implement it's 'Create a new Sitecore web site' task. If you have the extension installed you can access them from:
%localappdata%\Microsoft\VisualStudio\10.0\Extensions\Sitecore\Sitecore Rocks\0.7.12.1\Repositories\TaskLists\InstallSitecore
Change the path to reflect the version of Visual Studio and the Rocks extension that you are working with.
We currently use MSBuild for project build and transformations, and have TeamCity run these along with Powershell scripts. It means we can create websites, perform db backups, allow IIS changes from settings file in project, so that developers need not access the staging environment at all.
ReplyDeleteThe more you can reduce the interaction for developers, the more you can reduce the risk of issues along the way.