Accessing application settings from Azure Function Apps in a Docker Container
Tags: azurefunctionapp, docker, azure
Published: 2019-12-12 20:25:15

---
title: Accessing application settings from Azure Function Apps in a Docker Container
published: true
description: 
tags: azure function app, docker, azure
---

### Abstract
In my [previous article](https://dev.to/codeprototype/azure-function-app-and-docker-on-azure-made-easy-in-12-steps-3fob), the business logic in the Function App is practically none.  But one of the first common things of all software programs, Azure Function Apps or otherwise, in a real-world scenario is reading `environment variables`. In this article, I will refer to these `environment variables` as `application settings`. The reason is that I don't want us to get mixed up with `environment variables` that are [passed to the Docker container](https://docs.docker.com/engine/reference/commandline/run/).
     
Application settings in this context are, for example, the Function App needs to read the API key and/or secret of a third-party service in order to query for some data. Another example might be the connection string of the database. Generally, it is considered a bad programming to hard-code these values in the code itself. Since these values are configurable data, they should be decoupled from the program code and should live in an `environment variable` file or something like that. The key concept here is they should be decoupled.

The goal is we want to allow Function Apps to read application settings so that they can run locally and run inside a Docker container on the Desktop, as well as on Azure, inside and outside of an Azure Docker container.     

### Review: Non Docker way
Forget about Docker for a moment, let's say we write the Azure Function App on our development computer, we can keep all `application settings` in a file named `local.settings.json`. This file is in JSON format, and looks something like this:

```
{
    "SomeAPIClientKey": "...",
    "SomeAPIClientSecret": "..."
}
```

The function can access these application settings and be written as:

```
[FunctionName("kleSampleFunc")]
public static async Task<IActionResult> Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, ILogger log, ExecutionContext context)
    {
        var configuration = new ConfigurationBuilder()
            .SetBasePath(context.FunctionAppDirectory)                    
            .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
            .AddEnvironmentVariables()
            .Build();

        var apiKey = configuration["SomeAPIClientKey"];
        var apiSecret = configuration["SomeAPIClientSecret"];
        log.LogInformation($"apiKey: {apiKey}");
        log.LogInformation($"apiSecret : {apiSecret}");

        // .... Business logic that makes use of apiKey and apiSecret
        
        return OkObjectResult(new {
            //whatever        
        });         
    }
```

We can run it locally using the following command:

```
$ func start --build
```     

We might choose NOT to commit the file `local.settings.json` to Source Control, so it won't get deployed. But it doesn't matter because when this Function App runs on Azure, the `environment variables` are no longer coming from the file `local.settings.json`. Instead, there's an Application Settings blade on Azure Portal where we can configure them.

### Docker   
From my previous [article](https://dev.to/codeprototype/azure-function-app-and-docker-on-azure-made-easy-in-12-steps-3fob), the Function App running in the local Docker Desktop will not be able to read any `environment variable` from the `local.settings.json` file. 

Assume we already run 
```
$ docker build -t kle/sampledockerimg .
$ docker run -p 7071:80 kle/sampledockerimg
```

Test from Postman or `curl`, you will see the 2 `log.LogInformation()` statements above outputting `null` values for `apiKey` and `apiSecret`.

So launch another Terminal or Console, and run this command
```
$ docker ps
```

You will see the output in tabular format with 7 columns. The last column is `NAMES`. Note the value of this column for the docker image of your Function App. It's some kind of made-up name and varies each time the image is rebuilt. For example, I see mine as `vigorous_bhaskara`.

So now run 
```
$ docker exec -it vigorous_bhaskara /bin/bash
```

The command above allows us accessing the file system, similar to SSH.

So if you run the linux `ls` command

```
$ ls /home/site/wwwroot
```

You will NOT see the file `local.settings.json`

So if the file containing the `environment variables` is not present, how can can anything read their values? The fix is simple. All we have to do is copying the file to Docker container using the Docker copy command

```
$ docker cp local.settings.json 16527b513905:/home/site/wwwroot
```

Run Postman or `curl` again, everything should work. 

On the other hand, the same Function App, deployed to Azure, will be able to read all `environment variables` that have been configured in the Application Settings blade on Azure Portal. So we don't have to do anything there. 

### Conclusion
Long story short, just remember these 3 commands:

```
$ docker ps
$ docker exec -it vigorous_bhaskara /bin/bash
$ docker cp local.settings.json 16527b513905:/home/site/wwwroot
```

The first command tells us the container name and container id. In the example, that's `vigorous_bhaskara` and `16527b513905` respectively.

The second one allows us to access the file system of the Docker Container, in an SSH-like way.

The third one copies  the `local.settings.json` from the host computer to the container.