Azure Function App and Docker on Azure made easy in 12 steps
Tags: azure, azurefunctionapp, docker, dockeronazure
Published: 2019-12-06 23:20:10

---
title: Azure Function App and Docker on Azure made easy in 12 steps
published: true
description: 
tags: Azure, Azure Function App, Docker, Docker on Azure
---

### Abstract
This article shows how to write an Azure Function App on your development computer, aka local machine and deploy it to Docker on Azure. If you're new but want to learn about Azure Function App, Docker containers on Azure, Azure Container Registries etc, and how to use all of them together, you could be overwhelmed with plenty of but disparate Azure documentation (not to mention documentation on Docker website itself), and they won't be so clear especially if you're trying to see how they all fit together. On the hand, this article hopefully provides you with the quickest, step-by-step approach. You will go from zero to deployment in x minutes. Once you see how the Function App finally runs on Azure cloud after a few steps, we will go back to the development computer, makes some changes as we often have to do in real world situations, go through all the steps again, and see the changes reflected on Azure.    

### Requirements
1. **You must already have an Azure Subscription**
2. Your development (dev) computer must run at least Windows 10 Pro, or latest MacOS or Ubuntu Linux (I have not tried)

### Assumptions:
1. We will write the sample Azure Function App in `C#/.Net`
2. The sample Azure Function App is `HttpTriggered`.
3. I will show everything using command line interface (CLI). But there's always an UI alternative. 
4. Naming convention: You will find I'm using name like `kleSampleResourceGroup` in the instructions of this article. Such name like `kleSampleResourceGroup` can be broken in 3 parts. `kle` identifies the organization. `Sample` is the name of this project. `ResourceGroup` identifies the thing that we are naming.

### Step 1: Installation
We have to install a few software programs on the dev computer. However, these installations are extremely simple. Just follow the links listed.

**NodeJS** https://nodejs.org/download/release/
**Docker** https://www.docker.com/products/docker-desktop (Docker requires you to signup)
**Azure Function Core Tools** Once `NodeJS` and `npm` have been installed, you can run the following command
`% npm install -g azure-functions-core-tools@latest`
**.NET Core** https://dotnet.microsoft.com/download/dotnet-core (Note: I have not tried with .Net Core 3.+)
**Azure CLI** https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest 

### Step 2: Create a new Azure Function App on the dev computer
On your terminal, type
```
% mkdir kleSampleFuncApp
% cd kleSampleFuncApp
% func init . --docker
```
The last command will prompt us to select a worker runtime. Four choices are presented. As mentioned above, we will choose `dotnet`. Consequently, this command will generate the following files in the directory: `Dockerfile`, `host.json`, `kleSampleFuncApp.csproj` and `local.settings.json`

Next, in the newly created Function App, we will create a new Function using the HttpTriggered template. A Function App can have multiple Functions. Each Function in this context represents an URL endpoint.
```
% func new
```
This command will prompt us to pick a Function App template. Choose `HttpTrigger`. It will then prompt for a function name, enter `kleSampleFunc`. This will generate a file named `kleSampleFunc.cs`. Open up that file, search for `AuthorizationLevel.Function` and change it to `AuthorizationLevel.Anonymous`

### Step 3: Build and run the Function App on the dev computer
```
% func start --build
```
This command will build and start the Function App. We will see that the application is listening on the default port 7071, can handle both GET and POST requests and the entire URL endpoint is `http://localhost:7071/api/kleSampleFunc`

If you're on Mac or Linux, you can use `curl` to quickly test. Alternatively, you can use `Postman` or any other similar tools.
```
% curl -X POST http://localhost:7071/api/kleSampleFunc -d '{"name":"kevin"}' -H "Content-Type: application/json"
```

### Step 4: Create a Docker image of the Azure Function App on the dev computer
Earlier in step 2, we typed the command `func init . --docker`. The option or flag `--docker` tells Azure Function Core Tool to generate the `Dockerfile`. With that, now we can create a Docker image of the Function App. This image will be uploaded to a Docker container on the Azure cloud (Azure Container Registry) later.

With Docker Desktop running, on your terminal, type
```
% docker build -t kle/sampledockerimg .
% docker run -p 7071:80 kle/sampledockerimg
``` 
Do not forget to type the dot at the end of the build command

Now test again:
```
% curl -X POST http://localhost:7071/api/kleSampleFunc -d '{"name":"kevin"}' -H "Content-Type: application/json"
```
If that's working, we now have created a Docker image of the Function App and run it on Docker Desktop successfully.

### Step 5: Log in to Azure CLI on the dev computer
On your terminal, type
```
% az login
```
and follow the instructions.
### Step 6: Create an Azure Resource Group on Azure cloud
```
% az group create -l westus -n kleSampleResourceGroup
```
### Step 7: Create an Azure Container Registry on the Azure cloud
```
% az acr create -n kleSampleRegistry -g kleSampleResourceGroup --sku Standard --admin-enabled true
```
Notice the JSON output with the key `loginServer`. Its value should be something like `klesampleregistry.azurecr.io` 

Launch the Azure portal, https://portal.azure.com, then browse your [Container Registries] (https://portal.azure.com/#blade/HubsExtension/BrowseResourceBlade/resourceType/Microsoft.ContainerRegistry%2Fregistries), select the Registry you just created (in my case `klesampleregistry`), click on `Access Key` under `Settings`, and note the `username` and `password`.

### Step 8: Create an Azure Storage Account on Azure cloud
```
% az storage account create -n klesamplestorage -g kleSampleResourceGroup -l westus
```
### Step 9: Login to your Azure Container Registry
```
% docker login klesampleregistry.azurecr.io
```
When prompted, provide the `username` and `password` that you noted in step 7.

### Step 10: Tag your Docker image
Look at step 4 when you build the docker image of your Function App (`kle/sampledockerimg`), you will tag this image in the Container Registry as `klesample` (note this name must be all in lower case)
```
% docker tag kle/sampledockerimg klesampleregistry.azurecr.io/klesample
```

### Step 11: Push the docker image to the Container Registry
Using Docker, we can now push the image to the Container Registry on Azure
```
% docker push klesampleregistry.azurecr.io/klesample
```

### Step 12: Create an Azure Function App
There is a command from Azure CLI `az functionapp create` that we could use. But the problem is it does not allow the created Function App to be published from a Docker container. So we will use the UI https://portal.azure.com

Click on the big Plus button `Create a Resource` under `Azure Services`, search for `Function App` template and click on `Create` 

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/mufn6jyaxro8pj6sz718.png)

Click on `Next: Hosting >`

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/5r09mzrzqtd827cbe18m.png)

Click on `Review + Create` then `Create` on the last page.

Once the Function App `kleSampleFuncApp` has been created, click on `Platform features`, then `Container Settings` as shown below

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/l013d8zquaicwtrvub3m.png)

On the next screen, select `Single Container`, `Azure Container Registry`, the registry that we created in step 7, the image in step 10, `latest`. Select `On` for `Continuous Deployment`, and Save it.

Once saved, you can close the blade. Back on the `Overview` page, on the Right menu, click on `kleSampleFuncApp`, expand `kleSampleFunc`, you can run test directly from this page. Follow the screenshot below:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/xer4x2qi4e7bfnlxlaot.png)

You can also click the `Get Function URL` link next to the run button and test from Curl or Postman.

```
% curl -X POST https://klesamplefuncapp.azurewebsites.net/api/kleSampleFunc -d '{"name":"kevin"}' -H "Content-Type: application/json"
```

### Continuous Deployment
Remember back on step 12, we select `On` for `Continuous Deployment`. We did so because if we ever need to make changes of the code, which will certainly happen, we want to push the changes up to the Function App on the Docker container on Azure.

So let's go back to the code and change from `Hello` to `Hi`. Save.

First let's test when we run locally. On the terminal, type
```
func start -build
```  

If you get the error message 

```
Port 7071 is unavailable. Close the process using that port, or specify another port using --port [-p].
```

That's because we had the Docker image still running from earlier. We need to stop it.


Type
```
% docker ps
```
Note the `Container Id` in the output. Assume it's something like `87d8462f9d63`, type
```
% docker stop 87d8462f9d63
```

Again, type
```
% func start -build
``` 
Test as we did in step 3. This confirms the change we made is good. Now rebuild the Docker image and run it as we did in step 4.
```
% docker build -t kle/sampledockerimg .
% docker run -p 7071:80 kle/sampledockerimg
``` 
Test again. This confirms the new build of the Docker image contains the change that we made. Now let's tag and push it to Docker on Azure as we did in step 11.
```
% docker tag kle/sampledockerimg klesampleregistry.azurecr.io/klesample
% docker push klesampleregistry.azurecr.io/klesample
```




<!--
```
% az functionapp create --consumption-plan-location westus --name kleSampleFuncApp --os-type Linux --resource-group kleSampleResourceGroup --runtime dotnet --storage-account klesamplestorage
```
Note that `klesamplestorage` must be all in lower case.
-->


<!-- Create a resource -->
<!-- https://docs.microsoft.com/en-us/cli/azure/group?view=azure-cli-latest#az-group-create -->


<!-- Create a function app -->
<!-- https://docs.microsoft.com/en-us/cli/azure/functionapp?view=azure-cli-latest#az-functionapp-create -->

<!-- Create a container registry -->
<!-- https://docs.microsoft.com/en-us/cli/azure/acr?view=azure-cli-latest#az-acr-create -->

<!-- obexusersync.azurecr.io --> 

<!-- docker login obexusersync.azurecr.io -->

<!-- docker build -t obex/usersyncimg . -->

<!-- docker tag obex/usersyncimg obexusersync.azurecr.io/obexusersync -->

<!-- docker push obexusersync.azurecr.io/obexusersync -->