Sunday, August 29, 2010

Umbraco CMS - complete install on Windows Azure (the Microsoft cloud)

We use the Umbraco CMS a lot at work - it's widely regarded as one of (if not the) best CMSs out there in the .NET world. We've also done quite a bit of R&D work on Microsoft Azure cloud offering and this blog post shares a bit of that knowledge (all of the other guides out there appear to focus on getting the Umbraco database running on SQL Azure, but not how to get the Umbraco server-side application itself up and running on Azure). The cool thing is that Umbraco comes up quite nicely on Azure, with only config changes needed (no code changes).

So, first let's review the toolset / platforms I used:

* Umbraco 4.5.2, built for .NET 3.5
* Latest Windows Azure Guest OS (1.5 - Release 201006-01)
* Visual Studio 2010 Professional
* SQL Express 2008 Management Studio
* .NET 3.5 sp1


Step one is simply to get Umbraco running happily in VS 2010 as a regular ASP.NET project. The steps to achieve this are well documented here. Test your work by firing up Umbraco locally, accessing the admin console and generating a bit of content (XSLTs / Macros / Documents etc.) before progressing further. (The key to working efficiently with Azure is to always have a working case to fall back on, instead of wondering what bit of your project is not cloud-friendly).

Then use these steps to make your Umbraco project "Azure-aware" . Again, test your installation by deploying to the Azure Dev Compute and Storage Fabric on your local machine and testing that Umbraco works as it should before going to production. The Azure Dev environment is by no means perfect (see below) or a true synonym for Azure Production, but it's a good check nonetheless.

Now we need to use the SQL Azure Migration Wizard tool to migrate the Umbraco SQL Express database. I used v3.3.6 (which worked fine with SQL Express contrary to some of the comments on the site) to convert the Umbraco database to its SQL Azure equivalent - the only thing the migration tool has to change is add a clustered index on one of the tables (dbo.umbracoUserLogins) as follows - everything else migrates over to SQL Azure easily:



CREATE CLUSTERED INDEX [ci_azure_fixup_dbo_umbracoUserLogins] ON [dbo].[umbracoUserLogins]
(
[userID]
)WITH (IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF)
GO

Then create a new database in SQL Azure and re-play the script generated by AzureMW into it to create the db schema and standing data that Umbraco expects. To connect to it, you'll replace a line like this in the Umbraco web.config:

<add key="umbracoDbDSN" value="server=.\SQLExpress;database=umbraco452;user id=xxx;password=xxx" />


with a line like this:

<add key="umbracoDbDSN" value="server=tcp:<<youraccountname>>.database.windows.net;database=umbraco;user id=<<youruser>>@<<youraccount>>;password=<<yourpassword>>" />

So we now have the Umbraco database running in SQL Azure, and the Umbraco codebase itself wrapped using an Azure WebRole and deployed to Azure as a package. If we do this using the Visual Studio tool set, we get:

19:27:18 - Preparing...
19:27:19 - Connecting...
19:27:19 - Uploading...
19:29:48 - Creating...
19:31:12 - Starting...
19:31:52 - Initializing...
19:31:52 - Instance 0 of role umbraco452_net35 is initializing
19:38:35 - Instance 0 of role umbraco452_net35 is busy
19:40:15 - Instance 0 of role umbraco452_net35 is ready
19:40:16 - Complete.

Note the total time taken - Azure is deploying a new VM image for you when it does this, it's not just deploying a web app to IIS, so the time taken is always ~ 13 minutes, give or take. I wish it was quicker..



Final comments

If you deploy and it takes longer than ~13 minutes, then double check the common Azure gotchas. In my experience they are:

1. Missing assemblies in production - so your project runs fine on the Dev Fabric and just hangs in Production on deploy - for Umbraco you need to make sure that Copy Local is set to true for cms.dll, businesslogic.dll and of course umbraco.dll so that they get packaged up.

2. Forgetting to change the default value of DiagnosticsConnectionString in ServiceConfiguration.cscfg (by default it wants to persist to local storage which is inaccessible in production - you'll need to use an Azure storage service and update the connection string to match, e.g. your ServiceConfiguration.cscfg should look something like this:

<?xml version="1.0"?>
<ServiceConfiguration serviceName="UmbracoCloudService" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration">
<Role name="umbraco452_net35">
<Instances count="1" />
<ConfigurationSettings>
<Setting name="DiagnosticsConnectionString" value="DefaultEndpointsProtocol=https;AccountName=travelinkce;AccountKey=youraccountkey/>
</ConfigurationSettings>
</Role>
</ServiceConfiguration>


You also need to run Umbraco in full-trust mode, otherwise you will get a security exception when Umbraco tries to read files that are not inside its own "local store" as defined by the .NET CAS (Code Access Security) sub system running on the production Azure VM. In other words, you need the enableNativeCodeExecution property set to true in your ServiceDefinition.csdef like so:

<?xml version="1.0" encoding="utf-8"?>

<ServiceDefinition name="UmbracoCloudService" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
  <WebRole name="umbraco452_net35" enableNativeCodeExecution="true">
    <InputEndpoints>
      <InputEndpoint name="HttpIn" protocol="http" port="80" />
    </InputEndpoints>
    <ConfigurationSettings>
      <Setting name="DiagnosticsConnectionString" />
    </ConfigurationSettings>
  </WebRole>
</ServiceDefinition>



The Azure development tools (Fabric etc.) are quite immature in my opinion - very slow to start up (circa one minute) and simply crash when you've done something wrong rather than give a meaningful error message and then exit (for example, when trying to access a local SQL Server Express database (which is wrong - fair enough), the loadbalancer simply crashed with a System.Net.Sockets.SocketException{"An existing connection was forcibly closed by the remote host"}. I have the same criticism of the Azure production system - do a search to see how many people spin their wheels waiting for their roles to deploy with no feedback as to what is going / has gone wrong. Azure badly needs more dev-friendly logging output.

I couldn't get the .NET 4.0 build of Umbraco to work (and it should, .NET 4.0 is now supported on Azure). The problem appears to lie in missing sections in the machine.config file on my Azure machine that I haven't had the time or inclination to dig into yet.

You'll also find that the following directories do not get packaged up into your Azure deployment package by default: xslt, css, scripts, masterpages. To get around this quickly, I just put an empty file in each directory to force their inclusion in the build. If these directories are missing, you will be unable to create content in Umbraco.


Exercises for the reader

* Convert the default InProc session state used by Umbraco to SQLServer mode (otherwise you will have a problem once you scale out beyond one instance on Azure). Starting point is this article - http://blogs.msdn.com/b/sqlazure/archive/2010/08/04/10046103.aspx, but google for errata to the script - the original script supplied does not work out of the box.

* Use an Azure XDrive or similar to store content in one place and cluster Umbraco.

8 comments:

John Nicholas said...

I'm trying to get Umbraco running in Azure and found your post very helpful. I can login to the backend no problem and it appears to be running correctly. My last hurdle is being able to edit the css, scripts and xslt files. If I try to create a new one or edit anything in there I get a permissions error. I'm assuming I'm missing something it the DiagnosticsConnectionString section. I do have the enableNativeCodeExecution set. Any tips or advice?

Humphrey Sheil said...

Hi John

You didn't post the exception you got but I'd guess that you aren't shipping the necessary dirs in your Azure package for Umbraco to find, i.e. the step I document in the post as follows: "You'll also find that the following directories do not get packaged up into your Azure deployment package by default: xslt, css, scripts, masterpages. To get around this quickly, I just put an empty file in each directory to force their inclusion in the build. If these directories are missing, you will be unable to create content in Umbraco". Hope this helps.

Humphrey

John Nicholas said...

This includes editing files that are already there. For example I had jquery already in the scripts folder. I can open it in umbraco's editor but when I try to save a change it puts up the bubble that says"File not saved. file could not be saved. Please check file permissions" If I try to create a new file (a stylesheet for example) it says "File not saved. file could not be saved. Please check file permissions"

Are there any steps besides setting the DiagnosticsConnectionString to point to Azure storage? I feel like I must be really close but without any more feedback than the above errors I don't know where to look

Ricardo Fiel said...

Nice post.
Did you have any problems with writing files (umbraco.config, media, etc..) on azure?
Apparently, instead of writing files to the web app path, one should use Azure storage for that.
What was your approach?

Thanks

john said...

I've had no luck getting this to run at all. If it wasn't for this post I'd be sure that Umbraco and Azure aren't compatible at all. I end up with either a running install where no files can be edited or the whole thing just stalls and never launches. Combined with Azure's long waits for any steps and useless messages like "Busy" I really regret using it. I'm also afraid that even if I get it to run it will be impossible to add custom controls or update it in the future.

Humphrey Sheil said...

Hi Ricardo

I simply gave Umbraco full trust permissions so that it could write files in their default locations. The point about separating out content from the web app path to separate storage is a good one and that's what I would do for large production sites.

Humphrey

Humphrey Sheil said...

Hi John

Sorry you're having trouble with it. All I can advise is to stick with it - Umbraco does really run quite well under Azure once it's up and running.

Humphrey

Owen Hope said...

Hi Humphrey,

Great Guide! It got me up and going, however I am still struggling to get the Umbraco features to work very much the same as John. I've copied everything exactly as you have but I can't create templates I get an error stating:

Can't find E:/appRoot/masterpages/"templatename".master

And if i try to alter and save any CSS file or js file it says i do not have proper file permissions.

I can however create document types...

Any ideas?