Dockerfile CMD не выполняет сценарий bash, как ожидалось, например. эхо-команды в set-env.sh
не выполняются.
Во-первых, я передаю env var в образ, который Dockerfile использует.
docker build -f Dockerfile --pull --build-arg env=prod -t test-app .
Вот Dockerfile, который я использую
# 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 (упоминается в последней Dockerfile
строке выше)
#!/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
Выше ничего НЕ повторяется в env-config.js
- не знаю, почему.
Однако всякий раз, когда я запускаю set-env.sh
вручную из контейнера, он работает так, как ожидалось, например. выводит тестовую строку DEV или PROD в env-config.js
на основе параметра env, переданного в команду сборки docker
Есть идеи?
В вашем Dockerfile вы устанавливаете переменную ENVIRONMENT
, но в своем скрипте вы тестируете переменную env
.
Переменные аргумента сборки не передаются как переменные среды, поэтому вы не можете использовать env
, не установив его в Dockerfile.
Либо изменить
ENV ENVIRONMENT=$env
к
ENV env=$env
в Dockerfile или измените операторы скрипта if
на
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
(Я также собирался предложить в вопросе изменить строку shebang на #!/bin/sh
и не устанавливать bash в Dockerfile; похоже, что на самом деле это не использует какие-либо функции bash.)
Спасибо за всю информацию, размещенную всеми.
Проблема была связана с тем, как я тестировал скрипт. Я выполнил следующее и вошел в контейнер, чтобы проверить, что на самом деле произошло.
docker run test-app tail -F asdflg
Без моего ведома команда tail, разрешая запуск контейнера, на самом деле, казалось, задерживает обработку CMD в последней строке моего Dockerfile... Как только я вместо этого запустил контейнер с помощью docker compose up
, все заработало, как и ожидалось.
Лучше использовать
=
, а не==
- таким образом, операторы работают так же хорошо с базовым стандартом[
(по крайней мере, когда добавляются дополнительные кавычки), и вы не создаете память пальца только для bash. В качестве альтернативы рассмотритеcase $ENVIRONMENT in dev) echo "TEST: DEV";; prod) echo "TEST: PROD";; *) echo "Unsupported environment" >&2; exit 1;; esac >>./env-config.js
, который вообще не требует никаких расширений bash.