I recently came across the issue that I had to build a Docker container with a NextJS app inside that was relying on a environment variable to set the domain for Plausible.io.
The tricky thing was that I was building the container once and deploying it to multiple pods with different environment configs.
Technically docker can respect a .env
file when it is run with the option --env-file
like so:
docker run --rm --env-file .env -p 3000:3000 -d YOUR_CONTAINER_TAG:prod
So here comes the issue...
But since the environment was set during build time inside the container and NextJS has automatic site optimiziation and builds pre-rendered pages for server-side render during build, the environment variables from the Docker build run were baked into the image and it did not care about the .env
file for server logic.
A small bash script to the rescue
I am using Envault to manage environment configs and since the image is being build with a Jenkins pipeline, the pipeline pulls the correct .env
file from Envault each time.
Inside the Dockerfile
, change the vars to be this:
ARG DB_USER
ARG DD_SVC_NAME
ENV DB_USER=$DB_USER
ENV DD_SVC_NAME=$ARG DD_SVC_NAME
This means the build command needs to contain --build-arg
paramters for each variable.
To read those from the .env
file via bash, we can use this:
$(for i in `cat .env`; do out+="--build-arg $i " ; done; echo $out;out="")
The docker command looks like this:
docker build -f Dockerfile -t MYTAG:prod $(for i in `cat .env`; do out+="--build-arg $i " ; done; echo $out;out="") .
Bonus round: makefile
Since I love Makefiles, there is a small pitfall how to include the bash loop into the command, so here is my Makefile for reference:
SHELL := /bin/bash
...
# this line will set the build args from env file
DECONARGS = $(shell echo "$$(for i in `cat .env`; do out+="--build-arg $$i " ; done; echo $$out;out="")")
GEN_ARGS = $(eval BARGS=$(DECONARGS))
.PHONY: dist-prod
dist-prod:
@echo "Running docker build for PROD ..."
$(GEN_ARGS)
docker build -f Dockerfile -t $(TAG_SHA) $(BARGS) .
...
Top comments (5)
That was a nice read! Liked, bookmarked and followed, keep the good work!
Thanks! :)
I need to promote the same image from say dev environment to staging environment. Can you help me in this?
Even if I use env defined variables from vault, vars will be environment specific and will require to re-trigger image build, right?
Thanks
Thanks! But as it seems we have no other way to solve it (passing build-arg's is also recommended by docker).
I've been looking for hours how to optimise the process of my Azure pipeline.... The Docker concept "Build the Docker image only once, push it to the registry only once, deploy it anywhere and anytime." is not working in my case....
Greetings from Ludwigshafen! ;-)
Thanks for this helped me solve the problem