Featured image of post Optimizing Dockerfile Startup Script With Environment Variables

Optimizing Dockerfile Startup Script With Environment Variables

In this post, I will show how I optimized my Dockerfile startup script to leverage environment variables more elegantly.

In my previous post; Combining ENTRYPOINT and CMD in a Dockerfile, I showed how I added reusability to my Dockerfile by combining ENTRYPOINT and CMD.

To take things further, I didn’t like how I still had to supply arguments to entrypoint.sh when those arguments were already available in the container as environment variables, so I eventually modified my Dockerfile this way:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# [Choice] .NET Core version: 5.0, 3.1, 2.1
ARG VARIANT=3.1
ARG DB_SERVICE=db
ARG DB_SERVICE_PORT=1433
ARG PROJECT=Business.Web

# create a base runtime image with node
FROM mcr.microsoft.com/dotnet/core/aspnet:${VARIANT} AS runtime
EXPOSE 80
EXPOSE 443
RUN curl -sL https://deb.nodesource.com/setup_10.x |  bash -
RUN apt-get install -y nodejs

# create a base SDK image with node
FROM mcr.microsoft.com/dotnet/core/sdk:${VARIANT} as sdk
RUN curl -sL https://deb.nodesource.com/setup_10.x |  bash -
RUN apt-get install -y nodejs

# copy source files
FROM sdk as build
COPY src/ ./src

# restore nuget packages
WORKDIR /src
RUN dotnet restore

# run publish command
FROM build as publish
RUN dotnet publish -c Release -o /release --no-restore

# create release image from base runtime image
FROM runtime AS release
# https://github.com/moby/moby/issues/37345#issuecomment-400245466
ARG PROJECT
ENV ASSEMBLY=${PROJECT}.dll
COPY --from=publish /release .
COPY entrypoint.sh /bin/
COPY testconnection.sh /bin/
RUN chmod +x /bin/entrypoint.sh
RUN chmod +x /bin/testconnection.sh

ENTRYPOINT [ "/bin/entrypoint.sh" ]
CMD ["sh", "-c", "dotnet $ASSEMBLY"]

Subtle change; the location of the entrypoint.sh changed to /bin/entrypoint.sh and the $DB_SERVICE as well as the $DB_SERVICE_PORT arguments are missing. So, how does my entrypoint.sh know which server to check for connections before running our startup command? Thanks for asking:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/bin/bash
set -e

# check if the startup command has been provided
if [ "$1" == "" ]; then
 echo "Startup command not set. Exiting"
 exit;
fi

# check if the $DB_SERVICE environment variable has been set
if [ "$DB_SERVICE" == "" ]; then
 echo "Environment variable 'DB_SERVICE_NAME' not set. Exiting."
 exit;
fi

# check if the $DB_SERVICE_PORT environment variable has been set
if [ "$DB_SERVICE_PORT" == "" ]; then
 echo "Environment variable 'DB_SERVICE_PORT' not set. Exiting."
 exit;
fi

echo "Testing connection to ${DB_SERVICE}:${DB_SERVICE_PORT}"
until /bin/test-connection.sh $DB_SERVICE_NAME $DB_SERVICE_PORT; do
>&2 echo "DB Service is starting up"
sleep 1
done

>&2 echo "DB Service is up - executing command: '$@'"
# https://stackoverflow.com/a/3816747
exec "$@"
exit 0

As you can see, I am reading environment variables in the bash script and I use all arguments to this script as the startup command. You may prefer it the other way, but I like it this way, and I hope you find this post valuable.

As always, all comments and feedback are greatly appreciated.

Credits:
How to check if an environment variable exists and get its value?

Licensed under CC BY-NC-SA 4.0
Last updated on Apr 11, 2022 10:07 EST
Built with Hugo
Theme Stack designed by Jimmy