DEV Community

Cover image for How YOU can create and manage Serverless functions using a CLI
Chris Noring for Microsoft Azure

Posted on

How YOU can create and manage Serverless functions using a CLI

Follow me on Twitter, happy to take your suggestions on topics or improvements /Chris

There are many ways to create Serverless functions with Azure Functions. We can use the Portal, VS Code but also the terminal and a Cli tool called func. We will focus on the latter in this article, so be prepared to go full terminal :)

In this article we will cover:

  • WHY, why do we want to use the CLI to manage our functions when we have a UI?
  • WHAT, what will this CLI tool allow me to do?
  • Demo, of course, we want to take our CLI tool for a spin and see how it works right, right?

Resources

Why a CLI

There are many reasons to why you would want to use a CLI.

Scripting, One of the more important reasons is probably scripting for usage in a CI/CD process.

Speed, Speed could be another factor, few things beat the speed of running a command in the terminal

IDE/Editor agnostic, We all have a favorite terminal we like to use. Sometimes what we want to do is possible to do through a UI in our editor of choice and sometimes it's not

What

Before we begin let's start by installing our CLI. This looks a bit different depending on your OS of choice.

Installing

What we need is something called azure-functions-core-tools. Below is the instructions for respective OS:

Mac

brew tap azure/functions 
brew install azure-functions-core-tools

Windows

npm i -g azure-functions-core-tools --unsafe-perm true

Linux

wget -q https://packages.microsoft.com/config/ubuntu/19.04/packages-microsoft-prod.deb sudo dpkg -i packages-microsoft-prod.deb

Everything installed? Good :)

Overview of func

Ok so we got this CLI tool installed called func. Run func --help in the terminal and let's try to gain an understanding of what it can do for us:

Ok, we got quite the long answer back so let's look at it page by page. Above it's listing what it can do for us generally like working with:

  • Azure, allows us to manage resources
  • Durable, this is a stateful Serverless offering that we won't look at now but in a later article
  • Extensions, this is about supporting different kinds of bindings, to support binding to e.g a Database we need to have an extension installed for that
  • Function, this is about support actions around functions like creating and running them
  • Host, how to run our functions locally
  • Kubernetes, heard of Kubernetes? No? It's what you can use to orchestrate containers. Still confused? It's ok, I got a 5 part series on Kubernetes here
  • Settings, we want to be able to manage settings, it could be connection strings to a database or some other keys we might need to run the app
  • Templates, when you scaffold a function you need to start by selecting how to trigger it, e.g what causes the function to be invoked in the first place. That could be a change to a Database or someone hitting a HTTP endpoint and so on.

Let's check out the other page we got from running func --help

We got four distinct actions:

  • start, by calling func start we will build and run the code
  • new, by calling func new we trigger a function creation process in which we are asked to for the template we want to use
  • init, by calling func init we trigger a process that allows us to create a Function App project, all functions needs to live inside of such a project
  • logs, calling this command means we will be abl to get logs from a running function so we can analyze what's going on

 Demo

So what do we want to achieve with our demo? Well, we want to:

  • Scaffold a project, this where we need to start. We will go through how to scaffold for different programming platforms
  • Scaffold a function, of course, we want to scaffold functions. This has a great wizard that kicks off.
  • Run the app, once we scaffolded everything, let's ensure we can run our app, like we are used to from VS Code
  • Deploy to Azure, using Azure CLI we will create the needed resources and end up deploying our Function app + functions to the Cloud

Scaffold a project

You can start a project with just func init NameOfProject but this will give you the default worker runtime, which is dotnet. So for that reason I recommend being explicit like so:

With the above command we func init MyNodeApp --worker-runtime dotnet it will create a .Net based project in the directory MyDotnetApp, e.g the name of our creates a directory with the same name.

Other possible values for --worker-runtime are dotnet, node, python, powershell.

Scaffold a function

Now that we have decided a --worker-runtime and any functions we scaffold under our app will follow suit and be created in the same runtime.

To create a function we kick off a wizard by typing func new, like so:

As you can see above we are asked for a template, thereafter a name for our function. This creates the expected Get.cs file. What happens here depends on runtime chosen. For JavaScript, you would get a directory Get with a index.js and function.json.

So what does my Get.cs look like?


using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace MyDotnetApp
{
    public static class Get
    {
        [FunctionName("Get")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            string name = req.Query["name"];

            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            dynamic data = JsonConvert.DeserializeObject(requestBody);
            name = name ?? data?.name;

            return name != null
                ? (ActionResult)new OkObjectResult($"Hello, {name}")
                : new BadRequestObjectResult("Please pass a name on the query string or in the request body");
        }
    }
}

That looks like what we are used to. Worth noting is that authorization is AuthorizationLevel.Function, so if we want that to be either Anonymous or Admin we can always change it afterward.

So is this the only way to scaffold a function? No, we can skip this wizard and use flags like so:

func new --template HttpTrigger --name Post

In a scripted scenario, you are more likely to use the latter version of creating a function.

 Run the app

Ok, so we got a function app and a function, let's see if we can run it. We start up our app with func start, this implicitly runs restore, that fetches needed packages and also build our app. We end up with the familiar:

and the functions work quite well:

Deploy to Azure

What about deployment? Right-click, like the browser?

Not quite, but still relatively simple.

What you need to do is:

  • Create a function app in your subscription, this step consists of 4 steps. It might sound like much but think that you are scripting this, then it's not so much. If you are actively authoring a function you are more likely to use VS Code where the Create + Publish step is literally just right-click
  • Publish, this is a simple command that deploys your app

Create a function App using CLI

We need to create the following things

  • Resource group, this is a logical grouping of your resources, think of this as a directory in the Cloud
  • Storage account, as soon as you need to place files somewhere in Azure they need to be tied to a storage account
  • Service plan, An App Service Plan consists of the underlying virtual machines that will host the Azure App Services. It has several tiers, from Free to Premium. The App Service Plan defines the region of the physical server where your app will be hosted on and the amount of storage, RAM, and CPU the physical servers will have
  • Create the actual function app, based on having created the above artifacts we are now ready to create the actual Serverless app

Before we start, ensure you are logged into Azure via the Azure CLI. Type az login, if you are unsure.

Let's start by setting up two variables:

storageName=mystorageaccount$RANDOM
functionAppName=myappsvcpfunc$RANDOM

the call to $RANDOM will ensure we get a unique name.

Create a resource group

az group create \
  --name myResourceGroup \
  --location westeurope

Create an azure storage account

az storage account create \
  --name $storageName \
  --location westeurope \
  --resource-group myResourceGroup \
  --sku Standard_LRS

Create an App Service plan

az appservice plan create \
  --name myappserviceplan \
  --resource-group myResourceGroup \
  --location westeurope

Create a Function App

az functionapp create \
  --name $functionAppName \
  --storage-account $storageName \
  --plan myappserviceplan \
  --resource-group myResourceGroup

Publish

func azure functionapp publish $functionAppName

After you've run the last command it ends up listing all the URLs for each of the functions in your app. Clicking one of the URL links should spin up a browser and lough and behold, it works :)

Summary

Ok, so we took a trip down to CLI country, no UI as far as the eye could see. The terminal option might not feel as smooth as VS Code or IDEs in general but it's mostly meant for scripting so that's what you need to keep in mind. Next time you need to set up a CI/CD pipeline and need to script the creation of an app and even deploy, remember func and func --help even.

Top comments (0)