Configure IIS websites on Windows Azure with startup tasks and AppCmd
At LeanSentry, we use Windows Azure heavily to scale out our extensive data collection and diagnostic data processing. Just like anyone else, we have our fair share of difficulties with deploying and configuring our web roles, esp. when it comes to more advanced configuration. As a result, we often rely on startup tasks to configure IIS and other windows server components to do stuff we need.
Here are some tips and a tool we use to make these tasks much easier.
Configuring your Web role web site or application pool AFTER they are created
One of the issues for using startup tasks for configuring IIS is that the website definition is not yet created when your startup tasks are run. As a result, attempts to configure your website will fail with "website not found".
The workaround we use is to delay the execution of startup tasks using AppCmd till the website is created. The key things are:
1) Mark your tasks as "background". This way, Azure will not wait to put the role into a Ready state and create the website until your task is finished.
2) Delay the execution of your task until Azure has finished creating your website, using ExecWithRetries.exe
The second thing is harder, because there is no magical way to tell when the Azure IISConfigurator.exe process finishes creating your site. So, we wrote a helper tool called ExecWithRetries that allows us to wait for a while, and also make sure our configuration changes take.
The tool can delay the execution of an arbitrary command you specify, as well as to repeat it any number of times until it works with a specified delay between each attempt.
Here is the result:
<Task commandLine="StartupExecWithRetries.exe "/c:StartupAzureEnableWarmup.cmd" /d:5000 /r:20 /rd:5000 >> c:enablewarmup.cmd.log 2>>&1" executionContext="elevated" taskType="background" />
Be sure to use the normal " to specify multiple arguments with spaces - some text editors may convert the " character to a special angled quote which will not work in cmdline.
Also be sure to encode the quotes as " inside the azure startup task argument.
Get the ExecWithRetries tool:
- Download ExecWithRetries.exe here.
- To use it, add it to the Startup folder of your Azure role project, and set its "Copy to output directory" to "Always".
- Get the help by running the tool with no parameters:
Executes a command after waiting a little bit, with optional retries.
Usage: ExecWithRetries /c:<command> /a:<arguments> [/d:delayMs] [/r:retries] [/rd:retryDelayMs]
/c: Command to execute
/a: Arguments for the command
/e: Expected return codes (comma separated list).
If the command doesnt return the expected code, it counts as a failure
/d: How long to wait before first attempt in milliseconds (default: 0)
/r: Number of retries on failure (default: 0)
/rd: How long to wait between retries in milliseconds (default: 10000)
Finding the website and application pool for a web role
There is one more issue to be aware of: the names of the websites, application pools, etc that you may want to target with your commands are not necessarily known ahead of time. For example:
- The application pool is typically named with a GUID.
- The website is named after the role instance name, which is rolename_instance number. This makes it different on each instance of your role.
One quick workaround for this is to use AppCmd search with the web role name as the prefix for the site name, and pipe the resulting site to appcmd to configure it.
Here is an example:
> %windir%system32inetsrvappcmd list sites "/name:$=MyWebRoleName*" /xml | %windir%system32inetsrvappcmd set site /in /serverAutoStart:true
And an example for the application pool:
> %windir%system32inetsrvappcmd list sites "/name:$=MyWebRoleName*" /xml | %windir%system32inetsrvappcmd list apps /in /xml | %windir%system32inetsrvappcmd list apppools /in /xml | %windir%system32inetsrvappcmd set apppool /in /enable32BitAppOnWin64:true
The last one may make your head spin, but its nothing more than a chain of linked queries first finding the site, then finding all apps in the site, then finding apppools for those apps, and then setting a property on those apppools.
Back in my MSFT days, I got some flak from adding some of the "extra" features to AppCmd like piping and mask search, but I guess I knew it was going to pay off years later
You may want to read for AppCmd commands on Windows Azure:
I'll blog about a bunch more tricks we do for LeanSentry in a short bit, including very popular but hard to do things like configuring application warmup. Happy Azuring!