jon torresdal

  • About
  • Contact

    No-Click Web Deployment – Part 2 – Web Deploy (a.k.a. msdeploy)

    16. August 2010

    In Part 1 I hadn’t decided if I was going to use Web Deploy as the base of this blog series or the PowerShell scripts I already had in production. I decided to give Web Deploy a chance. In the end I didn’t regret it, but I must admit it was not straight forward. Hopefully this post will make it a breeze for you :-)

    Web Deploy With VS 2010 and TFS 2010

    VS 2010 and TFS 2010 now comes with Web Deploy integration and works great for low to medium complex web apps. When I tried it out with my requirements I did not manage to get my solution to work so I reverted back to the command line version.

    The documentation for this topic is also sparse, and it looks/feels unfinished. Here’s some resources if you’re going down that road:

    The Web Deploy MSBuild schema: C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\Web

    The official doc: http://msdn.microsoft.com/en-us/library/dd394698.aspx

    Web Deploy @PDC: http://www.microsoftpdc.com/2009/FT56

    FAQ: http://blogs.msdn.com/b/aspnetue/archive/2010/03/05/automated-deployment-in-asp-net-4-frequently-asked-questions.aspx

    MSBuild Web Deploy arguments + more resources: http://weblogs.asp.net/jdanforth/archive/2010/04/24/package-and-publish-web-sites-with-tfs-2010-build-server.aspx

    THE commands

    The two commands below solves all the requirements I listed in my previous post. I spent a great deal of time learning and studying Web Deploy in order to come up with this, so I hope you find it useful. It might not look too hard now, but nothing is when you have the solution in front of you :-) I’m always open for better ways if you find one though. If I could ask the Web Deploy team for a new feature, it would be to make the two commands below really simple.

    The rest of this post will discuss these commands in detail. Text in blue can be replaced with your own values.

    Create package:

    msdeploy.exe
    	-verb:sync
    	-source:manifest=PackageManifest.xml
    	-dest:package=Package.zip,encryptPassword="certificatePassword"
    	-enableLink:AppPoolExtension
    	-disableLink:CertificateExtension
    	-disableLink:ContentExtension
    	-replace:objectName=httpCert,targetAttributeName=hash,replace=08bf3e051bd10cd8d89ac1a3ac431887886ed343
    	-replace:objectName=logFile,targetAttributeName=directory,replace=C:\Web\Logs
    	-replace:objectName=virtualDirectory,targetAttributeName=physicalPath,match="C:\\WebDeployTemplateWebSites",replace="C:\Web"
    	-declareParam:name=HttpsBinding,kind=DestinationBinding,scope=webSiteName,match=.*:443:
    	-declareParam:name=HttpBinding,kind=DestinationBinding,scope=webSiteName,match=.*:80:
    	-declareParam:name=AppPoolUsername,kind=DeploymentObjectAttribute,scope=processModel,match=processModel/@userName
    	-declareParam:name=AppPoolPassword,kind=DeploymentObjectAttribute,scope=processModel,match=processModel/@password

    Install package:

    msdeploy.exe
    	-verb:sync
    	-source:package=Package.zip,encryptPassword="certificatePassword"
    	-dest:manifest=InstallManifest.xml,computerName=FQDN,username="domain\user",password="domainUserPassword"
    	-setParam:name=HttpsBinding,value=10.0.0.21:443:
    	-setParam:name=HttpBinding,value=10.0.0.21:80:
    	-setParam:name=AppPoolUsername,value=MyDomain\AppPoolServiceAccount
    	-setParam:name=AppPoolPassword,value=MySecureAppPoolPassword

    Note that the above commands are one-liners. I only structured them the way I did to make them readable.

    Complex

    Web Deploy was built for the purpose of deploying web applications, so at first it looked like the perfect solution. However, I soon realized I had to study it in great detail to make it do what I wanted. I’m talking days not hours. Time I was not eager to spend to replace something already working or just for the sake of this blog post (sorry guys :-)). The reason for not giving up on it entirely was because Web Deploy had the potential to simplify/replace my scripts, have fewer moving parts, and make the total solution easier to maintain.

    Around the same time as I published Part 1 I tweeted my concern about Web Deploy’s complexity and the @wdeploy team contacted me. I sent them a long email describing my concerns and they promised to do “creative things in the future” to make it less complex. I’ve been in contact several times after that and they are very responsive and eager to get feedback on the product. I’m personally looking forward to see (and maybe help influence) how this product will evolve.

    Web Deploy Command Options

    Before diving into the inner workings of these commands, we need to know a bit more about the tool. Web Deploy have a lot of functionality and is extremely powerful. Here’s the command line syntax:

    	msdeploy.exe -verb:<verbName>
    	-source:<provider>[=<pathToProviderObject>
    		[,<providerSetting>=<providerSettingValue>]]
    	[-dest:<provider>[=<pathToProviderObject>
            	         [,<providerSetting>=<providerSettingValue>]]
    	]
    	[-<MSDeployOperationSetting> ...]

    Doesn’t look too scary right? There is more to it though…

    Verbs

    The following verbs exist:

    • delete
    • dump
    • getDependencies
    • getParameters
    • getSystemInfo
    • sync

    Providers

    Let’s look at which providers it has:

    • Web Deploy appHostConfig Provider
    • Web Deploy appHostSchema Provider
    • Web Deploy appPoolConfig Provider
    • Web Deploy archiveDir Provider
    • Web Deploy auto Provider
    • Web Deploy cert Provider
    • Web Deploy comObject32 Provider
    • Web Deploy comObject64 Provider
    • Web Deploy contentPath Provider
    • Web Deploy createApp Provider
    • Web Deploy dbFullSql Provider
    • Web Deploy dbMySql Provider
    • Web Deploy dbSqlite Provider
    • Web Deploy dirPath Provider
    • Web Deploy fcgiExtConfig Provider
    • Web Deploy filePath Provider
    • Web Deploy gacAssembly Provider
    • Web Deploy iisApp Provider
    • Web Deploy machineConfig32 Provider
    • Web Deploy machineConfig64 Provider
    • Web Deploy manifest Provider
    • Web Deploy metaKey Provider
    • Web Deploy package Provider
    • Web Deploy recycleApp Provider
    • Web Deploy regKey Provider
    • Web Deploy regValue Provider
    • Web Deploy rootWebConfig32 Provider
    • Web Deploy rootWebConfig64 Provider
    • Web Deploy runCommand Provider
    • Web Deploy setAcl Provider
    • Web Deploy urlScanConfig Provider
    • Web Deploy webServer Provider
    • Web Deploy webServer60 Provider

    These are of course only the built-in providers, then you can create your own or use 3rd party ones if you like. A quick scan through this list shows that it does a lot more that just web stuff, like COM objects, registry settings, certificates, gac, databases.. the lot.

    Provider Settings

    The providers again have a set of common provider settings:

    • authType
    • computerName
    • encryptPassword
    • getCredentials
    • ignoreErrors
    • includeAcls
    • password
    • storeCredentials
    • tempAgent
    • userName
    • wmsvc

    MSDeployOperationSetting

    From the documentation:

    Web Deploy operation settings are non-provider specific command-line flags. They modify all of a Web Deploy operation.

    • allowUntrusted
    • declareParam
    • declareParamFile
    • dest
    • disableLink
    • disableRule
    • disableSkipDirective
    • enableLink
    • enableRule
    • enableSkipDirective
    • postSync
    • preSync
    • removeParam
    • replace
    • retryAttempts
    • retryInterval
    • setParam
    • setParamFile
    • showSecure
    • skip
    • source
    • useCheckSum
    • verb
    • verbose
    • whatif
    • xml
    • xpath

    Manifest Provider

    We now have an overview of the command line syntax of the tool, but there are a few other important aspects. The first one being the manifest provider. Most likely you want to use more than one provider in your command, and that’s exactly what this provider does. Here’s an example from the documentation:

    <sitemanifest>
    
       <appHostConfig path="mySite" />
    
       <gacAssembly path="System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    
       <comObject path="Microsoft.ApplicationHost.AdminManager" />
    
       <contentPath path="c:\source" />
    
       <regKey path="HKLM\Software\ODBC" />
    
    </sitemanifest>

    I would actually preferred having these on the command line instead. When I trigger my commands from a build, I’m inserting variables into the command anyways and I would be better of with the ONE command and not have to maintain the xml files as well. Actually I would like to have both options. In the command I would suggest something like this (which would adhere to the existing conventions):

    -source:appHostConfig=mySite,gacAssembly=System.Web…,[…]=[…]

    Link Extensions

    Another one is the concept of link extensions, which can be enabled/disabled by using the enableLink and disableLink operations. One example drawn from the documentation is:

    …if you specify -disableLink:ContentExtension on the command line, you can prevent content from being included in a sync operation. This enables you to synchronize two Web servers without moving any content.

    Web Deploy Rules

    Web Deploy rules exists to disable or enable built-in or custom rules (using e.g. the enableRule and disableRule operations) for the sync verb. This is however (naturally) only true if the isDefault attribute is set to true in the rule definitions. See here to find the built-in rules. By creating the file Msdeploy.exe.configsettings in %program files%\IIS\Microsoft Web Deploy folder, you can add custom rules.

    Packages and Archives

    From the docs:

    The Web Deploy package and archiveDir features let you create a snapshot backup of your Web site or Web server into a .zip file or archive directory. In addition, the parameterization and manifest features let you customize the archive or package that you create. You can then use your package files to deploy Web sites and Web servers to other computers or computer locations.

    What’s wrong?

    That’s a lot of stuff to consume! In order to effectively use this tool for deployment, you have to learn most of these verbs, providers and operations, figure out how they work and how you can take advantage of them.

    This is (in my opinion) what Greg Young have been talking about and expressed in the NDC Magazine article Failure (well worth the read), where the intent is lost in the system and the user is forced to “reverse engineer” it to make sense of it all.

    I’m fully aware of the endless amount of user scenarios that exists, and I don’t expect the Web Deploy team to cover them all, but the most common ones would be nice. Like the one I’m showing in this post I would think would be quite common for auto deployment scenarios. The advanced configuration could still be available for the not-so-common scenarios. Instead I’m “forced” to spend a lot of time learning the inner workings of a complicated tool, which in the end create a lot of value. How valuable wouldn’t it be if I didn’t have to invest so much time in learning the tool?

    I’m also aware of the new TFS 2010 integration that exists, which simplifies many of these tasks, but that solution lacks documentation and the advanced options are hard to get at.

    Setting up Web Deploy for remote access

    To be able to access a server remotely, Web Deploy must be given access to the server. Several options are available, but I’ll focus on the Web Deployment Agent Service, which requires administrator privileges to use.

    The Agent Service requires Web Deploy to be installed on the target server. You can find the detailed installation instructions here: http://technet.microsoft.com/en-us/library/dd569030(WS.10).aspx

    Basic Usage

    Let’s look at some vanilla examples for deploying web stuff remotely:

    msdeploy

      -verb:sync

      -source:contentpath=c:\data,

      -dest:contentpath=c:\data,

          computerName=Server2,

          username=admin,

          password=pass

    This copies your local C:\data directory to the server Server2, and provide a username and password to get access to the remote server. This is done by using the sync verb and the contentpath provider. So we can push files, which is nice cause we don’t have to use FTP, BITS or similar.

    Deployment Requirements 

    We want to do a lot more than just copy files. Here’s a list extracted from my previous post of what I want to deploy to remote servers:

    • File content
    • Virtual Directories and Applications settings
    • AppPools settings
    • Certificates
    • Bindings
    • Log location settings
    • Virtual Directory file location settings

    Packaging structure

    My commands can be used to produce one package per web site multiplied by the number of environments you have (e.g. Dev, Test and Prod). So if you have 4 web sites and 3 environments, you create 12 packages.

    To better understand why this is, here’s a list of the settings that are specific for each environment and common across all servers in one specific environment:

    • File content
    • SSL Certificate password
    • Certificate hash/thumbprint
    • Web site log directory location
    • Virtual directory root locations

    For server specific differences we create the package so that it accepts parameters for:

    • User and password for the service account under which the worker process of the Application Pools runs
    • The https binding (if used)
    • The http binding (if used)

    If we did not define the last three parameters, we would have to multiply the packages with the amount of servers in the different environments as well. 4 web sites, 3 environments and 2 servers in each environment = 24 packages. You don’t want to go there…

    Another option would be to define all possible changes as parameters, leaving you with only one package. I tried that. I could not figure out how to accomplish all of these using params, so I analyzed what I needed and used a little of both. It works, but could be better.

    As an example of the above, a package for the web site blog.torresdal.net could be created for e.g. Dev with these settings:

    • File content = E:\MyBuildOutput\blog.torresdal.net
    • Certificate password = MySecureSSLPassword
    • Certificate hash=08bf3e051bd10cd8d89ac1a3ac431887886ed343
    • Web site log dir = E:\Logs\blog.torresdal.net
    • Virtual Directory locations = E:\Web

    …and used these parameters when deploying:

    • Username for AppPool = MyDomain\AppPoolServiceAccount
    • Password for AppPool = MySecureAppPoolPassword
    • Https binding = 10.0.0.21:443:
    • Http binding = 10.0.0.21:80:

    Notes on Application Pool

    Note on bindings: You have to use either http or https or both. If you want to use hostname you could do: *:80:blog.torresdal.net

    Note that host names are not supported on SSL in IIS 7, even though it’s technically possible to do.

    Note on the service account for the application pool: On Windows Server 2008, IIS support Application Pool Identities. These are Windows virtual accounts that are assigned to the application pool effectively isolating it from other services. If you want to use these, then you don’t have to declare the parameters for the app pool identities as long as your source is using App Pool Id’s.

    Dissecting The Create Package Command

    I believe you now have an idea of what the commands above do, but lets pull it apart and describe each piece by itself.

    The package manifest file

    First we’re going to look at the manifest file which contains all source providers used to create the package:

    <sitemanifest>
    
       <appHostConfig path="blog.torresdal.net" />
    
       <cert path="my\08bf3e051bd10cd8d89ac1a3ac431887886ed343 " />
    
       <dirPath path="E:\MyBuildDrop\LatestVersion\Dev\blog.torresdal.net" />
    
    </sitemanifest>

    This is the way that Web Deploy allows you to use more than one provider. Here’s a short description of each provider and what it does:

    appHostConfig Gets all IIS specific settings from a web site.
    cert Gets the certificate with the given thumbprint/hash.
    dirPath Gets the content from the given path.

    The create Package command

    Now lets look at each section of the command:

    -verb:sync Tells Web Deploy to do a sync
    -source:manifest=PackageManifest.xml Points to the manifest file showed above containing all providers to use as source.
    -dest:package=Package.zip,

    encryptPassword="certificatePassword"
    Use the package provider as destination for creating a package (zip) containing all content and information needed to deploy a package to a server. Since we’re using the cert provider (in the manifest) we need to provide the password to get access to the certificate.
    -enableLink:AppPoolExtension I want the application pool to be synced as well.
    -disableLink:CertificateExtension The appHostConfig provider include certificate and content by default. I want to control which certificate and what content to include, so I use –disableLink to disable these extensions. That is why I’ve added the cert and dirPath providers in the manifest so that I can be explicit about these.
    -disableLink:ContentExtension See previous…
    -replace:objectName=httpCert,

    targetAttributeName=hash,

    replace=08bf3e051bd10cd…

    The appHostProvider and the cert provider are unaware of each others actions, so the appHostProvider outputs the thumbprint from the certificate found in IIS. I need to replace the httpCert hash property with the same hash used in the manifest file or else the web site would be bounded to the wrong certificate.
    -replace:objectName=logFile,

    targetAttributeName=directory,

    replace=C:\Web\Logs

    I want to replace the IIS log directory to a different path than the IIS I’m exporting from.
    -replace:objectName=virtualDirectory,

    targetAttributeName=physicalPath,

    match="C:\\WebDeployMasterWebSites",

    replace="C:\Web"

    The web site I’m exporting from reside in C:\WebDeployMasterWebSites\{webSiteName}, and all Virtual Directories are located below this path. I want to control the root path, so I replace it.

    Note: This would be a natural candidate for a parameter, but with params you can only replace the complete value, not just part of it.

    Here’s a description of the parameter declarations allowing us to pass in params when deployment the package (these are also part of the same command):

    -declareParam:name=HttpsBinding,

    kind=DestinationBinding,

    scope=webSiteName,

    match=.*:443:

    I want to control the SSL binding for the web site.
    -declareParam:name=HttpBinding,

    kind=DestinationBinding,

    scope=webSiteName,

    match=.*:80:

    Same as above only for HTTP.
    -declareParam:name=AppPoolUsername,

    kind=DeploymentObjectAttribute,

    scope=processModel,

    match=processModel/@userName

    I want to set the user name of the account under which the worker process of the Application Pools runs
    -declareParam:name=AppPoolPassword,

    kind=DeploymentObjectAttribute,

    scope=processModel,

    match=processModel/@password

    Same as above only for the password.

    To shorten the above command a tiny bit you can define the parameters in an xml file instead, like this:

    <parameters>
    
       <parameter name="HttpsBinding" description="Web Site Binding for SSL">
    
          <parameterEntry kind="DestinationBinding" scope="sikker.frende.no" match=".*:443:" />
    
       </parameter>
    
    
    
       <parameter name="HttpBinding" description="Web Site Binding for http">
    
          <parameterEntry kind="DestinationBinding" scope="sikker.frende.no" match=".*:443:" />
    
       </parameter>
    
    
    
       <parameter name="AppPoolUsername" description="Account username for this application pool">
    
          <parameterEntry kind="DeploymentObjectAttribute" scope="processModel" match="processModel/@userName"/>
    
       </parameter>
    
    
    
       <parameter name="AppPoolPassword" description="Account password for this application pool">
    
          <parameterEntry kind="DeploymentObjectAttribute" scope="processModel" match="processModel/@password"/>
    
       </parameter>
    
    </parameters>

    You will then replace the –declareParam operation settings above with this:

    -declareParamFile:MyParamFile.xml

    However, if you’re going to execute this command from TFS or some other build tool, you’re better off leaving them inside the command. Less moving parts.

    Dissecting The Deploy Package Command

    We also need a manifest file when installing the package. This is ALMOST identical to the manifest we used when creating the package:

    <sitemanifest>
    
       <appHostConfig path="blog.torresdal.net" />
    
       <cert path="my\08bf3e051bd10cd8d89ac1a3ac431887886ed343 " />
    
       <dirPath path="E:\Web" />
    
    </sitemanifest>

    The only difference between the two is in the dirPath provider. For the package we used files from E:\MyBuildDrop\LatestVersion\Dev\blog.torresdal.net, but when deploying we PUT files to E:\Web.

    The deployment package command

    Each section in detail:

    -verb:sync Tells Web Deploy to do a sync
    -source:package=Package.zip,

    encryptPassword="certificatePassword"
    Uses the earlier created package as source. Since this package contains a certificate, you need to provide the certificate password in order to get access to it.
    -dest:manifest=InstallManifest.xml,

    computerName=FQCN,

    username="domain\user",

    password="domainUserPassword"

    Points to the manifest file to use for deployment, and to which server we are deploying to with the username/password.
    -setParam:name=HttpsBinding,

    value=10.0.0.21:443:
    Set the SSL binding for the web site. Using IP 10.0.0.21 on port 443 (SSL).
    -setParam:name=HttpBinding,

    value=10.0.0.21:80:
    Same as above only for HTTP.
    -setParam:name=AppPoolUsername,

    value=MyDomain\AppPoolServiceAccount
    Set the user name for the account under which the worker process of the Application Pools runs
    -setParam:name=AppPoolPassword,

    value=MySecureAppPoolPassword
    Same as above, only for the password

    The Build/Deploy Process Using Web Deploy

    Here’s the exact same deployment process overview as in my previous post, only now with Web Deploy. As a result the process got two steps shorter :-)

    image

    What’s Next?

    In my next post I’ll either show you how to control the load balancer during deployment or integration with TFS. Both will be covered in the end.

  • Recent Posts

    • How ConDep came to life
    • Introducing ConDep
    • Lightning Talk: Why you shouldn’t track bugs
    • How Do We Track Bugs? Check In a Failing Test!
    • Stepping Down from NNUG Bergen, Still Chairman of NNUG National
  • Archives

    • March 2013
    • February 2013
    • November 2012
    • January 2012
    • June 2011
    • May 2011
    • September 2010
    • August 2010
    • June 2010
    • April 2010
    • March 2010
    • February 2010
    • January 2010
    • December 2009
    • August 2009
    • July 2009
    • June 2009
    • May 2009
    • April 2009
    • March 2009
    • February 2009
    • January 2009
    • December 2008
    • November 2008
    • October 2008
    • September 2008
    • August 2008
    • July 2008
    • June 2008
    • May 2008
    • April 2008
    • March 2008
    • February 2008
    • January 2008
    • December 2007
    • November 2007
    • October 2007
    • September 2007
    • August 2007
    • July 2007
    • June 2007
    • May 2007
    • April 2007
    • March 2007
    • February 2007
    • January 2007
    • December 2006
    • November 2006
    • October 2006
    • September 2006
  • Categories

    • .Net
    • ADFS
    • Agile
    • Ajax
    • Architecture
    • Articles
    • ASP.NET
    • ASP.NET-MVC
    • Blogging
    • Books
    • BPEL
    • CleanCode
    • CloudComputing
    • Community
    • ContinuousDelivery
    • ContinuousDeployment
    • CSharp
    • DasBlog
    • Database
    • DDD
    • Deployment
    • DevOps
    • DSL
    • Events
    • ExtremeProgramming
    • Fun
    • Gadgets
    • IIS
    • InfoQ
    • Java
    • Kanban
    • Lean
    • Linq
    • MemoryLeaks
    • Microsoft
    • MVC
    • NDC
    • NNUG
    • Other
    • Patterns
    • Performance
    • Scrum
    • Security
    • Silverlight
    • Software
    • TeamManagement
    • TechEd
    • Testing
    • Tools
    • TvGuide
    • Uncategorized
    • Vista
    • VisualStudio
    • WCF
    • Web
    • WebDeploy
    • WIF
    • Windows
    • WiX
    • Work
    • Workflow
  • Meta

    • Log in
    • Entries RSS
    • Comments RSS
    • WordPress.org

Tumblog WordPress Themes by Theme created by Obox