What is Serverless Computing? Exploring Azure Functions
There's a lot of confusing terms in the Cloud space. And that's not counting the term "Cloud." ;)
- IaaS (Infrastructure as a Services) - Virtual Machines and stuff on demand.
- PaaS (Platform as a Service) - You deploy your apps but try not to think about the Virtual Machines underneath. They exist, but we pretend they don't until forced.
- SaaS (Software as a Service) - Stuff like Office 365 and Gmail. You pay a subscription and you get email/whatever as a service. It Just Works.
"Serverless Computing" doesn't really mean there's no server. Serverless means there's no server you need to worry about. That might sound like PaaS, but it's higher level that than.
Serverless Computing is like this - Your code, a slider bar, and your credit card. You just have your function out there and it will scale as long as you can pay for it. It's as close to "cloudy" as The Cloud can get.
With Platform as a Service, you might make a Node or C# app, check it into Git, deploy it to a Web Site/Application, and then you've got an endpoint. You might scale it up (get more CPU/Memory/Disk) or out (have 1, 2, n instances of the Web App) but it's not seamless. It's totally cool, to be clear, but you're always aware of the servers.
New cloud systems like Amazon Lambda and Azure Functions have you upload some code and it's running seconds later. You can have continuous jobs, functions that run on a triggered event, or make Web APIs or Webhooks that are just a function with a URL.
I'm going to see how quickly I can make a Web API with Serverless Computing.
I'll go to http://functions.azure.com and make a new function. If you don't have an account you can sign up free.
You can make a function in JavaScript or C#.
Once you're into the Azure Function Editor, click "New Function" and you've got dozens of templates and code examples for things like:
- Find a face in an image and store the rectangle of where the face is.
- Run a function and comment on a GitHub issue when a GitHub webhook is triggered
- Update a storage blob when an HTTP Request comes in
- Load entities from a database or storage table
I figured I'd change the first example. It is a trigger that sees an image in storage, calls a cognitive services API to get the location of the face, then stores the data. I wanted to change it to:
- Take an image as input from an HTTP Post
- Draw a rectangle around the face
- Return the new image
You can do this work from Git/GitHub but for easy stuff I'm literally doing it all in the browser. Here's what it looks like.
I code and iterate and save and fail fast, fail often. Here's the starter code I based it on. Remember, that this is a starter function that runs on a triggered event, so note its Run()...I'm going to change this.
#r "Microsoft.WindowsAzure.Storage" #r "Newtonsoft.Json" using System.Net; using System.Net.Http; using System.Net.Http.Headers; using Newtonsoft.Json; using Microsoft.WindowsAzure.Storage.Table; using System.IO; public static async Task Run(Stream image, string name, IAsyncCollector<FaceRectangle> outTable, TraceWriter log) { var image = await req.Content.ReadAsStreamAsync(); string result = await CallVisionAPI(image); //STREAM log.Info(result); if (String.IsNullOrEmpty(result)) { return req.CreateResponse(HttpStatusCode.BadRequest); } ImageData imageData = JsonConvert.DeserializeObject<ImageData>(result); foreach (Face face in imageData.Faces) { var faceRectangle = face.FaceRectangle; faceRectangle.RowKey = Guid.NewGuid().ToString(); faceRectangle.PartitionKey = "Functions"; faceRectangle.ImageFile = name + ".jpg"; await outTable.AddAsync(faceRectangle); } return req.CreateResponse(HttpStatusCode.OK, "Nice Job"); } static async Task<string> CallVisionAPI(Stream image) { using (var client = new HttpClient()) { var content = new StreamContent(image); var url = "https://api.projectoxford.ai/vision/v1.0/analyze?visualFeatures=Faces"; client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", Environment.GetEnvironmentVariable("Vision_API_Subscription_Key")); content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); var httpResponse = await client.PostAsync(url, content); if (httpResponse.StatusCode == HttpStatusCode.OK){ return await httpResponse.Content.ReadAsStringAsync(); } } return null; } public class ImageData { public List<Face> Faces { get; set; } } public class Face { public int Age { get; set; } public string Gender { get; set; } public FaceRectangle FaceRectangle { get; set; } } public class FaceRectangle : TableEntity { public string ImageFile { get; set; } public int Left { get; set; } public int Top { get; set; } public int Width { get; set; } public int Height { get; set; } }
GOAL: I'll change this Run() and make this listen for an HTTP request that contains an image, read the image that's POSTed in (ya, I know, no validation), draw rectangle around detected faces, then return a new image.
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log) {
var image = await req.Content.ReadAsStreamAsync();
As for the body of this function, I'm 20% sure I'm using too many MemoryStreams but they are getting disposed so take this code as a initial proof of concept. However, I DO need at least the two I have. Regardless, happy to chat with those who know more, but it's more subtle than even I thought. That said, basically call out to the API, get back some face data that looks like this:
2016-08-26T23:59:26.741 {"requestId":"8be222ff-98cc-4019-8038-c22eeffa63ed","metadata":{"width":2808,"height":1872,"format":"Jpeg"},"faces":[{"age":41,"gender":"Male","faceRectangle":{"left":1059,"top":671,"width":466,"height":466}},{"age":41,"gender":"Male","faceRectangle":{"left":1916,"top":702,"width":448,"height":448}}]}
Then take that data and DRAW a Rectangle over the faces detected.
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log) { var image = await req.Content.ReadAsStreamAsync(); MemoryStream mem = new MemoryStream(); image.CopyTo(mem); //make a copy since one gets destroy in the other API. Lame, I know. image.Position = 0; mem.Position = 0; string result = await CallVisionAPI(image); log.Info(result); if (String.IsNullOrEmpty(result)) { return req.CreateResponse(HttpStatusCode.BadRequest); } ImageData imageData = JsonConvert.DeserializeObject<ImageData>(result); MemoryStream outputStream = new MemoryStream(); using(Image maybeFace = Image.FromStream(mem, true)) { using (Graphics g = Graphics.FromImage(maybeFace)) { Pen yellowPen = new Pen(Color.Yellow, 4); foreach (Face face in imageData.Faces) { var faceRectangle = face.FaceRectangle; g.DrawRectangle(yellowPen, faceRectangle.Left, faceRectangle.Top, faceRectangle.Width, faceRectangle.Height); } } maybeFace.Save(outputStream, ImageFormat.Jpeg); } var response = new HttpResponseMessage() { Content = new ByteArrayContent(outputStream.ToArray()), StatusCode = HttpStatusCode.OK, }; response.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg"); return response; }
I also added a reference to System. Drawing using this syntax at the top of the file and added a few namespaces with usings like System.Drawing and System.Drawing.Imaging. I also changed the input in the Integrate tab to "HTTP" as my input.
#r "System.Drawing
Now I go into Postman and POST an image to my new Azure Function endpoint. Here I uploaded a flattering picture of me and unflattering picture of The Oatmeal. He's pretty in real life just NOT HERE. ;)
So in just about 15 min with no idea and armed with just my browser, Postman (also my browser), Google/StackOverflow, and Azure Functions I've got a backend proof of concept.
Azure Functions supports Node.js, C#, F#, Python, PHP *and* Batch, Bash, and PowerShell, which really opens it up to basically anyone. You can use them for anything when you just want a function (or more) out there on the web. Send stuff to Slack, automate your house, update GitHub issues, act as a Webhook, etc. There's some great 3d party Azure Functions sample code in this GitHub repo as well. Inputs can be from basically anywhere and outputs can be basically anywhere. If those anywheres are also cloud services like Tables or Storage, you've got a "serverless backed" that is easy to scale.
I'm still learning, but I can see when I'd want a VM (total control) vs a Web App (near total control) vs a "Serverless" Azure Function (less control but I didn't need it anyway, just wanted a function in the cloud.)
Sponsor: Aspose makes programming APIs for working with files, like: DOC, XLS, PPT, PDF and countless more. Developers can use their products to create, convert, modify, or manage files in almost any way. Aspose is a good company and they offer solid products. Check them out, and download a free evaluation.
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter
So what .NET API level is supported? 4.5? 4.62? 2.0?
1) Add the following:
#r "System.Drawing"
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Microsoft.Azure.WebJobs.Host;
2) Change the inputs and outputs under the "Integrate" tab to "HTTP" (default names are fine)
If MS friends are reading this - Intellisense in the browser would go a long way to help this kind of debugging.
1. It uses .NET 4.6 - we hope to move to dotnet core later on.
2. This is based on WebJobs - in fact, you can find the host open source at a repo which still bares webjobs in the name. https://github.com/Azure/azure-webjobs-sdk-script
3. There is a local host for development. It's still fairly early in development, but our CLI provides a local instance - npm install -g azurefunctions
Please test in another App in the cloud though. Don't push straight to prod without testing on Azure. :)
Feel free to reach out to our team via twitter or ask questions on stack overflow, we try to stay on top of issues we see.
I have been testing MS Azure & Google Cloud at the same time for two different projects.
I have been using them for high traffic websites that require on-demand resources.
But this is something new to me. Interesting article.
Thanks
Tauseef Alam
Thanks for a really good example of how to use Functions!
Johan
Karlo: Yes, you can add Nuget references. See more information here.
James: You can absolutely make requests from your functions and consume external services. Similar to the way Scott, is consuming the Cognitive Services API in his example.
Onur: Glad you found that F# is supported. That support is being enhanced in the next release as we've been working closely with the F# team to ensure we have great support for it.
Chad: Yes. Access control is managed at the trigger level, since different triggers offer different mechanisms (e.g. HTTP triggers support request authentication, Storage Queues and Blobs using authenticated publishers, etc.)
From the article there is still a bunch of configuration needed (just as with web app on Azure) and as someone else mentioned there is also testing to consider.
I thought it would be totally free given the quotas. However, I got a notification that $0.01 had already been taken from my free allocation of $200 trial just a few hours later.
I looked into the details and found it was for an auto-created storage bucket. I figured "no big deal" I'll remove that and it'll be free, since my function is totally stateless.
Now, the multi-function app is totally broken. I get:
Error:
An error occurred when trying to create a controller of type 'FunctionController'. Make sure that the controller has a parameterless public constructor.
... when I attempt to even click on the app. I'm guessing now that the functions themselves are stored in that storage bucket, but it still let me remove the bucket and now it's totally broken.
I assume I'll have to destroy the app and re-create it, but I just wanted to warn others that it's not actually free even though "Functions" has a free quota. It requires Storage.
Most disappointing, both in personal-use pricing and in it letting me totally destroy my applications (I saved most of the code in a Gist thankfully, in case I care later).
Thanks.
I'm one of the PMs for Azure Functions.
You're right that we have a free grant on Dynamic Tier, but that Dynamic Tier does require Storage, so it will break when you remove it. We don't have warning on the Storage blade for removal because Storage isn't aware on what is using it, but we could probably have better warnings for you as part of our Quickstart/create process. I've created these bugs to track improving that experience:
- https://github.com/projectkudu/AzureFunctionsPortal/issues/517
- https://github.com/projectkudu/AzureFunctionsPortal/issues/516
You can use Functions in a "Free" App Service Plan, which doesn't require Storage (though we still create one by default), but it will pretty much only work with HTTP. Dynamic Tier will still require Storage, for the foreseeable future, by design. That does mean it's not totally free. I'll also follow up with our marketing/pricing material to make sure that is more clear: We have a free grant for our billing meters, but we have dependencies which aren't free.
Sorry for the confusion and some experience issues. Appreciate you reporting them to us so we can improve. :)
-Chris Anderson
Ian W: You can use some legacy Win32 code on Functions, but only if they aren't using APIs that are blocked by the underlying App Service application sandbox. For instance, GDI+ APIs can't be used. You can try uploading your .exes and see if it uses any of these.
Artyom K: Could you share more about why you don't think this would be a useful service beyond prototyping? Our goal is to enable real scenarios, but admittedly the portal tooling is not nearly as powerful as Visual Studio. :)
The lack of transparency over costs the impossibility to set a spendig limit is killing your efforts to make Azure a widely used service. Individual developers avoid Azure because of this, and if there aren't enough individual developers who use your services the enterprises will not have enough resources to hire so they will not use your services.
It isn't an issue only with Functions, I followed a link from an Azure IoT article few months ago, didn't actually connect any device, yet at the end of the month I was charged $700 USD on my credit card. I was shocked. And it wasn't even possible to tell from Azure Portal which esources were generating cost and which aren't, I had to work with Azure support two days until all unwanted services, storage and others were deleted.
Besides clear visibility and detailed reports a spending limit should also be enabled:
https://feedback.azure.com/forums/170030-billing/suggestions/3238796-spending-limit-or-maximum-cost-cap-for-azure
That's a cool example.
I followed the links and the Azure Functions Overview page states:
Choice of language - Write functions using C#, Node.js, Python, F#, PHP, batch, bash, Java, or any executable.
I use at least 4 of those languages, so I'm just asking out of curiosity:
1) I note that C++ and VB.Net aren't in the list yet. Are C# and F# considered the .NET languages of choice now?
2) It does state "Any executable" - does that mean a standalone.exe, or can you upload any supporting dlls as well?
Thanks
Diarmuid
I'm not familiar with the #r syntax in place of using. My google-fu wasn't strong enough to turn up any results. Anyone have a link that would help clarify?
Thanks!
-Nathan W.
Found this from a co-worker that explains it also:
https://github.com/scriptcs/scriptcs/wiki/Writing-a-script#referencing-assemblies
You can browse ipaddressdefinition.com for more information
http://news.softpedia.com/news/catastrophic-ddos-attack-pummels-linode-servers-over-the-weekend-507985.shtml
Maybe the Hanselman Effect could become a thing :)
Comments are closed.