Sunday, 19 December 2010

Using WebDeploy with Windows Azure

Update:  Looks like Wade also blogged about this, showing a similar way with some early scripts I wrote.  However, there are some important differences around versioning of WebDeploy and creating users that you should pay attention to here.  Also, I am using plugins, which are much easier to consume.

One of the features announced at PDC was the coming ability to use the standard IIS7 WebDeploy capability with Windows Azure.  This is exciting news, but it comes with an important caveat.  This feature is strictly for development purposes only.  That is, you should not expect anything you deploy using WebDeploy to persist longterm on your running Windows Azure instances.  If you are familiar with Windows Azure, you know the reason is that any changes to the OS post-startup are not durable.

So, the use case for WebDeploy in Windows Azure is in the case of a single instance of a role during development.  The idea is that you would:

  1. Deploy your hosted service (using the .cspkg upload and deploy) with a single instance with WebDeploy enabled.
  2. Use WebDeploy on subsequent deploys for instant feedback
  3. Deploy the final version again using .cspkg (without WebDeploy enabled) so the results are durable with at least 2 instances.

The Visual Studio team will shortly be supplying some tooling to make this scenario simple.  However, in the interim, it is relatively straightforward to implement this yourself and do what the tooling will eventually do for you.

If you look at the Windows Azure Training Kit, you will find the Advanced Web and Worker Lab Exercise 3 and it will show you the main things to get this done.  You simply need to extrapolate from this to get the whole thing working.

We will be using Startup Tasks to perform a little bit of bootstrapping when the role instance (note the singular) starts in order to use Web Deploy.  This will be implemented using the Role Plugin feature to make this a snap to consume.  Right now, the plugins are undocumented, but if you peruse your SDK bin folder, it won't be too hard to figure out how they work.

The nice thing about using a plugin is that you don't need to litter your service definition with anything in order to use the feature.  You simply need to include a single "Import" element and you are done!

Install the Plugin

In order to use this feature, simply extract the contents of the zip file into "%programfiles%\Windows Azure SDK\v1.3\bin\plugins\WebDeploy".  You might have to extract the files locally in your profile first and copy them into this location if you run UAC.  At the end of the day, you need a folder called "WebDeploy" in this location with all the files in this zip in it.

Use the Plugin

To use the plugin you simply need to add one line to your Service Definition:

 <Imports>
      <Import moduleName="RemoteAccess" />
      <Import moduleName="RemoteForwarder" />
      <Import moduleName="WebDeploy"/>
    </Imports>

Notice, in my example, I am also including the Remote Access and Remote Forwarder plugins as well.  You must have RemoteAccess enabled to use this plugin as we will rely on the user created here.  The Remote Forwarder is required on one role in your solution.

Next, you should hit publish on the Windows Azure project (not Web Site) and setup an RDP user.  We will be using this same user later in order to deploy because by default the RDP user is also an Admin with permission to use Web Deploy.  Alternatively, you could create an admin user with a Startup Task, but this method is easier (and you get RDP).  If you have not setup the certificates for RDP access before, it is a one time process outlined here.

 

image

 

image

Now, you publish this to Windows Azure using the normal Windows Azure publishing process:

image

That's it.  Your running instance has WebDeploy and the IIS Management Service running now.  All you had to do was import the WebDeploy plugin and make sure you also used RDP (which most developers will enable during development anyway).

At this point, it is a pretty simple matter to publish using WebDeploy.  Just right click the Web Site (not the Cloud Project) and hit publish:

image

You will need to type in the name of your .cloudapp.net project in the Service URL.  By default, it will assume port 8172; if you have chosen a different public VIP port (by editing the plugin -see *hint below), here is where you need to update it (using the full https:// syntax).

Next, you need to update the Site/Application.  The format for this is ROLENAME_IN_0_SITENAME, so you need to look in your Service Definition to find this:

image

Notice, in my example, my ROLENAME is "WebUX" and the Site name is "Web".  This will differ for each Web Role potentially, so make sure you check this carefully.

Finally, check the "Allow untrusted certificate" option and use the same RDP username and password you created on deploy.  That's all.  It should be possible for you to use Web Deploy now with your running instance:  Hit Publish and Done!

How it works

If you check the plugin, you will see that we use 2 scripts and WebPI to do this.  Actually, this is the command line version of WebPI, so it will run without prompts.  You can also download it, but it is packaged already in the plugin.

The first script, called EnableWebAdmin.cmd simply enables the IIS Management service and gets it running.  By default, this sets up the service to run and listen on port 8172.  If you check the .csplugin file, you will notice we have opened that port on the Load Balancer as well.

start /w ocsetup IIS-ManagementService
reg add HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WebManagement\Server /v EnableRemoteManagement /t REG_DWORD /d 1 /f
net start wmsvc
sc config WMSVC start= auto
exit /b 0

*Hint: if you work at a place like Microsoft that prevents ports other than 443 to host SSL traffic, here would be a good place to map 443 to 8172 in order to deploy.  For most normal environments, this is not necessary.

Next, we have the proper WebDeploy installation command using WebPI command line.

@echo off
ECHO "Starting WebDeploy Installation" >> log.txt
"%~dp0webpicmd\WebPICmdLine.exe" /Products: WDeploy /xml:https://www.microsoft.com/web/webpi/2.0/RTM/WebProductList.xml /log:webdeploy.txt

ECHO "Completed WebDeploy Installation" >> log.txt

 

net stop wmsvc

net start wmsvc

You will notice one oddity here - namely, we are using the WebPI 2.0 feed to install an older version of WebDeploy (v1.1).  If you leave this off, it will default to the 3.0 version of WebPI that uses the Web Deploy 2.0 RC.  In my testing, Web Deploy 2.0 RC only works sporadically and usually not at all.  The 1.1 version is well integrated in VS tooling, so I would suggest this one instead until 2.0 works better.

Also, you will notice that I am stopping and restarting the IIS Management Service here as well.  In my testing, WebDeploy was was unreliable on the Windows Server 2008 R2 family (osFamily=2).  Starting and stopping the service seems to fix it.

Final Warning

Please bear in mind that this method is only for proto-typing and rapid development.  Since the changes are not persisted, they will disappear the next time you are healed by the fabric controller.  Eventually, the Visual Studio team will release their own plugin that does essentially the same thing and you can stop using this.  In the meantime, have fun!

Sunday, 19 December 2010 23:20:24 (Eastern Standard Time, UTC-05:00)
Works great! Thanks so much. Quick note though, the save path should be "%programfiles%\Windows Azure SDK\v1.3\bin\plugins\WebDeploy" (add the "plugins" and no spaces for "Web Deploy). Other than that it worked great! Make sure only 1 site has the RemoteForwarded import.

Thanks again! This is exactly what I needed, will save me tons of time.
--Aaron
Monday, 20 December 2010 20:12:41 (Eastern Standard Time, UTC-05:00)
Great solution! my only little stumbles were 1) I had to add a _web to the application name shown in the azure manager to get it work and 2) I had to remember it is https and not http.

Thanks for putting this together!
Monday, 20 December 2010 23:29:17 (Eastern Standard Time, UTC-05:00)
@Aaron - fixed the typos. Thanks!

@Peter - Check the post again - you should be using your Site name, not "_Web" unless it actually happens to be that. See the two highlighted areas in the Service Definition? See the format as I listed? Also, notice in the screenshot that if you do everything correctly, it uses HTTPS and I mention you should "Allow untrusted certificate".
Thursday, 30 December 2010 21:33:08 (Eastern Standard Time, UTC-05:00)
Thanks for putting together the plugin and blogging it. I set this up yesterday and it worked great. I combined it with multiple sites--I had a "main" application, plus two "spike" sites. I setup DNS CName records for www.XXX.com (the main site), spike1.XXX.com and spike2.XXX.com. It all worked smoothly and I could WebDeploy to all three sites just fine.

But ... I deleted the deployment last night and deployed again today. This time I added a second web application--so there are four IIS sites altogether. After deploying, all four sites worked fine. I did a WebDeploy successfully twice to the new application. Then ... I started getting the error below consistently. Rebooting the instance doesn't help either. I remoted into it but I don't see anything wrong (and that shows the remote stuff seems to be working. I don't know WebDeploy very well, is this the flakey problem you alluded to when you described your WebDeploy version choice?

Error 5 Web deployment task failed.(Remote agent (URL https://XXXX.cloudapp.net:8172/msdeploy.axd?site=XXXX.mvc_IN_0_Spike1) could not be contacted. Make sure the remote agent service is installed and started on the target computer.)

Remote agent (URL https://XXXX.cloudapp.net:8172/msdeploy.axd?site=XXXX.mvc_IN_0_Spike1) could not be contacted. Make sure the remote agent service is installed and started on the target computer.
An unsupported response was received. The response header 'MSDeploy.Response' was '' but 'v1' was expected.
The request was aborted: The request was canceled.
COM object that has been separated from its underlying RCW cannot be used. 0 0 XXXX.mvc

Jeff G. Young
Friday, 31 December 2010 04:58:25 (Eastern Standard Time, UTC-05:00)
Update: After trying almost everything I could do through the Windows Azure portal and via remote desktop to the server, I restarted Visual Studio 2010 and the problem went away--WebDeploy works again without the above error. Since I can't reproduce the problem I don't really know the origin but if anybody else runs into this, try restarting Visual Studio first. :)

WebDeploy and multiple site support is an awesome combination for development productivity!
Jeff G. Young
Comments are closed.