Dockerfile: Environment Variables

If you are here without reading the previous articles Dockerfile: Layered Architecture and Dockerfile: Multi-stage Build, then I would encourage you to read them first as the foundation for this article is there.

In the previous article we built an image using multi-stage build and ran a container but still had to edit the application.properties file which contains datasource properties such as database host, username and password. In this article, we are going to avoid that completely and fetch data source properties using environment variables.

Updating Application Properties

In order to do this, first of all we should update our properties file so that it can fetch relevant values from Environment Variables on the host machine. In our case, the application.properties file would look like below.

spring.datasource.url=jdbc:mysql://${DB_HOST}:3306/photo_app
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}
spring.jpa.hibernate.ddl-auto=update
server.error.include-message=always
tokenSecret=jf9f45lasdfk8
server.servlet.context-path=/mobile-app-ws

Here ${DB_HOST}, ${DB_USERNAME}, ${DB_PASSWORD} are all Environment Variables and the values will be fetched from host machine’s Environment Variables. Therefore, in order for the application to work properly, we have to make sure these Environment Variables are properly set.

Since this is a Spring Boot application, this is one way to let the application know that it should fetch the relevant values from Environment variables. If it were a different one, then the syntax could be different. The point is, if we need to use Environment Variables in our Docker containers for our application, then the application should be written in a way that it could read those variables.

Updated Dockerfile

Since we have configured our application to utilize Environment Variables, we need to provide them when creating our container. To do that, our image must know which Environment Variables to look for.

FROM maven:3.6.3-openjdk-16-slim AS build
 
ENV DB_HOST=db \
     DB_USERNAME=username \
     DB_PASSWORD=password
 
COPY ./mobile-app-ws /usr/local/mobile-app-ws
 
WORKDIR /usr/local/mobile-app-ws/
 
RUN mvn -Dmaven.test.skip=true clean package
 

FROM tomcat:8
 
COPY --from=build /usr/local/mobile-app-ws/target/mobile-app-ws-0.0.1-SNAPSHOT.war /usr/local/tomcat/webapps/mobile-app-ws.war
 
EXPOSE 8080
 
CMD ["catalina.sh", "run"]

Here the rest of the Dockerfile is the same as before. Only new layer I have added is the line that contains ENV at line number 3. If you need to know more about what other layers mean, please refer to the previous article.

I have specified the exact same Environment Variables I specified in the application.properties file. Value given after ‘=’ is the default value assigned for the Environment Variable. For instance, ‘DB_HOST’ Environment Variable is assigned ‘db’ as the default value. We can override that default value when we create a container from the image.

Building the Image

Same as before, we can build an image using this Dockerfile. I will tag this one as v3.

C:\WINDOWS\system32>docker build --progress=plain -t myapp:v3 "C:\Users\charith\Desktop"

This could take a few minutes.

--progress=plain option will show the output in the command line as plain text, which would make it easier to read.

Notice that the build context in this case is “C:\Users\charith\Desktop” directory, which means the Dockerfile is in the same directory and my project is in “C:\Users\charith\Desktop\mobile-app-ws” directory. This is very important because the COPY command looks at directories relative to the build context.

Running a Container from the New Image

Once the image is built successfully, we can run a container using it, but this time, we need to specify the 3 Environment Variables.

charith@ch MINGW64 ~
 $ docker run -d --name ws-myappv3 \
   -e DB_HOST=db-myapp \
   -e DB_USERNAME=charith \
   -e DB_PASSWORD=charith \
   -p 38083:8080 \
   --network=myapp \
   myapp:v3
   2d38d959998e1008225fbbad62cf0f140c17af3d8ba4a174178d5a1beaa81112 

As you can see above, I have specified the Environment Variables in my run command and given the values of my MySQL database container. What I have given as DB_HOST is essentially the name of the MySQL container.

Now all I need to do is check whether my application is working without any issues. And it does!

Looking up the Environment Variables Inside the Container

Let’s just open a terminal inside our container and see the values set for our Environment Variables.

C:\WINDOWS\system32>docker exec -it ws-myappv3 sh
 # echo $DB_HOST " " $DB_USERNAME " " $DB_PASSWORD
 db-myapp charith   charith
 #

As you can see the Environment Variables contain the values we set in docker run command instead of the default ones we set in Dockerfile.

Share this article if it was helpful!

Leave a Reply

Your email address will not be published. Required fields are marked *