As we keep seeing the same questions on Twitter (or elsewhere) regarding how to run F# applications on Azure, someone suggested to me that I write a post that outlines what your options are, and when and where you should use one service or the other.
.NET on Azure
Azure has always had a good “developer-focused” story for deploying .NET code. Unlike, say, Amazon Web Services (which started with a VM-first story and only more recently has started to offer higher-level abstractions), Azure has always been about offering the .NET developer ways to run your code in a way that are abstracted from the VM. In the early days of Azure, there was really only one option for hosting code (and zero options for running VMs), but as the number of Azure services offered grows at an incredible rate, there are now a number of different options available out-of-the-box in Azure. So, here’s a brief outline of some of the compute options that you have in Azure currently.
Disclaimer: If you’re an Azure boffin and notice some simplifications in this posting – it’s by design🙂 But please let me know if you notice something that’s completely wrong!
Cloud Services were as far as I’m aware the first platform service offering on Azure. You write your .NET code, you wrap it in a “cloud service”, and push it into Azure. Azure will handle provisioning of a VM for you, deploy your code onto it, and provide you with a load-balancer from which you can expose specific ports to your application as required. Alternatively, you can use e.g. some of the Azure messaging mechanisms such as Queues or Service Bus for sending commands to your worker role.
The process of wrapping your application in a Cloud Service basically involves bundling up your application into a zip file which contains the application files plus metadata about the service e.g. the VM size that you wish to run on, how many instances you want to run, the name of the service etc. etc.
Once your code is running, you can scale out the service to a number of “instances” of that service (aka “role”) by dragging a slider within the Azure portal, or use an auto-scaler which scales based on a number of metrics e.g. CPU utilisation.
Of course, Visual Studio has a number of templates included out of the box for creating such projects, including (which might surprise some people) an F# one. The only issue is that FSharp.Core isn’t included on Azure VMs by default, so you’ll need to ensure that it gets included in the output of your code (either by setting CopyLocal to True, or using the FSharp.Core nuget package).
The good thing about Cloud Services is that they’re very flexible – you can run any arbitrary .NET code (or non .NET) on them, as they essentially run in a similar manner to Windows Services – you get a number of events such as when the service is spawned, when it shuts down, if there’s a change to the configuration etc. You also get an API for configuration settings and even a distributed cache service across all instances of a role (although my understanding is that this service is being deprecated in the next 12 months).
However, Cloud Services are starting to show their age – there’s no support for e.g. direct integration with GitHub or other source control mechanisms. Instead, you need to package up code into the “.cspkg” format and deploy – which can take quite a while (minutes rather than seconds). Furthermore, there’s not much flexibility in terms of deployment – you write your code, you deploy it, and it maps to a VM. There’s no scope for multi-tenanting multiple services on a VM unless you manually do this yourself within the context of the Cloud Service at the code level, and configuration is a little bit of a pain compared to some of the other options out there.
F# and Cloud Services
Use Cloud Services for any F# applications you want to use – think of Cloud Services as distributed, replicated Windows Services. As an example, the MBrace Azure project runs on Cloud Services. Just note, that because they’re so flexible, you might have to do some plumbing to fit a Cloud Service to your specific needs (this isn’t just in F#) such as opening ports or the like, and there’s no specific Cloud Service APIs to connect to other Azure services.
Web Apps (formerly Azure Websites) were originally designed in order to simplify the use case for hosting ASP .NET applications in Azure as opposed to using Cloud Services, responding to HTTP traffic over port 80. As such, there’s out-of-the-box support for hosting any ASP .NET application in IIS directly from a source code repository e.g. GitHub; in addition, you can use the WebDeploy mechanism and tooling built into Visual Studio, plus there’s FTP support. Web Apps also come with the Kudu scripting language / tooling which is a kind of batch scripting set of commands for things like deployment-time file diffs. WebApps also support eight “deployment slots” that can host multiple versions of your website. So you can deploy to a number of “slots”, and hot-swap the “live” one in and out with basically instant results.
But, Web Apps are written at a higher level of abstraction than, say, Cloud Services – think of it as “IIS as a service” rather than just “code as a service”. This is what they’re designed for, and everything about them, from all the examples you see on the Azure website to the out-of-the-box reports and metrics in the portal, shows that they are geared up for HTTP-enabled applications. There are actually some good examples of using F# within ASP .NET – either directly using some of the third-party Visual Studio project templates etc., or using an IIS module that allows you to redirect all HTTP requests to any arbitrary executable – you can use such a mechanism to e.g. run Suave on Azure websites.
Of course, there’s nothing to stop you writing an application that ignores HTTP traffic and communicates through e.g. Azure Queues or whatnot, but you’d probably be better off using Cloud Services for something like that. As a “get out” for the HTTP route, you can also make use of “Web Jobs”, which are arbitrary executables that run within the context of a Web App, and can be set up to run or a schedule, continuously, or whenever e.g. a message gets dropped onto a storage queue. So imagine an e-commerce website where search results are displayed based on a batch-generated set of read-only database results or similar. You can use a web job that runs every n minutes or whenever some data changes to regenerate the table. This all runs within the context of the “website”, on the same VM. So if you want to scale the web job, you also have scale up website at the same time.
Web Apps are a great option for running applications that are geared up towards serving HTTP requests, particularly if you’re running an ASP .NET application over IIS. There are also some options for running other types of application e.g. batch processes within the context of the website. You can also run them for less money than Cloud Services, as the cheaper options allow for hosting multiple web apps within a single physical VM. So whilst Wep Apps lack the flexibility of Cloud Services e.g. you don’t get the same choice of VM sizes and run within the framework of IIS, they’re a much more modern option, with better support throughout Azure, and you should consider this where possible. There’s also much better support on the newer portal for Websites, and features like authentication with a number of providers e.g. Twitter, AD, Google etc. are included as part of the service for free.
F# and Web Apps
Use Web Apps for any application that is primarily HTTP-facing. You have several options for running F# within a Web App: –
- Create a C# web project as a thin e.g. MVC veneer and delegate calls to your F# code.
- Create an F# web project (either hand rolled or using one of the third-party templates available) and use something like Web API through the full ASP .NET stack or via OWIN / Katana. I believe that there’s also a full MVC F# template out there as well.
- Deploy an alternative application that can respond to HTTP traffic e.g. Suave, and use a custom module in IIS to route traffic through that. There’s a working solution for this within my GitHub repo.
As Cloud Services have aged, and containerised solutions have become more and more popular e.g. Docker, Microsoft have looked to create a more modern Azure service for hosting your code. Service Fabric allows you to host any executable (.NET or not) – so in this respect it’s somewhat like a Cloud Service. However, unlike a Cloud Service, a Service Fabric cluster is made of a number of nodes, on which you can host a number of services. In Microsoft’s mind, this allows you to create a whole host of micro-services hosted on your SF cluster. Each service within an SF cluster will be replicated across the nodes of the cluster – you can shape this behaviour with a reasonable level of control e.g. singleton services / n instances / maximum i.e. = cluster size. If a node goes down another one will spin up automatically and rehydrate its state, and you can also dynamically resize a cluster to introduce new nodes as required.
In addition to the usual Azure services that you may want to connect to, you can also use a number of SF-specific services that are hosted and run within the context of your cluster. These are services to allow sharing data in a consistent manner, and messaging across services in the cluster. These include creating .NET collections that work in a consistent, transactional manner across the cluster (sort of like the Concurrent collections in .NET but distributed across nodes rather than threads). So if you can imagine a micro-service which needs to maintain some state, rather than resorting to a database you could simply use an e.g. out-of-the-box distributed list.
Whilst Service Fabric is a relatively new public service offering on Azure, it’s actually been used internally by Microsoft for a number of services for a while one – so it’s a tried and tested technology.
It’s worth pointing out that in addition to the “host any raw executable” model, Service Fabric comes with an Actor model loosely based on the Orleans model. It’s not exactly the same, but a fairly close fit. But don’t think that Service Fabric is an actor service – it’s a much more flexible container model that happens to come with an actor model.
F# and Service Fabric
It’s important to know that out of the box, there is zero tooling support for Service Fabric with F#. There are no project templates, and no automated tooling for updating the myriad of XML configuration files or Powershell deployment tools that are required for Service Fabric. I’ve documented on this blog the steps that are (or were – that post is a little old now) required to get SF up and running with F# in terms of the project structure and tooling, and it is possible. I do wonder if there’s a more “lightweight” way to go about it though i.e. just deploy an executable with a lightweight project shell that hosts that exe, which would be decoupled from the SF project fluff. Currently the story that’s told by Visual Studio and Microsoft in terms of the configuration that’s required seems a bit of a backwards step to me.
Having said all that – once it’s up and running, Service Fabric offers a great story in terms of features for hosting services. It’s more powerful than Cloud Services, with out-of-the-box micro-service messaging and both stateless and stateful services that can replicate and scale automatically, as well as multi-tenanting services across single nodes.
If you’re think of hosting non-web facing code – whether micro services working together or arbitrary disconnected services – Service Fabric is a good choice. But it’s a more heavyweight option than e.g. Cloud Services in the sense that it contains a cluster of nodes (i.e. VMs) designed for hosting multiple services. It might be overkill to use it for a single service.
Azure offers a number of great developer-facing options for hosting F# applications, whether web-facing APIs or back-end services that receive requests via e.g. queues. There are also other compute options that I’ve not touched on here (such as Azure Batch), and more features coming all the time – so it’s definitely worth trying out to see how it can open up some new possibilities for your specific needs.