0

Dockerfile CMD not executing a bash script as expected e.g. the echo commands in set-env.sh do not get executed.

First, I pass in an env var to the image for Dockerfile to use

docker build -f Dockerfile --pull --build-arg env=prod -t test-app .

Here's the Dockerfile I'm using

# Multi-stage
# 1) Node image for building frontend assets
# 2) nginx stage to serve frontend assets

# Name the node stage "builder"
FROM node:16 AS builder
# Set working directory
WORKDIR /project
# Copy all files from current directory to working dir in image
COPY . .
# install node modules and build assets
RUN yarn install --network-timeout 100000 && yarn build

# nginx state for serving content
FROM nginx:alpine

# Nginx config
RUN rm -rf /etc/nginx/conf.d
COPY conf /etc/nginx

# Set working directory to nginx asset directory
WORKDIR /usr/share/nginx/html
# Remove default nginx static assets
RUN rm -rf ./*
# Copy static assets from builder stage
COPY --from=builder /project/build .

# Set enviorment so the set-env.sh script can read the correct env file
ARG env
ENV ENVIRONMENT=$env

# these statements print out the env vars as expected during the build
RUN echo $env
RUN echo $ENVIRONMENT

# Default port exposure
EXPOSE 443

# Copy environment file and script into container
COPY ./set-env.sh .

# Add bash
RUN apk add --no-cache bash

# Containers run nginx with global directives and daemon off
CMD ["/bin/bash", "-c", "/usr/share/nginx/html/set-env.sh && nginx -g 'daemon off;'"]

set-env.sh (referenced in the last Dockerfile line above)

#!/bin/bash

# Recreate config file
rm -rf ./env-config.js
touch ./env-config.js

# Choose the .env file base on "ENV" defined in the DockerFile
if [ $env == "dev" ]; then
  echo "TEST: DEV " >> ./env-config.js
elif [ $env == "prod" ]; then
  echo "TEST: PROD " >> ./env-config.js
else
  echo "Unsupported environment"
  exit 1
fi

Above does NOT echo anything out to env-config.js - not sure why.

However, whenever I run set-env.sh manually from within the container, it works as expected e.g. prints out DEV or PROD test line to env-config.js based on the env param passed in to the docker build command

Any ideas?

2 Answers2

1

Thanks for all the info posted by everyone.

The issue was related to how I was testing the script. I ran the following and logged in into the container to check on what actually happened.

docker run test-app tail -F asdflg

Unbeknown to me, the tail command, while allowing the container to run, actually seemed to hold up the processing of the CMD on the last line of my Dockerfile... Once I ran the container with docker compose up instead, everything worked as expected.

0

In your Dockerfile, you set the variable ENVIRONMENT but in your script, you test on the variable env.

Build argument variables are not passed on as environment variables, so you can't use env without setting it in the Dockerfile.

Either change

ENV ENVIRONMENT=$env

to

ENV env=$env

in the Dockerfile or change your script if statements to

if [ $ENVIRONMENT == "dev" ]; then
  echo "TEST: DEV " >> ./env-config.js
elif [ $ENVIRONMENT == "prod" ]; then
  echo "TEST: PROD " >> ./env-config.js
else
  echo "Unsupported environment"
  exit 1
fi
Hans Kilian
  • 18,948
  • 1
  • 26
  • 35
  • Better to use `=` rather than `==` -- that way one's statements work just as well with a baseline-standard `[` (at least when extra quoting is added) and one isn't creating bash-only finger memory. Alternately, consider `case $ENVIRONMENT in dev) echo "TEST: DEV";; prod) echo "TEST: PROD";; *) echo "Unsupported environment" >&2; exit 1;; esac >>./env-config.js`, which doesn't require any bash extensions at all. – Charles Duffy Apr 04 '23 at 14:56
  • (I was also going to suggest in the question changing the shebang line to `#!/bin/sh` and not installing bash in the Dockerfile; this doesn't really seem to use any bash features.) – David Maze Apr 04 '23 at 15:29