Microsoft ushered in a new era for .NET development with the launch of .NET Core. The early releases were, by all accounts, rough around the edges but still demonstrated that .NET was to be taken seriously in the cloud development space.
The .NET Core 2 release improved the usability of the development platform by increasing the API surface area and adding some spit and polish to the tooling. All that work by Microsoft has paid off in terms of adoption by not only Azure but AWS and Google as well.
In this article I look at the distinguishing features of each of the technologies that can host a .NET Core application across the big three cloud providers. Those techs are Virtual Machines, Serverless, Containers and Platform-as-a-Service. I also try to determine which is best if you’re starting a cloud migration from scratch.
(If you’re looking for the same comparison on the .NET Framework side of things, you can read all about it here [LINK].)
Virtual Machines: It’s a toss up.
There isn’t anything fancy about provisioning, monitoring and scaling a set of virtual machines. All three cloud providers have made it so easy that even someone without a technical background could do it. In a sense, they’ve slowed the adoption of other technologies like PaaS, containers, and serverless by making virtual machines so accessible to anyone.
.NET Core brings a new dimension to running an API or Worker on a virtual machine, and that’s the possibility of running them on Linux. One of the most interesting reasons to consider doing so from a business perspective is cost. Whilst it’s near impossible to accurately compare costs of similar machines across the big three providers, one thing that is obvious is that the same instance size on Linux is significantly cheaper than its Windows counterparts.
I’d give AWS a long and hard look if you’re considering Linux to run any type of workload, mainly due to its breadth of experience in providing these types of instances in the cloud. Similarly, if you’re planning on using Windows VMs, Azure’s expertise and deep-rooted connection with Microsoft give them the slight edge there. That isn’t to say that Google’s Compute instances aren’t up to snuff. They definitely are. But experience and depth of knowledge count for a lot and AWS are the kings of the cloud on Linux, and the same can be said about Azure and Windows.
Serverless: AWS, but the gap is closing.
I’m a huge serverless (and more particularly Lambda) fan. I’ve seen first hand how quickly you can go from idea to MVP to full-fledged product with it, all the while enabling massive scale with next to no tuning.
Being first to market allowed AWS to carve out a technical and market lead in the serverless space. Lambda functions are built using .NET Core 2 in Visual Studio with the AWS Toolkit. The templates make it simple to create and deploy a function (or entire Web API for that matter) in minutes. Of course a real application needs a more thorough CI/CD pipeline, such as VSTS, which has a series of extensions provided by AWS to facilitate deployments.
Azure Functions are based on the WebJobs SDK. While it’s recently been ported to .NET Core 2, what you’re really doing is writing .NET Standard 2.0 Functions. Using WebJobs does provide you some additional customizability but also adds a layer of confusion as to which APIs are and aren’t available.
Google Cloud Functions, while still in beta, works only with Node.js at the moment. Sadly that leaves them out of contention for this category. It’s unclear if or when they might support additional languages.
The execution models of Lambda and Functions are somewhat different. Lambda completely abstracts away execution details but dig a little and you’ll find that the underlying technology powering Lambda is containers. Azure Functions run on App Service instances, a Platform-as-a-Service that also lets you build Web apps and APIs (more on this later). That makes it possible to share unused cycles from other App Service applications instead of the pay-as-you-go model that you get with Lambda. It’s also possible to use a pay-as-you-go model for Functions.
The deciding factor between Lambda and Functions could be the types of triggers you’re expecting to use. Serverless is well suited to do background processing and one major difference between Lambda and Functions is that the latter supports triggering a function from a queue. This is a gap on the Lambda side. There are workarounds, and AWS recommend using SNS instead to do Publish/Subscribe. It’d still be nice if they supported triggering from a queue out of the box though.
Containers: Still up for grabs
The beauty of containers is that they run the same regardless of where they are hosted. That’s all well and good but it makes finding differentiating criteria among the big cloud providers that much more difficult.
The first step to choosing the cloud provider you plan on using to host your containers is to determine your orchestrator of preference. With that decision in mind the next step is to look at how well that orchestrator works on each cloud provider.
This can guide us to some conclusions. Kubernetes was built by Google and underpins their container engine. It’s fair to say that GCP is therefore likely to have a better integration with Kubernetes seeing as they developed the entire product line.
AWS’s newest container product, Fargate, could be the answer if you’re looking for a managed container service. Managed services are becoming increasingly popular and they make total sense with containers because of the complexity to operationalize them correctly for production use.
And then there’s the fact that while .NET Core can be run anywhere, Microsoft have a slight edge in making containers more usable for it seeing as they understand its needs better than anyone else. For that reason alone, I’d probably stick with Microsoft for the time being.
Platform As A Service: Another close call.
There’s some stiff competition in the PaaS space for .NET Core applications.
Azure has two technologies on offer. For simpler workloads, App Service fits the bill nicely while still providing all the features you’d expect from PaaS such as autoscaling, monitoring, easy deployment and maintenance. And for more advanced scenarios, there’s Service Fabric. Its additional customizability and the ability to run background workers make it a complete solution at the expense of simplicity.
Google’s Platform-as-a-Service is called App Engine. Everything in App Engine is built around HTTP, regardless of whether you’re building a web app, an API or a worker. You can also schedule work to run via Cron jobs or start a worker that consumes messages from a pub/sub notification. App Engine, much like Service Fabric, runs on containers internally. Its simplicity of use is refreshing when compared to Service Fabric.
Beanstalk, AWS’s entry into the PaaS space, can also be used to run .NET Core web apps and APIs. Unlike Google and Azure though, Beanstalk has no support for worker environments with .NET Core. This limitation is due to it running on Windows instances, so hopefully we’ll eventually be able to run it on Linux instances and get access to the full gamut of Beanstalk features. That doesn’t take away that it does do a nice job with web apps and APIs, so it should be in the running if you’re going to go down the PaaS route and only need those two features.
Will any of this change?
Definitely, if the past year is any indication. Most of the battles are so close that it’s impossible to say that a single provider is the definite leader in a technology. The investments in .NET Core that Microsoft, Google, and AWS are making in the containers and serverless space show a renewed interest in the .NET platform as a whole. It’s very exciting for anyone working in .NET these days and I’ll be keeping an eye on how it evolves in 2018. Expect an update to this post next year around this time to see how the landscape has changed.