Welcome to today’s post.
In today’s post I will be showing you how to setup your docker containers to be configured with environment variables.
In a previous post I showed how to build Docker containers using the tools in the Visual Studio development environment. However, in the post I did not show how to integrate other dependent services within the container images. That is where the use of environment variables becomes useful, and that is where this post is focused.
Why use Environment Variables in Docker containers?
Why do we need to use environment variables within our docker containers? Why can’t we just use the variables within our container applications and API services?
The reason is that when we are in a development or test environment, using settings internal to our applications might be acceptable in some situations, but when we deploy the docker images from test into a production environment, the settings we configure using our application configuration file, appSettings.json, can be exposed within the production environment. If we then store the application source within a source repository, any sensitive settings are exposed.
In the next two sections I will discuss the options for storing environments: either in the Docker script or outside of the script.
Storing Environment Settings in the Docker Compose Script File
One option is to store settings environment data in a docker-compose.yml script file with explicit key names and values:
version: '3.4'
services:
bookloan.catalog.api:
image: ${DOCKER_REGISTRY-}bookloancatalogapi
environment:
- DB_CONN_STR=Server=172.x.x.x,1433;Database=aspnet-BookCatalog;User Id=xxxxx;Password=xxxxx;
- URL_CATALOG_API=http://localhost/BookLoan.Catalog.API/
build:
context: .
dockerfile: BookLoan.Catalog.API/Dockerfile
To limit exposure of our container application settings, we can store the environment settings variables outside of the container applications, and within an environment configuration file that is outside of the source code folder repository.
Storing Environment Settings Outside of the Docker Compose Script File
To store our environment settings outside of the docker compose script file, we define our environment settings files with a .env file extension.
With docker compose, we define our environment settings files with a .env file extension.
An example is shown below:
bookloan_env.env:
# DB connection string
DB_CONN_STR=Server=172.x.x.x,1433;Database=aspnet-BookCatalog;User Id=xxxxx;Password=xxxxx;
# catalog API URL
URL_CATALOG_API=http://localhost/BookLoan.Catalog.API/
Accessing the environment file is done using a docker-compose script with an env_file section.
When the environment settings file is specified without a qualified path, the default location is the same folder as the current folder of the docker-compose.yml file.
docker-compose.yml
version: '3.4'
services:
bookloan.loan.api:
image: ${DOCKER_REGISTRY-}bookloanloanapi
env_file:
- bookloan_env.env
build:
context: .
dockerfile: BookLoan.Loan.API/Dockerfile
Below is an example of how to specify the environment settings file with an absolute file path:
version: '3.4'
services:
bookloan.loan.api:
image: ${DOCKER_REGISTRY-}bookloanloanapi
env_file:
- C:\development\environment\bookloan_env.env
build:
context: .
dockerfile: BookLoan.Loan.API/Dockerfile
Running the Containers with Environment Variables in Visual Studio
We can run our container application within Visual Studio and view the environment variables within the docker container.
To view the environment variables we first list the running containers:
docker container ls
The output from the above command is shown below:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0678e489bb46 bookloanloanapi:dev "tail -f /dev/null" 15 minutes ago
Up 15 minutes 0.0.0.0:32774->80/tcp BookLoan.Loan.API
Obtain the container id, then run the following command to view the variables.
docker container inspect 0678e489bb46
The environment variables are within the values of the “Env” key of the JSON output:
…
"Env": [
"DB_CONN_STR=Server=172.x.x.x,1433;Database=aspnet-BookCatalog;User Id=xxxxx; Password=xxxxx;",
"URL_CATALOG_API=http://localhost/BookLoan.Catalog.API/",
"ASPNETCORE_ENVIRONMENT=Development",
"DOTNET_USE_POLLING_FILE_WATCHER=1",
"ASPNETCORE_LOGGING__CONSOLE__DISABLECOLORS=true",
"NUGET_FALLBACK_PACKAGES=/root/.nuget/fallbackpackages",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"ASPNETCORE_URLS=http://+:80",
"DOTNET_RUNNING_IN_CONTAINER=true"
],
…
In the final section, I will show how to run the containers with their environment variables from outside of Visual Studio.
Running the Containers with the Environment Variables outside of Visual Studio
Likewise, we can run our docker containers outside of the Visual Studio 2019 IDE in a command prompt and achieve the same outcome.
First run the build:
docker-compose build
The output from the above command is below:
Building bookloan.loan.api
Step 1/16 : FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
---> 46c1b808c34b
Step 2/16 : WORKDIR /app
---> Using cache
…
…
Step 16/16 : ENTRYPOINT ["dotnet", "BookLoan.Loan.API.dll"]
---> Running in 30b37d227063
Removing intermediate container 30b37d227063
---> 6a56c111df7c
Successfully built 6a56c111df7c
Successfully tagged bookloanloanapi:latest
Start the image within as a container application:
docker-compose up
The output for the above command is below:
Recreating bookloanloanapi_bookloan.loan.api_1 ... done Attaching to bookloanloanapi_bookloan.loan.api_1
bookloan.loan.api_1 | warn: Microsoft.EntityFrameworkCore.Model.Validation[30000]
bookloan.loan.api_1 | No type was specified for the decimal column 'DailyOverdueFee' on entity type 'AdminFeeViewModel'. This will cause values to be silently truncated if they do not fit in the default precision and scale. Explicitly specify the SQL server column type that can accommodate all the values using 'HasColumnType()'.
…
bookloan.loan.api_1 | Hosting environment: Development
bookloan.loan.api_1 | Content root path: /app
bookloan.loan.api_1 | Now listening on: http://[::]:80
bookloan.loan.api_1 | Application started. Press Ctrl+C to shut down.
To test our container application can run with the consumed environment variables, we will need to obtain the IP address of the HostPort of the docker container.
After running the following command:
docker container ls
The output from the above command shows the IP address is 32776:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
07f105b07a22 bookloanloanapi "dotnet BookLoan.Loa…" 2 minutes ago Up 2 minutes 0.0.0.0:32776->80/tcp bookloanloanapi_bookloan.loan.api_1
Then we just run a CURL command to call our API request within the docker container:
curl -X GET "http://localhost:32776/api/Loan/Details/1" -H "accept: */*"
{"id":1,"loanedBy":"billy@bookloan.com","dateLoaned":"2020-12-12T00:00:00","dateDue":"2020-12-26T00:00:00","dateReturn":"0001-01-01T00:00:00","onShelf":false,"dateCreated":"2020-12-12T00:38:18.4419333","dateUpdated":"2020-12-12T00:38:18.4419389","bookID":5,"book":null,"overdueLoans":null}
There may be possible problems running our container application with environment variables. When starting our docker container you may see the following state of the container:
This means that there was an abnormal exit of the container application, likely caused by an invalid configuration value or when retrieving the environment variable from the container application.
We can see a more detailed error when we try running docker-compose up:
docker-compose up
The output from the above command is shown below:
Creating network "bookloanloanapi_default" with the default driver
Creating bookloanloanapi_bookloan.loan.api_1 ... done Attaching to bookloanloanapi_bookloan.loan.api_1
bookloan.loan.api_1 | Application startup exception: System.ArgumentNullException:
Value cannot be null. (Parameter 'connectionString')
bookloan.loan.api_1 | at Microsoft.EntityFrameworkCore.Utilities.Check.NotEmpty(String value, String parameterName)
...
bookloan.loan.api_1 | at Microsoft.AspNetCore.Hosting.WebHostExtensions.Run(IWebHost host)
bookloan.loan.api_1 | at BookLoan.Loan.API.Program.Main(String[] args) in /src/BookLoan.Loan.API/Program.cs:line 18
bookloanloanapi_bookloan.loan.api_1 exited with code 139
To investigate this issue, either add logs to your application or re-run the container within the VS 2019 IDE debugger and trace the problem.
That’s all for today’s post.
In a future post I will discuss how to combine multiple images within the same container as a microservice.
I hope you found this post useful and informative.
Andrew Halil is a blogger, author and software developer with expertise of many areas in the information technology industry including full-stack web and native cloud based development, test driven development and Devops.