Serverless in Context
Getting the Most From Azure Functions
*** A newer, updated version of this course is available here. ***
An Introduction to Azure Functions
Serverless Computing has emerged as a capable and low-friction means to execute custom logic in the public cloud. Whether you're using Amazon Lambda, Google Cloud Functions, or Azure Functions, you have a wide variety of target languages, ecosystem integrations, and deployment mechanisms to choose from. All this while leaving the heavy lifting of server provisioning and maintenance to the experts, which gives you plenty of time to focus on your differentiated application functionality.
In this "Introduction to Azure Functions" course, you’ll learn how to build Azure Function applications in the cloud. You'll discover the core feature set of Functions and see how to integrate with a variety of sibling Azure services. You'll explore Function topics like security, monitoring, deployment, and testing best practices. You'll also learn about ideal Functions use cases and the pricing model. Finally, you'll learn about how we've arrived at the serverless computing model, and where serverless is likely to go in the future. By the end of this course, you’ll have a solid foundation to continue exploring Functions on your own, and incorporating Azure Functions capability into your work.
An Introduction to Azure Functions: What You'll Learn
|Lecture||What you'll learn|
|Intro||What to expect from this course|
|Serverless Computing In Context||Understanding what serverless computing is, and how we got here|
|Core Features||A high-level overview of what Azure Functions is, and its basic capabilities|
|Creating Your First Function||A demo of creating your first function in the Azure portal|
|Security||A review of security features in Azure Functions|
|Using API Key Management||A demo of configuring an Azure Function to require API key use|
|HTTP Proxies||A discussion of lightweight HTTP Proxy support|
|Proxying Azure Blob Storage||A demo of using Functions' HTTP Proxy support to front Azure blob storage|
|Triggers and Bindings||Event-based triggering of functions and declarative binding of inputs and outputs|
|Triggering on Queues and Binding to DocumentDB||A demo of Triggering with Azure Queues and Binding Function Output to DocumentDB|
|Testing and Debugging||Tools and techniques for working with Functions during the development cycle|
|Deployment||Options for deploying Azure Function apps into production|
|Deploying From a Local Git Repo||A demo of deploying a complete Azure Function app to the cloud, from a local Git repository|
|Monitoring||Tools for monitoring Azure Functions during dev, test, and release|
|Use Cases||A discussion of ideal use cases for serverless compute and Azure Functions|
|Pricing||A review of how Functions are priced, and a demo of determining price using the Azure Pricing Calculator|
|Serverless in the Future||A short discussion on the future of serverless in the cloud|
|Summary||Course wrap up|
If you have thoughts or suggestions for this course, please contact Cloud Academy at firstname.lastname@example.org.
Okay, so let's take a look at how to configure a local Git repository for deployment into an Azure function app.
So here in the portal I've created a new Azure function app, it's empty, doesn't have any functions in it yet. So I'm going to create the artifacts needed for having a single function inside of this app. I'm gonna create those artifacts manually on my local machine in a text editor, and then we'll deploy and upload those artifacts to this function app, so that we can see, kind of how this works from the standpoint of creating an app outside of the portal itself.
So let me switch over to a text editor, I'll Use Visual Studio Code, but certainly you can use any text editor you like. In order to create a function app, you need a couple of things. The most basic thing you need at the root of the app is a file called host.json. This is a JSON file that contains some optional attributes, configuration for your function application. By default you actually don't really need anything in here, so I'm just going to leave it as an empty JSON document, but there is some documentation for adding, kind of, additional optional attributes if you need them. Each of the functions in your function app will live in its own top-level folder, the name of the folder will be the name of the function, so I'm going to create a folder called Reverse since I'm going to create a function in C# which will accept an input string in an HTTP request body, reverse that string, and then send it back as part of the response. So for each function we need a couple of things, the first thing we need is a function.json document, and this will contain configuration for things like input and output bindings, and I'll configure those in just a moment. The other thing that we need, of course, is our run.csx file. See, now run.csx is specific to C# and .NET support in Azure functions. If you were going to use, say the Node.js or Java, or PHP support, or you know, some of the other languages and technologies supported, then you might need slightly different artifacts for your function, and all of that stuff is well-documented in the Azure documentation.
So let's switch back to function.json, and again, what we're configuring in here are the input and output bindings for the most part. There's a handful of other things as well, but mostly it's the input and output bindings for the function. So because this is going to be an HTTP-triggered function, I need to configure the HTTP inputs and outputs for my function. So we start by creating a top-level bindings attribute, which is an array of bindings. So I'll create my first one as the input. First thing that we're required to have, there are some optional attributes in here, but I'll give you, just kind of the bare bones attributes that you need. We have to specify the authentication level, and this is where I specify whether I require clients to pass in a valid API key, or maybe I allowed them to call anonymously. And so in my case, just for these purposes, I'm going to use anonymous here. I'll need the name of the binding, which also corresponds to the name of the input argument that will be passed in to my function, and this will correspond to the HTTP input request, or request object, and so I'll just use something like req. We need a type which corresponds to, in my case, httpTrigger, and the last thing we need is a direction, just to specify that this is input, so we'll say in, all right? And now we'll specify our output binding. First thing we'll need is a name, and in my case I'm going to use a special syntax, $return, which indicates that the output binding for my function should be, it should bind to the output of the function itself. If we wanted to we could use output arguments, like out arguments in C#, but I'm not going to use that here, I just prefer to use the output of the function. So type would be http, oops, and then last will be the direction, and in this case, of course, it is out. All right, the only other thing we really need in here is to specify that our function is not in fact disabled, so we'll specify that here as well.
Okay, so I think that's all we need for our function.json, so now let's switch gears and we'll write up our code. We'll bring in a couple of namespaces, see, System.Threading.Tasks. Okay, so for my static function we'll make it asynchronous, and of course we'll return an HttpResponseMessage, and we will accept an HttpRequestMessage. This is kind of a standard pattern that you'll see in C# or .NET flavored Azure functions, and of course we want the name of our input argument to be req, since that's what we specified in our binding. Okay, so all we're really going to do here, or all our function is really expecting is that we're going to pass, a string is going to be passed in as the request body, and we're just going to take that string, read it, reverse it, and then send it back as the response. So we don't even need any JSON here or anything like that, we're just looking for raw text in the body. So to get that we can say, actually, we can just say var data equals, we'll await request Content.Read, oops, AsStringAsync Okay, so that will give us the body of the request as a string, to reverse it is easy enough, we just say new stringReverseToArray). Yep, that looks right. Okay, so now we have our reverse string, and we just need to return it in the body. So to do that we say req.CreateResponse, and we'll return 200, or OK, and we just return reverse as the body.
All right, I think that looks right, so I think we've got everything we need for our code. Okay, so the next thing we need to do is we need to create a local Git repository, so if we look real quick at the folder that contains this code, we can see that our host.json and then our inside of our Reverse folder we have a couple of artifacts, again, that correspond to our function configuration for our bindings as well as the actual code. But again, we need to create, we need to initialize a Git repository here, so let's do that first by saying git init, and then git add -A to add all the files, and then git commit -m "first commit" as our message, okay.
So we've added our three files to our repository, so they're fully committed, but now we need to push them up to our Azure function app up in the cloud. So to do that, it's actually fairly straightforward, let's switch back to the portal for a second, and again, because function apps are Azure App Service-based applications, they're configured for deployment, just like any other Azure App Service-based service, like Web Apps or API Apps. So we'll click on Platform features and go to Deployment options, and we'll click Setup and specify Local Git Repository... And I think that's all we need, yes, very good.
Okay, so we've already specified, occasionally if it's the first time you specified a deployment scenario, or deployment option in any of your apps in your subscription, you may have to create a username and a password which is used to authenticate deployments. In this case I've already done that, so I wasn't prompted to do that, but once you've set that up, in either case it's quite easy, once you've set that up, if you go back to Properties for your application, you'll see that there's a URL here for Git, and that's the URL that we wanna use to deploy against, and so I'm going to copy that, and then I'll switch back to PowerShell, and what I need to do is I need to add my remote Git repository up in the cloud for my function app, I need to add that as a remote reference in my Git shell here. So to do that we use the git remote command, we'll say git remote add azurefuncapp, I think we'll use two, and copy that, and now we should be able to say, so we've added the reference, git push azurefuncapp2, and master, and so what this does is it, and now we're going to push our committed changes that are in our local repository here in the master branch, we're going to push those to our azure function app up in the cloud, against that URL that we just configured. So I'll say go, so I need to specify my credentials here, so my user that I created previously, this, as long as I get the password correct, then we should push our source, our code up into the cloud. And yes, it looks like it's going to work, take just a second.
All right, looks like we had a successful deployment. So if I switch, go back to the cloud and refresh my function app... Then we should see a new function, which we do, which is Reverse. We can see our code, and so let's test it real quick. Say hello world!, run this, and sure enough, we see our output is reversed, so our function has run correctly and furthermore, we can look down at our log and we can see that it started, and then completed successfully.
About the Author
Josh Lane is a Microsoft Azure MVP and Azure Trainer and Researcher at Cloud Academy. He’s spent almost twenty years architecting and building enterprise software for companies around the world, in industries as diverse as financial services, insurance, energy, education, and telecom. He loves the challenges that come with designing, building, and running software at scale. Away from the keyboard you'll find him crashing his mountain bike, drumming quasi-rythmically, spending time outdoors with his wife and daughters, or drinking good beer with good friends.