:::: MENU ::::

Wednesday, May 16, 2012

Now that I have my source code being checked into GitHub and have TeamCity doing automatic builds (and running tests), I thought it was about time to take the last big step and automatically deploy the latest version of an application to a live site (either for testing or just straight to production, it's up to you) whenever a successful build has taken place.

The best resource I've found for deploying directly from TeamCity (note: the steps would be the same for any CI server) can be found in Troy Hunt's excellent 5 part blog series here: http://www.troyhunt.com/2010/11/you-deploying-it-wrong-teamcity.html.  It is very comprehensive and well worth a read, but I had some issues configuring deployment permissions and wanted to detail them here in case it helps someone else down the road.

An Overview Of the CI Deployment Process

Here's a basic idea of how to get started—if you've ever used the Visual Studio 2010 "Publish" wizard then you are 1/2 way there.  If you have any questions on these steps, refer to the blog series mentioned above or Google with Bing for help.

  • Install Microsoft Web Deploy 2.0 from http://www.iis.net/download/webdeploy on the server you wish to publish to.
  • Setup Web.Config transformations for your desired build configurations (see http://msdn.microsoft.com/en-us/library/dd465318.aspx)
  • Inside Visual Studio, right click –> properties on your Web project, and under Package/Publish Web setup the IIS Web Application name to match your IIS server
    • This is the virtual directory inside IIS that your deployment will be pushed to.  Set it up for each desired build configuration.
  • Setup Permissions on your IIS Server to allow web deployment from your CI agent or service account (detailed below).
  • Craft an MSBuild command that will build AND deploy your web application, and run it during your CI Server build process (also detailed below).

Deploying Via MSBuild

That last point requires a bit of explanation as it's the crux of the problem (other than permissions, which I'll get to later).  What we want MSBuild to do here is to build your project/solution using the desired build configuration (like Debug/Release) and then to use the MS Web Deploy service to push your auto-created deployment package to IIS.  Here's an example of MSBuild parameters from Troy's blog that will accomplish this:

  /P:Configuration=%env.Configuration%
  /P:DeployOnBuild=True
  /P:DeployTarget=MSDeployPublish
/P:MsDeployServiceUrl=https://%env.TargetServer%/MsDeploy.axd
/P:AllowUntrustedCertificate=True
/P:MSDeployPublishMethod=WMSvc
  /P:CreatePackageOnPublish=True
/P:UserName=AutoDeploy\Administrator
/P:Password=Passw0rd

Basically the above parameters use the provided env.Configuration (Debug/Release) to set the build configuration and then tell MSBulid to deploy using WMSvc (web management service) to the service url located at env.TargetServer (you can set the defaults on your CI server).

This is pretty handy, but I unfortunately for me (and maybe for you) there are two problems here:

#1: The user (AutoDeploy\Administrator) needs to be an admin on your IIS, and you need to have allowed Administrators to bypass rules in the "Management Service Delegation" area of IIS (see ScottGu's post here: http://weblogs.asp.net/scottgu/archive/2010/09/13/automating-deployment-with-microsoft-web-deploy.aspx).  For me, this is too much by itself.

#2: The username and password as passed in plain text through your configuration, as shown above. Not good.

The rest of this post will detail how to solve these issues, and in the end we will setup an service account that has non-admin access and which doesn't require passing credentials manually.

Setting Up the Service Account

The first step is to create a non-admin service account that will be used on both your build server and IIS boxes. I'll be using a no-login domain account called "mydomain\builderservice", but any account would work.

On your CI server (in my case, TeamCity), you'll want to run your build agent as your new service account, as shown here:

image

Note you might also have to give this service access to certain files. For example, in TeamCity the build agent needs access to C:\TeamCity\buildAgent to do its work.

Changing the MSBuild Script to Run As "Current User"

This part was fairly tricky since simply removing the UserName/Password parameters from the msbuild command will not work as expected.  Instead you must specify the AuthType to be NTLM (or it will default to Basic) and the UserName=[blank] so it will impersonate the current user.  The relevant parameters are /P:UserName= /P:AuthType=NTLM.  This makes the final MSBuild parameters:

  /P:Configuration=%env.Configuration%
  /P:DeployOnBuild=True 
  /P:DeployTarget=MSDeployPublish 
/P:MsDeployServiceUrl=https://%env.TargetServer%/MsDeploy.axd
/P:AllowUntrustedCertificate=True 
/P:MsDeployPublishMethod=WMSvc 
  /P:CreatePackageOnPublish=True 
/P:UserName= 
/P:AuthType=NTLM

Now that we have TeamCity running MSBuild with these parameters while running under a service account, we need to grant permission on the IIS server that has MS Deploy installed (%env.TargetServer%).

IIS Server Permission For Deployment

Your mileage may vary, but in order to get a successful web deployment from a non-administrator account, I had to perform the following steps, each of which I will explain in detail.

  1. Enable Windows Authentication for the Web Management Server (WMSvc)
  2. Grant Management Service Delegation rights at the Site level to the necessary providers
  3. Grant IIS Manager Permissions to your virtual application
  4. Grant file/folder permissions to the web directory

#1: Enable Windows Authentication for the Web Management Server (WMSvc)

In order to get the WMSvc to accept my build agent credentials, I had to enable Windows Authentication inside the IIS Management Service. You can do this either from the UI or Windows Registry as described in this stackoverflow post.  For convenience, here is the regex key (make sure to restart the WMSvc after making the change): 'reg add HKLM\Software\Microsoft\WebManagement\Server /v WindowsAuthenticationEnabled /t REG_DWORD /d 1'

#2: Grant Management Service Delegation rights at the Site level to the necessary providers

Next you must Delegate to your service account the rights to perform certain actions through the management service providers. If you forget any of these you will get a helpful error message saying that you don't have rights to run a certain provider (ex: "createApp") so you'd then need to come back in and add those.  I needed the following providers: "contentPath, iisApp, createApp, setAcl."

To set a delegation rule go to your site root in IIS and under Management choose "Management Service Delegation."  Now choose "Add Rule" in the upper-right and choose the "Deploy Applications with Content" template (this has the best defaults) and then add in your desired providers. Mine looked like this:

image

Click ok, and now that the rule is defined you just have to select the newly created rule and choose "Add User To Role."  In the ensuing dialog enter the name of your service account and press OK.

image

#3: Grant IIS Manager Permissions to your virtual application

Now that you granted site-level provider access within the {userScope} path, you must give the account IIS permission on the site/application that you will be deploying to.  Choose your site and then under Management choose "IIS Manager Permissions."  Now click "Allow User" and enter the account name again to grant access.

image

#4: Grant file/folder permissions to the web directory

This one is pretty obvious, but you still have to remember to give full control to your service account at the OS-folder level (ex: C:\inetpub\SiteName).  Right-click –> Properties –> Security –> Edit, and then choose Add.  Now type in your service account one more time, grant it full control, and you are finished.

image

Celebrate!

That was certainly a lot of info, and I hope it makes someone's deployment configuration easier.  Integrating your build, test, and deployments with a CI Server like TeamCity has many advantages, including the ability to handle "deploy automatically only when all tests pass" and "oops, deploy the version from last week" scenarios.

May all your Deployments be green.

image

Enjoy!


More

Save this URL, memorize it, write it on a sticky note, tweet it, tell your colleagues about it! 

localtest.me (http://localtest.me)

and

*.localtest.me (http://something.localtest.me)

If you do any testing on your local system you've probably created hosts file entries (c:\windows\system32\drivers\etc\hosts) for different testing domains and had them point back to 127.0.0.1.  This works great but it requires just a bit of extra effort.

This localtest.me trick is so obvious, so simple, and yet so powerful.  I wouldn't be surprised if there are other domain names like this out there, but I haven't run across them yet so I just ordered the domain name localtest.me which I'll keep available for the internet community to use.

Here's how it works. The entire domain name localtest.me—and all wildcard entries—point to 127.0.0.1.  So without any changes to your host file you can immediate start testing with a local URL.

Examples:

http://localtest.me 
http://newyork.localtest.me 
http://mysite.localtest.me 
http://redirecttest.localtest.me 
http://sub1.sub2.sub3.localtest.me

You name it, just use any *.localtest.me URL that you dream up and it will work for testing on your local system.

This was inspired by a trick that Imar Spaanjaars introduced me to. He created a loopback wildcard URL with his company domain name.  I took this one step further and ordered a domain name just for this purpose.

I would have liked to order localhost.com or localhost.me but those domain names were taken. So to help you remember, just remember that it's 'localtest' and not 'localhost', and it's '.me' rather than '.com'.

I can't track usage since the domain name resolves to 127.0.0.1 and never passes through my servers, so this is just a public tool which I'll give to the community. I hope it gets used. And, since I can't really use the domain name to explain itself, please spread the word and tell others about it.

Some examples on how to use it would include:

I hope you enjoy!

More

Wednesday, May 9, 2012

Server: Windows 2003 bit IIS6

Steps I had to take are as follows:

Install framework 4.0 on the computer (this was already done a while back)
within IIS, go to "web service extensions" and ensure that .NET 4.0
has been added and is allowed (not prohibited)
used plesk to move the site in question into its own application pool.
This is important apparently as it can confuse IIS if you try to have
websites targeting different framework version in the same application
pool
instead of manually changing the mappings as in the post above I then
went to this article and followed it
http://weblogs.asp.net/owscott/archive/2006/05/30/ASPNet_5F00_regiis.exe-tool_2C00_-setting-the-default-version-without-forcing-an-upgrade-on-all-sites.aspx


What that article told me in broad terms was:

Use this trick to find out the SiteID of the site(s) you want to
upgrade:http://weblogs.asp.net/owscott/archive/2005/07/29/421058.aspx
Run the following command prompt commands (assuming you know how to
use cmd prompt):

Click start | run | type cmd | press enter
type cd C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319
use the aspnet_regiis tool by typing: aspnet_regiis -sn
W3SCV/{SITEID}/ROOT replacing {SITEID} with the number you got from
the article above.
In my case the cmd looked like:
C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319>aspnet_regiis -SN W3SVC/3868/ROOT
Start registering ASP.NET (4.0.30319) at W3SVC/3868/ROOT.
Finished registering ASP.NET (4.0.30319) at W3SVC/3868/ROOT.
You can then use aspnet_regiis -lk to list all the sites and which
versions they are configured to, which now shows my site is configured
to asp.net 4

The first article is aimed at showing you how to set the defaults for
sites on your server from here on out so my steps above are a slight
variation as I only wanted to set two specific sites to use asp.net 4
and the rest to continue defaulting to asp.net 2.0.