Docker — Environment variables & appsettings.json- .Net - DotNet
By: Lucas Bazetto
Tags: Programming, Dotnet Core, Docker, Containers, Dotnet

Photo by Karl Pawlowicz on Unsplash

If you already worked with .Net, a.k.a .Net Core, you probably noticed how handy is to store some settings in the appsetting.json file. Beyond the malleability of working with a JSON file, the way of getting and manage this information is very straightforward.

However, if you are running the application inside a Docker container and you want to change it for some reason, it can be a little bit complex.

Nevertheless, using the concept of environment variables can be very helpful.

The problem

Let's say that we have our application running in a Docker container. But, we need to have one or more containers per customer, and each customer has different settings. So, what we can do to solve this issue?

The application

To illustrate this problem, I've created a very simple Web API with just one endpoint. The function of this endpoint is very simple, just read the settings from the appsettings.json and show it.

If you want to, you can clone the full source code from Github:

git clone https://github.com/lbazetto/DockerEnvironmentVariablesDotNet

The appsettings.json file

In the appsettings.json we kept all defaults and just added two more sections:

- MyFirstValueCustomConfig — Simple string

- ComplexConfig — Array with child objects

The full file:

The web API endpoint

As the only thing that the endpoint does for us is to read the data from the appsettings.json file, our code can be something like:

The Dockerfile

The Dockerfile is very basic as well:

The output

Running the application, and reaching the endpoint (http://localhost:5000/settings) we are going to get the results:

["I'm the first custom setting","Hi, Complex!"]

Ok, now that we have the problem and application, let's explore the solutions.

Solutions

The idea is to try to show the different solutions with pros and cons of each one.

Solution 1 — One Docker image per customer

Firstly, we can create one base image with all default settings. And then, build a new image per customer containing these new values.

Pros:

- Isolated definition per customer

- Can be helpful in a scenario when you want to implement something specifically for a specific customer (what I'm always trying to avoid 😂)

Cons:

- Hard to maintaining

- High storage consumption

Solution 2 — Docker volumes

Secondly, we can use the volumes. What is it? Following the docker definition about volumes, we have:

Volumes are the preferred mechanism for persisting data generated by and used by Docker containers.

In my opinion, it will be better than our first solution, as we can use the same base image for all customers and just have one different file per customer.

Assuming that we have one folder called CustomerSettings in the root directory like this:

Customer Settings

Another nice thing about the volume is the ability to rename the file/folder automatically without coding. In that way, regardless of the name that we choose for the file outside of the container, inside we always expect the same name (appsettings.json). The docker-compose file can be something like this:

Docker-compose file with a volume

However, the downside of this approach is to manage and configure the data storage following the rules/requirements of your container orchestrator/cloud provider. So, the overview of this proposal:

Pros:

- Same base image for all customers

Cons:

- Storage management

Solution 3 — Environment variables

Apart from these, there is another approach that can be very useful and mix the benefits from the solutions above, the environment variables.

Following the definition from Wikipedia:

An environment variable is a dynamic-named value that can affect the way running processes will behave on a computer. They are part of the environment in which a process runs.

In addition to this, Docker has a nice mechanism for working with this resource.

By the same token of solution 2, the idea is to have just one base image and set the data per container. Following the same concept of the example above we are going to use the docker-compose file to inject the information. But now, we are going to replace the volume for the environment variables:

Pros:

- Same base image for all customer

- No storage management

Cons:

- Depending on the number of variables/structure can be tricky to maintain

Conclusion

Using environment variables with a docker container can be a nice match, as you can extract the advantages of this combination without adding extra code to your application.