Lucas Monastirsky
Sep 12 · 9 min read

In this step-by-step guide I will be showing you how easy and quick it is to use Azure Functions within Docker containers. You will learn how to install all necessary resources and build a simple REST API that delivers JSON responses via GET and POST requests. We will be doing so in C#, but Azure Functions also supports Node and F# (it also supports Python and PHP, but this is not recommended as the support for them is experimental). This is only one of the many, many things that you can do with Azure Functions, and at the end of the guide you will find links to guide you on what you can do next.


1. Introduction

If you’re already familiar with Azure Functions and Docker, you might want to go straight to the installation section of the guide. If you aren’t familiar with them, though, I’ll explain them briefly:

Azure Functions

Azure Functions is a serverless computing service hosted by Microsoft. This means that you can simply upload your project/code to the cloud, and let Azure take care of the infrastructure for you. It also scales automatically to fit your needs, meaning you only pay for what you use, instead of having to buy or rent servers that you might not actually need. Needless to say, Azure Functions can save you a lot of time and money. Serverless computing services are usually not used for full-projects though; They’re best utilized for hosting multiple specific, small tasks.

If you want to learn more about Azure Functions, you can read this article.

Docker and Containers

Docker is, basically, a tool for working with containers, which are, in layman’s terms, closed boxes where you can put a process, kind of like miniature virtual machines, but with only the necessary parts. These containers have all the necessary resources for the process to work, and they do not allow the process to access any files from outside the container. Why is this good? Because of consistency. A process in a container is self-sufficient, so if you send someone your container, you can rest assured that it will work in whatever system they have. The typical “well it works in my computer!” problem is no longer an issue, since the container already has all the necessary resources inside.


2. Installation

The first thing you need to install is Node.js. If you’re on Windows, here is a good guide on how to do so. If you’re on Ubuntu, you can follow this guide.

Once you have Node.js, you need to install Azure Functions Core Tools. If you’re on Windows, simply open your command line and run the following command:

npm install -g azure-functions-core-tools

If you’re on MacOS, you need to install Homebrew if you don’t have it already, and then run the following commands in your command line:

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

If you’re on Ubuntu, follow the instructions in this repository.

Once you’ve installed Core Tools on your computer, download and install .NET Core 2.X SDK.

After that, you just need to install Docker. Here are links for how to install it on Windows, MacOS, and Ubuntu.


3. Creating the Project

Once you’ve installed all the necessary resources, open your command line, and navigate to whatever directory you want to place your new project in. Then, run this command:

func init MyProjectName --docker

Replace ‘MyProjectName’ with whatever name you want for your project. The ‘docker’ argument means that a Dockerfile will be created for you. It basically tells Docker how to build your program’s image, from which it can build a container. You can learn more about the Dockerfile here.

This should show up after you’ve run the command:

Select a worker runtime: 
dotnet
node
python (preview)
powershell (preview)

With your arrow keys, select ‘dotnet’ for a C# project, and press enter. You can choose Node, if you want, but this guide will show C# code.

By default, Azure Functions will create your C# project as a .csproj, which you can use with Visual Studio or Visual Studio Code. You can still simply edit the function’s .cs file with any text editor you want, though. If you’d rather work with .csx, add the ‘csx’ argument, like this:

func init MyProjectName --docker --csx

Now, you need to create a function for your project. In your command line, navigate to the folder that Azure just created for you.

cd MyProjectName

Then, simply run the following command (add the csx argument if you did so in the previous step):

func new

This should show up:

Select a template:
QueueTrigger
HttpTrigger
BlobTrigger
TimerTrigger
DurableFunctionsOrchestration
SendGrid
EventHubTrigger
ServiceBusQueueTrigger
ServiceBusTopicTrigger
EventGridTrigger
CosmosDBTrigger
IotHubTrigger

Select ‘HttpTrigger’. This means the function will be able to receive GET and/or POST requests and deliver a response.

You will be asked to name your function. I named mine ‘Search’.

Select a template: Function name: Search

You should see this on your command line now:

The function "Search" was created successfully from the "HttpTrigger" template.

Your function should be ready now. Let’s try it out! Run the following command:

func start --build

After your function is done building, your command line will look something like this:

You can see your function there, with its url. Copy it into your browser. You might need to wait a minute for it to work. You should see “Please pass a name on the query string or in the request body”. This is the default behaviour for the function. You can play around with it by adding ?name=YourName to the end of the url, or by sending it a POST request with something like Postman. Now we can see the function’s code and start programming our API.

4. Coding Your Function

Open your project’s folder. If you want to work with Visual Studio, open MyProjectName.csproj with it, and from Visual Studio, open the file Search.cs

If you want to code your function with a simple text editor, just open Search.cs with said editor.

It should look something like this:

From the default code, we can learn a few things. The Run() function takes two arguments: an HttpRequest, and an ILogger.

The HttpRequest object will contain the GET and POST parameters, and the ILogger object allows us to output text to the commandline while we’re running our function locally. If you run your function and look at your command line, you’ll see the output of this line:

log.LogInformation("C# HTTP trigger function processed a request.");

The last part we’ll look at is the return:

Now we know that we can use OkObjectResult() to deliver a response with an Ok HTTP code, and BadRequestObjectResult to deliver a response with a Bad Request code. If you want to learn more about returning HTTP response codes, you can read this.

Before we start modifying the function, let’s simulate a database by creating a class, a builder to give us a list of objects of that class, and a method that queries that list by the object’s name parameter. I will be doing this with a Person class:

The list builder:

The query:

Now that we have our fake database, we make the function query it and return a JSON response. The default function already gets the name parameter from the GET request, and if there wasn’t such parameter, it looks for it in the POST request body.

So we just need to change the return so that it returns the queried list in JSON format, which is as simple as changing this:

new OkObjectResult($"Hello, {name}")

Into this:

new OkObjectResult(JsonConvert.SerializeObject(queryByName(name)))

The return statement should look like this:

And that’s it! You can save the changes and run the function just like you did before with the command:

func start --build

And your REST API should be working! Play around with giving it different name parameters, and you’ll see the JSON responses in your browser.


5. Building the Docker Image

Before we build the Docker image, we need to change the security level for our function. The default authorization allows us to connect to the function from the same computer that it’s being run on, but remember that containers alienate the function from our computer, so this won’t work once the function is running inside the container.

Changing this is simple, simply change this line in the function’s code:

To this:

AuthorizationLevel.Anonymous

It should look like this:

Of course, this is just for the purpose of this guide, because we’re not gonna get into the details of authorization here. If you want to learn about authorization in Azure Functions, you can check out this blog. For now, though, anonymous will do just fine.

Now, open your command line (if necessary, navigate to the project’s folder again), and run this command:

docker build -t myprojectname .

If you’re using Ubuntu, add ‘sudo’ before ‘docker’.

The ‘t’ argument lets you specify a tag for your image, so that you can recognize it. You can replace ‘myprojectname’ with whatever tag you want, it doesn’t need to be the same as your project’s name.

Don’t forget the dot at the end. This tells docker that you’re building the image in the current directory.

Once the image is done building, you can verify that it’s there by seeing all your docker images, with the following command:

docker images

Again, if you’re using Ubuntu, add ‘sudo’ before ‘docker’.

You should see the image you just built in the list:

Now, we can finally run our image and test it, with the following command:

docker run -p 8080:80 myprojectname

Once more, add ‘sudo’ if you’re using Ubuntu.

The ‘p’ argument lets you specify a port for your container to listen to.

Now, you can test your API just like you did before, with the url localhost:8080/api/Search (If you specified a different port, change it in the url. Change “Search” too if you chose a different name for your Azure Function.).


6. What’s Next?

That’s it! You’ve created a REST API that’s ready to be published to Azure’s serverless service.

You can follow this link to learn how to publish your function to the cloud if you have Visual Studio. If you want to publish your function without Visual Studio, you can follow this link.

If you want to improve your new project by connecting it to an actual database, follow this link to learn how to set up an Azure SQL Database. You can then follow this link to learn how to connect your function to the database.

If you want to learn more about Docker, I recommend learning about Docker Hub and how to upload your Docker image. You might also want to learn how to export your container.

You can check out my repository for this project if you want.


Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade