This question already has answers here:
How can I use a variable inside a Dockerfile CMD?
(6 answers)
Closed last month.
We have an angular/express app that is dockerized and deployed in k8s.
Dockerfile:
FROM node:18
WORKDIR /usr/src/app
COPY . .
EXPOSE 1234
CMD [ "npm", "run", "prod" ]
Is it possible to have a variable and have that variable be dynamic?
Example of what I want:
FROM node:18
WORKDIR /usr/src/app
COPY . .
EXPOSE 1234
CMD [ "npm", "run", ENV ] <<<<<------ HERE (want to pass in either dev or prod)
I have a build script (which needs to be run with an arg passed in) that does the following:
./build_and_deploy_app.sh dev or ./build_and_deploy_app.sh prod
dev or prod are the variables I want to pass into Dockerfile
builds docker app
tags docker app
pushes docker app to ECR
Once that docker image is pushed to ECR:
We update our k8s deployment to use the newly uploaded image
I wondering if there is a way to allow our Dockerfile (docker image that is uploaded to ECR) to use a dynamic variable instead of a static variable (like shown above).
Thank you!
You could use the Docker ARG instruction:
FROM node:18
WORKDIR /usr/src/app
COPY . .
EXPOSE 1234
ARG env
CMD [ "npm", "run", ${env}]
And then pass the value with --build-arg:
docker build --build-arg env=prod -t mycontainer .
And of course, you could take this from the shell script's argument:
docker build --build-arg env=$1 -t mycontainer .
Related
I am trying to set environment variables in my dockerfile that are available at runtime after running the next js app via npm run start (next start).
I have read that I need to use ENV variables in my dockerfile to have these env variables available at runtime. ARG variables in dockerfile are only available at build time.
So I am running the docker build command wih --build-arg and it is working with my NEXT_PUBLIC... variables but it wont work for my secret non public env variabels.
here is my content of .env file in nextjs:
NEXT_PUBLIC_RECAPTCHA_SITE_KEY=my-public-key...
RECAPTCHA_SECRET_KEY=my-secret-key...
this is my docker run command from my Gitlab CI:
docker build --build-arg NEXT_PUBLIC_RECAPTCHA_SITE_KEY="$NEXT_PUBLIC_RECAPTCHA_SITE_KEY" --build-arg RECAPTCHA_SECRET_KEY="$RECAPTCHA_SECRET_KEY" -t ${CI_REGISTRY}/${CI_PROJECT_PATH}/nextjs:${CI_COMMIT_SHA} ./nextjs
the docker file:
ARG BASE_IMAGE=node:14.16.0-alpine3.13
# Build
FROM $BASE_IMAGE as BUILD
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
RUN apk add --no-cache bash git
WORKDIR /app
COPY ./package.json ./
COPY ./package-lock.json ./
RUN CI=true npm ci
COPY . ./
ARG RECAPTCHA_SECRET_KEY=recaptchasecrect_placeholder
ENV RECAPTCHA_SECRET_KEY=${RECAPTCHA_SECRET_KEY}
ARG NEXT_PUBLIC_RECAPTCHA_SITE_KEY=recaptchasitekey_placeholder
ENV NEXT_PUBLIC_RECAPTCHA_SITE_KEY=${NEXT_PUBLIC_RECAPTCHA_SITE_KEY}
RUN npm run build
# Run
FROM $BASE_IMAGE
WORKDIR /app
COPY --from=BUILD /app ./
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
EXPOSE 3000
CMD ["npm", "start"]
If I put ENV RECAPTCHA_SECRET_KEY=my-secret-key... hardcoded into the dockerfile above EXPOSE 3000 it will work and the .env variable is available at runtime.
Why is my NEXT_PUBLIC_RECAPTCHA_SITE_KEY variable available at runtime and my RECAPTCHA_SECRET_KEY variable that is set the same way not?
When you run the next app, the variables in .evn will only load to next app if they start with NEXT_PUBLIC_, remember you are not running the next app from cmd, your starting point is 'npm start' in docker which only loads env variable with names stating from "NEXT_PUBLIC"
NEXT_PUBLIC_ANALYTICS_ID=abcdefghijk
More info here - https://nextjs.org/docs/basic-features/environment-variables
Just prefix all your variables with "NEXT_PUBLIC"
NEXT_PUBLIC_RECAPTCHA_SITE_KEY=my-public-key...
NEXT_PUBLIC_RECAPTCHA_SECRET_KEY=my-secret-key...
I have a multi-stage build where a python script runs in the first stage and uses several env vars.
How do I set these variables in the docker build command?
Here's the Dockerfile:
FROM python:3 AS exporter
RUN mkdir -p /opt/export && pip install mysql-connector-python
ADD --chmod=555 export.py /opt/export
CMD ["python", "/opt/export/export.py"]
FROM nginx
COPY --from=exporter /tmp/gen/* /usr/share/nginx/html
My export.py script reads several env vars, and I have a .env file. If I run a container built with teh first stage and pass --env-file it works, but I can't seem to get it to work in the build stage.
How can I get the env vars to be available when building the first stage?
I don't care if they are saved in the image or not...
its seens you are looking for the ARG instruction. it's only avaible at the building time and won't be avaible at image runtime. Don’t use them for secrets which are not meant to stick around!
# default value if not using --build-arg instruction
ARG GLOBAL_AVAILABLE=iamglobal
FROM python:3 AS exporter
RUN mkdir -p /opt/export && pip install mysql-connector-python
ADD --chmod=555 export.py /opt/export
ARG GLOBAL_AVAILABLE
ENV GLOBAL_AVAILABLE=$GLOBAL_AVAILABLE
# only visible at exporter build stage:
ARG LOCAL_AVAILABLE=aimlocal
# multistage visible:
RUN echo ${GLOBAL_AVAILABLE}
# local stage visible (exporter build stage):
RUN echo ${LOCAL_AVAILABLE}
CMD ["python", "/opt/export/export.py"]
FROM nginx
COPY --from=exporter /tmp/gen/* /usr/share/nginx/html
you can pass custom ARG values by using the --build-arg flag:
docker build -t <image-name>:<tag> --build-arg GLOBAL_AVAILABLE=abc .
the general format to pass multiple args is:
docker build -t <image-name>:<tag> --build-arg <key1>=<value1> --build-arg <key2>=<value2> .
some refs:
https://docs.docker.com/engine/reference/builder/
https://blog.bitsrc.io/how-to-pass-environment-info-during-docker-builds-1f7c5566dd0e
https://vsupalov.com/docker-arg-env-variable-guide/
I am currently trying to explore of a way on how to possibly make my dockerfile generic where it can be used by any .net projects.
My docker file looks like this. I have parameterized the base image to be used. And now I want to try to parameterized the EntryPoint instead of writing "mydotnet.dll" I want it to be passed as a variable/argument during docker build.
My docker file
ARG var1
FROM $var1
WORKDIR /app/
COPY . .
EXPOSE 80
ENTRYPOINT ["dotnet", "mydotnet.dll"]
When passing environment during docker runtime, my environment variables are getting wrapped with quotes. How am I able to set an environment variable without having it quoted?
I set the environment like such; docker run server -e NODE_ENV=dev
Output from the command above:
node dist/server.js "NODE_ENV=dev"
Heres a snippet from my Dockerfile
FROM base AS release
# copy production node_modules
COPY --from=dependencies /root/app/prod_node_modules ./node_modules
# copy app sources
COPY . .
# expose port and define CMD
EXPOSE 3000
ENTRYPOINT ["npm", "run", "start:prod"]
First of all I think the sequence of your docker run command has a problem.
-e option should be before your docker image name, like this
docker run -e NODE_ENV=dev server
If its still not helping, then try --env-file option of docker run.
docker run --env-file /path/to/server.env server
In server.env
NODE_ENV=dev
I'm passing a build argument into: docker build --build-arg RUNTIME=test
In my Dockerfile I want to use the argument's value in the CMD:
CMD ["npm", "run", "start:${RUNTIME}"]
Doing so results in this error: npm ERR! missing script: start:${RUNTIME} - it's not expanding the variable
I read through this post: Use environment variables in CMD
So I tried doing: CMD ["sh", "-c", "npm run start:${RUNTIME}"] - I end up with this error: /bin/sh: [sh,: not found
Both errors occur when I run the built container.
I'm using the node alpine image as a base. Anyone have ideas how to get the argument value to expand within CMD? Thanks in advance!
full Dockerfile:
FROM node:10.15.0-alpine as builder
ARG RUNTIME_ENV=test
RUN mkdir -p /usr/app
WORKDIR /usr/app
COPY . .
RUN npm ci
RUN npm run build
FROM node:10.15.0-alpine
COPY --from=builder /usr/app/.npmrc /usr/app/package*.json /usr/app/server.js ./
COPY --from=builder /usr/app/config ./config
COPY --from=builder /usr/app/build ./build
RUN npm ci --only=production
EXPOSE 3000
CMD ["npm", "run", "start:${RUNTIME_ENV}"]
Update:
Just for clarity there were two problems I was running into.
1. The problem as described by Samuel P.
2. ENV values are not carried between containers (multi-stage)
Here's the working Dockerfile where I'm able to expand environment variables in CMD:
# Here we set the build-arg as an environment variable.
# Setting this in the base image allows each build stage to access it
FROM node:10.15.0-alpine as base
ARG ENV
ENV RUNTIME_ENV=${ENV}
FROM base as builder
RUN mkdir -p /usr/app
WORKDIR /usr/app
COPY . .
RUN npm ci && npm run build
FROM base
COPY --from=builder /usr/app/.npmrc /usr/app/package*.json /usr/app/server.js ./
COPY --from=builder /usr/app/config ./config
COPY --from=builder /usr/app/build ./build
RUN npm ci --only=production
EXPOSE 3000
CMD npm run start:${RUNTIME_ENV}
The problem here is that ARG params are available only during image build.
The ARG instruction defines a variable that users can pass at build-time to the builder with the docker build command using the --build-arg <varname>=<value> flag.
https://docs.docker.com/engine/reference/builder/#arg
CMD is executed at container startup where ARG variables aren't available anymore.
ENV variables are available during build and also in the container:
The environment variables set using ENV will persist when a container is run from the resulting image.
https://docs.docker.com/engine/reference/builder/#env
To solve your problem you should transfer the ARG variable to an ENV variable.
add the following line before your CMD:
ENV RUNTIME_ENV ${RUNTIME_ENV}
If you want to provide a default value you can use the following:
ENV RUNTIME_ENV ${RUNTIME_ENV:default_value}
Here are some more details about the usage of ARG and ENV from the docker docs.